Created
September 17, 2012 17:56
-
-
Save scragg0x/3738771 to your computer and use it in GitHub Desktop.
Tornados Signed Value Functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def _time_independent_equals(a, b): | |
if len(a) != len(b): | |
return False | |
result = 0 | |
if type(a[0]) is int: # python3 byte strings | |
for x, y in zip(a, b): | |
result |= x ^ y | |
else: # python2 | |
for x, y in zip(a, b): | |
result |= ord(x) ^ ord(y) | |
return result == 0 | |
def create_signed_value(secret, name, value): | |
timestamp = utf8(str(int(time.time()))) | |
value = base64.b64encode(utf8(value)) | |
signature = _create_signature(secret, name, value, timestamp) | |
value = b("|").join([value, timestamp, signature]) | |
return value | |
def decode_signed_value(secret, name, value, max_age_days=31): | |
if not value: | |
return None | |
parts = utf8(value).split(b("|")) | |
if len(parts) != 3: | |
return None | |
signature = _create_signature(secret, name, parts[0], parts[1]) | |
if not _time_independent_equals(parts[2], signature): | |
logging.warning("Invalid cookie signature %r", value) | |
return None | |
timestamp = int(parts[1]) | |
if timestamp < time.time() - max_age_days * 86400: | |
logging.warning("Expired cookie %r", value) | |
return None | |
if timestamp > time.time() + 31 * 86400: | |
# _cookie_signature does not hash a delimiter between the | |
# parts of the cookie, so an attacker could transfer trailing | |
# digits from the payload to the timestamp without altering the | |
# signature. For backwards compatibility, sanity-check timestamp | |
# here instead of modifying _cookie_signature. | |
logging.warning("Cookie timestamp in future; possible tampering %r", value) | |
return None | |
if parts[1].startswith(b("0")): | |
logging.warning("Tampered cookie %r", value) | |
return None | |
try: | |
return base64.b64decode(parts[0]) | |
except Exception: | |
return None | |
def _create_signature(secret, *parts): | |
hash = hmac.new(utf8(secret), digestmod=hashlib.sha1) | |
for part in parts: | |
hash.update(utf8(part)) | |
return utf8(hash.hexdigest()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment