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:
parent
85ee3aa9d5
commit
1f0798f4fb
|
@ -110,7 +110,7 @@ from time import gmtime, strftime, time
|
||||||
from time import time
|
from time import time
|
||||||
from urllib import quote, unquote
|
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.
|
#: 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'
|
attributes.get('expires') or '0'
|
||||||
)
|
)
|
||||||
sig = hmac.new(key, hmac_body, sha1).hexdigest()
|
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'
|
return '401 Unauthorized', 'invalid signature'
|
||||||
subenv['swift.authorize'] = lambda req: None
|
subenv['swift.authorize'] = lambda req: None
|
||||||
subenv['swift.authorize_override'] = True
|
subenv['swift.authorize_override'] = True
|
||||||
|
|
|
@ -1117,3 +1117,23 @@ def listdir(path):
|
||||||
if err.errno != errno.ENOENT:
|
if err.errno != errno.ENOENT:
|
||||||
raise
|
raise
|
||||||
return []
|
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
|
||||||
|
|
|
@ -850,6 +850,11 @@ log_name = %(yarr)s'''
|
||||||
for v in utils.TRUE_VALUES:
|
for v in utils.TRUE_VALUES:
|
||||||
self.assertEquals(v, v.lower())
|
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__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
Loading…
Reference in New Issue