summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarian Sigler <m@qjym.de>2013-05-23 00:17:45 +0200
committerMarian Sigler <m@qjym.de>2013-05-23 00:17:45 +0200
commit426736b8288e40a6c283e653c73e59efbc436c4f (patch)
tree59f945c52ad03229b10561f83e937fc319867387
parent7da85c36293a0821cf009724aa135b8343c882e4 (diff)
downloadweb-426736b8288e40a6c283e653c73e59efbc436c4f.tar.gz
web-426736b8288e40a6c283e653c73e59efbc436c4f.tar.bz2
web-426736b8288e40a6c283e653c73e59efbc436c4f.zip
use a constant time compare when verifying confirmation links
-rw-r--r--utils.py28
1 files changed, 27 insertions, 1 deletions
diff --git a/utils.py b/utils.py
index 7071284..7e5fd85 100644
--- a/utils.py
+++ b/utils.py
@@ -13,6 +13,7 @@ from flask import current_app, flash, g, redirect, render_template, request, ses
from flask import url_for as flask_url_for
from flask.ext.wtf import ValidationError
from hashlib import sha1
+from itertools import izip
from random import randint
from time import time
from werkzeug.exceptions import Forbidden
@@ -148,7 +149,7 @@ def verify_confirmation(realm, token, timeout=None):
tokentime = struct.unpack('>i', token[20:24])[0]
payload = token[24:]
- if mac != hmac.new(key, token[20:], sha1).digest():
+ if not constant_time_compare(mac, hmac.new(key, token[20:], sha1).digest()):
raise ConfirmationInvalid('MAC does not match')
if timeout is not None and time() > tokentime + timeout:
@@ -170,6 +171,31 @@ def http_verify_confirmation(*args, **kwargs):
raise Forbidden(u'Bestätigungslink ist zu alt.')
+# Shamelessly stolen from https://github.com/mitsuhiko/itsdangerous/
+# (C) 2011 by Armin Ronacher and the Django Software Foundation. 3-clause BSD.
+def constant_time_compare(val1, val2):
+ """Returns True if the two strings are equal, False otherwise.
+
+ The time taken is independent of the number of characters that match. Do
+ not use this function for anything else than comparision with known
+ length targets.
+
+ This is should be implemented in C in order to get it completely right.
+ """
+ if _builtin_constant_time_compare is not None:
+ return _builtin_constant_time_compare(val1, val2)
+ len_eq = len(val1) == len(val2)
+ if len_eq:
+ result = 0
+ left = val1
+ else:
+ result = 1
+ left = val2
+ for x, y in izip(bytearray(left), bytearray(val2)):
+ result |= x ^ y
+ return result == 0
+
+
def send_mail(recipient, subject, body, sender=None):
if sender is None:
sender = current_app.config['MAIL_DEFAULT_SENDER']