Glenn Linderman <v+pyt...@g.nevcal.com> added the comment: Given Martin's comment (msg150832) I guess I should add my suggestion to this issue, at least for the record.
Rather than change hash functions, randomization could be added to those dicts that are subject to attack by wanting to store user-supplied key values. The list so far seems to be urllib.parse, cgi, json Some have claimed there are many more, but without enumeration. These three are clearly related to the documented issue. The technique would be to wrap dict and add a short random prefix to each key value, preventing the attacker from supplier keys that are known to collide... and even if he successfully stumbles on a set that does collide on one request, it is unlikely to collide on a subsequent request with a different prefix string. The technique is fully backward compatible with all applications except those that contain potential vulnerabilities as described by the researchers. The technique adds no startup or runtime overhead to any application that doesn't contain the potential vulnerabilities. Due to the per-request randomization, the complexity of creating a sequence of sets of keys that may collide is enormous, and requires that such a set of keys happen to arrive on a request in the right sequence where the predicted prefix randomization would be used to cause the collisions to occur. This might be possible on a lightly loaded system, but is less likely on a system with heavy load, which are more interesting to attack. Serhiy Storchaka provided a sample implementation on the python-dev, copied below, and attached as a file (but is not a patch). # -*- coding: utf-8 -*- from collections import MutableMapping import random class SafeDict(dict, MutableMapping): def __init__(self, *args, **kwds): dict.__init__(self) self._prefix = str(random.getrandbits(64)) self.update(*args, **kwds) def clear(self): dict.clear(self) self._prefix = str(random.getrandbits(64)) def _safe_key(self, key): return self._prefix + repr(key), key def __getitem__(self, key): try: return dict.__getitem__(self, self._safe_key(key)) except KeyError as e: e.args = (key,) raise e def __setitem__(self, key, value): dict.__setitem__(self, self._safe_key(key), value) def __delitem__(self, key): try: dict.__delitem__(self, self._safe_key(key)) except KeyError as e: e.args = (key,) raise e def __iter__(self): for skey, key in dict.__iter__(self): yield key def __contains__(self, key): return dict.__contains__(self, self._safe_key(key)) setdefault = MutableMapping.setdefault update = MutableMapping.update pop = MutableMapping.pop popitem = MutableMapping.popitem keys = MutableMapping.keys values = MutableMapping.values items = MutableMapping.items def __repr__(self): return '{%s}' % ', '.join('%s: %s' % (repr(k), repr(v)) for k, v in self.items()) def copy(self): return self.__class__(self) @classmethod def fromkeys(cls, iterable, value=None): d = cls() for key in iterable: d[key] = value return d def __eq__(self, other): return all(k in other and other[k] == v for k, v in self.items()) and \ all(k in self and self[k] == v for k, v in other.items()) def __ne__(self, other): return not self == other ---------- Added file: http://bugs.python.org/file24169/SafeDict.py _______________________________________ Python tracker <rep...@bugs.python.org> <http://bugs.python.org/issue13703> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com