Ryan Kelly
2011-10-15 c8c9bc80621bea468d2dbd440255b9f0b7baeb4e
Avoid timing attacks in AuthTktAutenticationPolicy

This factors out the timing-invariant string comparison code from
session.py and re-uses it for signature checking in AuthTkt code.
3 files modified
38 ■■■■ changed files
pyramid/authentication.py 6 ●●●● patch | view | raw | blame | history
pyramid/session.py 12 ●●●● patch | view | raw | blame | history
pyramid/util.py 20 ●●●●● patch | view | raw | blame | history
pyramid/authentication.py
@@ -14,6 +14,8 @@
from pyramid.security import Authenticated
from pyramid.security import Everyone
from pyramid.util import strings_differ
VALID_TOKEN = re.compile(r"^[A-Za-z][A-Za-z0-9+_-]*$")
class CallbackAuthenticationPolicy(object):
@@ -486,7 +488,9 @@
    expected = calculate_digest(ip, timestamp, secret,
                                userid, tokens, user_data)
    if expected != digest:
    # Avoid timing attacks (see
    # http://seb.dbzteam.org/crypto/python-oauth-timing-hmac.pdf)
    if strings_differ(expected, digest):
        raise BadTicket('Digest signature is not correct',
                        expected=(expected, digest))
pyramid/session.py
@@ -14,6 +14,7 @@
from zope.interface import implements
from pyramid.interfaces import ISession
from pyramid.util import strings_differ
def manage_accessed(wrapped):
    """ Decorator which causes a cookie to be set when a wrapped
@@ -261,17 +262,10 @@
    sig = hmac.new(secret, pickled, sha1).hexdigest()
    if len(sig) != len(input_sig):
        raise ValueError('Wrong signature length')
    # Avoid timing attacks (see
    # http://seb.dbzteam.org/crypto/python-oauth-timing-hmac.pdf)
    invalid_bits = 0
    for a, b in zip(sig, input_sig):
        invalid_bits += a != b
    if invalid_bits:
        raise ValueError('Invalid bits in signature')
    if strings_differ(sig, input_sig):
        raise ValueError('Invalid signature')
    return pickle.loads(pickled)
pyramid/util.py
@@ -207,3 +207,23 @@
            oid = self._order[-1]
            return self._items[oid]()
def strings_differ(string1, string2):
    """Check whether two strings differ while avoiding timing attacks.
    This function returns True if the given strings differ and False
    if they are equal.  It's careful not to leak information about *where*
    they differ as a result of its running time, which can be very important
    to avoid certain timing-related crypto attacks:
        http://seb.dbzteam.org/crypto/python-oauth-timing-hmac.pdf
    """
    if len(string1) != len(string2):
        return True
    invalid_bits = 0
    for a, b in zip(string1, string2):
        invalid_bits += a != b
    return invalid_bits != 0