def cache_poisoning_event(self, poison_info, request=None, context=None): """Create a 'cache_poisoning_server' event for event-collector poison_info: Details from the client about the poisoning event request, context: Should be pylons.request & pylons.c respectively """ poisoner_name = poison_info.pop("poisoner_name") event = Event( topic="cache_poisoning_events", event_type="ss.cache_poisoning", request=request, context=context, data=poison_info, truncatable_field="resp_headers", ) event.add("poison_blame_guess", "proxy") resp_headers = poison_info["resp_headers"] if resp_headers: # Check if the caching headers we got back match the current policy cache_policy = poison_info["cache_policy"] headers_valid = cache_headers_valid(cache_policy, resp_headers) event.add("cache_headers_valid", headers_valid) # try to determine what kind of poisoning we're dealing with if poison_info["source"] == "web": # Do we think they logged in the usual way, or do we think they # got poisoned with someone else's session cookie? valid_login_hook = hooks.get_hook("poisoning.guess_valid_login") if valid_login_hook.call_until_return(poisoner_name=poisoner_name): # Maybe a misconfigured local Squid proxy + multiple # clients? event.add("poison_blame_guess", "local_proxy") event.add("poison_credentialed_guess", False) elif (context.user_is_loggedin and context.user.name == poisoner_name): # Guess we got poisoned with a cookie-bearing response. event.add("poison_credentialed_guess", True) else: event.add("poison_credentialed_guess", False) elif poison_info["source"] == "mweb": # All mweb responses contain an OAuth token, so we have to assume # whoever got this response can perform actions as the poisoner event.add("poison_credentialed_guess", True) else: raise Exception("Unsupported source in cache_poisoning_event") # Check if the CF-Cache-Status header is present (this header is not # present if caching is disallowed.) If it is, the CDN caching rules # are all jacked up. if resp_headers and "cf-cache-status" in resp_headers: event.add("poison_blame_guess", "cdn") self.save_event(event)
def cache_poisoning_event(self, poison_info, event_base=None, request=None, context=None): """Create a 'cache_poisoning_server' event for event-collector poison_info: Details from the client about the poisoning event event_base: The base fields for an Event. If not given, caller MUST supply a pylons.request and pylons.c object to build a base from request, context: Should be pylons.request & pylons.c respectively; used to build the base Event if event_base is not given """ if event_base is None: event_base = Event.base_from_request(request, context) event_base["event_name"] = "cache_poisoning_server" event_base["event_topic"] = "cache_poisoning" submit_ts = epoch_timestamp(datetime.datetime.now(pytz.UTC)) event_base["event_ts"] = _epoch_to_millis(submit_ts) poisoner_name = poison_info.pop("poisoner_name") event_base.update(**poison_info) event_base["poison_blame_guess"] = "proxy" resp_headers = poison_info["resp_headers"] if resp_headers: # Check if the caching headers we got back match the current policy cache_policy = poison_info["cache_policy"] headers_valid = cache_headers_valid(cache_policy, resp_headers) event_base["cache_headers_valid"] = headers_valid # try to determine what kind of poisoning we're dealing with if poison_info["source"] == "web": # Do we think they logged in the usual way, or do we think they # got poisoned with someone else's session cookie? valid_login_hook = hooks.get_hook("poisoning.guess_valid_login") if valid_login_hook.call_until_return(poisoner_name=poisoner_name): # Maybe a misconfigured local Squid proxy + multiple # clients? event_base["poison_blame_guess"] = "local_proxy" event_base["poison_credentialed_guess"] = False elif (context.user_is_loggedin and context.user.name == poisoner_name): # Guess we got poisoned with a cookie-bearing response. event_base["poison_credentialed_guess"] = True else: event_base["poison_credentialed_guess"] = False elif poison_info["source"] == "mweb": # All mweb responses contain an OAuth token, so we have to assume # whoever got this response can perform actions as the poisoner event_base["poison_credentialed_guess"] = True else: raise Exception("Unsupported source in cache_poisoning_event") # Check if the CF-Cache-Status header is present (this header is not # present if caching is disallowed.) If it is, the CDN caching rules # are all jacked up. if resp_headers and "cf-cache-status" in resp_headers: event_base["poison_blame_guess"] = "cdn" size_so_far = len(json.dumps(event_base)) oversize = size_so_far - MAX_EVENT_SIZE if oversize > 0: # It's almost definitely the headers that are too large event_base["resp_headers"] = {} # No JSON support in the DBs we target event_base["resp_headers"] = json.dumps(event_base["resp_headers"]) self.save_event(event_base)