Switch csrf token check to use compare_digest to prevent timing attacks

Also adds some additional tests for CSRF tokens
This commit is contained in:
Joseph Schorr 2016-12-08 23:46:31 -05:00
parent dbdcb802b1
commit 1302fd2fbd
2 changed files with 36 additions and 12 deletions

View file

@ -124,9 +124,11 @@ class ApiTestCase(unittest.TestCase):
query[CSRF_TOKEN_KEY] = CSRF_TOKEN
return urlunparse(list(parts[0:4]) + [urlencode(query)] + list(parts[5:]))
def url_for(self, resource_name, params={}):
def url_for(self, resource_name, params=None, skip_csrf=False):
params = params or {}
url = api.url_for(resource_name, **params)
url = ApiTestCase._add_csrf(url)
if not skip_csrf:
url = ApiTestCase._add_csrf(url)
return url
def setUp(self):
@ -211,8 +213,8 @@ class ApiTestCase(unittest.TestCase):
return parsed
def putJsonResponse(self, resource_name, params={}, data={},
expected_code=200):
rv = self.app.put(self.url_for(resource_name, params),
expected_code=200, skip_csrf=False):
rv = self.app.put(self.url_for(resource_name, params, skip_csrf),
data=py_json.dumps(data),
headers={"Content-Type": "application/json"})
@ -246,15 +248,35 @@ class TestCSRFFailure(ApiTestCase):
self.login(READ_ACCESS_USER)
# Make sure a simple post call succeeds.
self.putJsonResponse(User,
data=dict(password='newpasswordiscool'))
self.putJsonResponse(User, data=dict(password='newpasswordiscool'))
# Change the session's CSRF token.
self.setCsrfToken('someinvalidtoken')
# Verify that the call now fails.
self.putJsonResponse(User,
data=dict(password='newpasswordiscool'),
self.putJsonResponse(User, data=dict(password='newpasswordiscool'), expected_code=403)
def test_csrf_failure_empty_token(self):
self.login(READ_ACCESS_USER)
# Change the session's CSRF token to be empty.
self.setCsrfToken('')
# Verify that the call now fails.
self.putJsonResponse(User, data=dict(password='newpasswordiscool'), expected_code=403)
def test_csrf_failure_missing_token(self):
self.login(READ_ACCESS_USER)
# Make sure a simple post call without a token at all fails.
self.putJsonResponse(User, data=dict(password='newpasswordiscool'), skip_csrf=True,
expected_code=403)
# Change the session's CSRF token to be empty.
self.setCsrfToken('')
# Verify that the call still fails.
self.putJsonResponse(User, data=dict(password='newpasswordiscool'), skip_csrf=True,
expected_code=403)