Use constant time string comparisons for auth.

Fix bug 942644.

Use constant time string comparisons when doing authentication to help
guard against timing attacks.

Change-Id: I88c4c5cd9edd9e5d60db07b6ae2638b74a2a2e17
This commit is contained in:
Russell Bryant 2012-02-28 11:17:21 -05:00
parent 85ee3aa9d5
commit 1f0798f4fb
3 changed files with 28 additions and 2 deletions

View File

@ -110,7 +110,7 @@ from time import gmtime, strftime, time
from time import time
from urllib import quote, unquote
from swift.common.utils import get_logger
from swift.common.utils import get_logger, strcmp_const_time
#: The size of data to read from the form at any given time.
@ -442,7 +442,8 @@ class FormPost(object):
attributes.get('expires') or '0'
)
sig = hmac.new(key, hmac_body, sha1).hexdigest()
if sig != (attributes.get('signature') or 'invalid'):
if not strcmp_const_time(sig,(attributes.get('signature') or
'invalid')):
return '401 Unauthorized', 'invalid signature'
subenv['swift.authorize'] = lambda req: None
subenv['swift.authorize_override'] = True

View File

@ -1117,3 +1117,23 @@ def listdir(path):
if err.errno != errno.ENOENT:
raise
return []
def strcmp_const_time(s1, s2):
"""Constant-time string comparison.
:params s1: the first string
:params s2: the second string
:return: True if the strings are equal.
This function takes two strings and compares them. It is intended to be
used when doing a comparison for authentication purposes to help guard
against timing attacks.
"""
if len(s1) != len(s2):
return False
result = 0
for (a, b) in zip(s1, s2):
result |= ord(a) ^ ord(b)
return result == 0

View File

@ -850,6 +850,11 @@ log_name = %(yarr)s'''
for v in utils.TRUE_VALUES:
self.assertEquals(v, v.lower())
def test_strcmp_const_time(self):
self.assertTrue(utils.strcmp_const_time('abc123', 'abc123'))
self.assertFalse(utils.strcmp_const_time('a', 'aaaaa'))
self.assertFalse(utils.strcmp_const_time('ABC123', 'abc123'))
if __name__ == '__main__':
unittest.main()