def signed_deserialize(serialized, secret, hmac=hmac): """ Deserialize the value returned from ``signed_serialize``. If the value cannot be deserialized for any reason, a :exc:`ValueError` exception will be raised. This function is useful for deserializing a signed cookie value created by ``signed_serialize``. For example: .. code-block:: python cookieval = request.cookies['signed_cookie'] data = signed_deserialize(cookieval, 'secret') """ # hmac parameterized only for unit tests try: input_sig, pickled = (serialized[:40], base64.b64decode(bytes_(serialized[40:]))) except (binascii.Error, TypeError) as e: # Badly formed data can make base64 die raise ValueError('Badly formed base64 data: %s' % e) sig = hmac.new(bytes_(secret), pickled, sha1).hexdigest() # Avoid timing attacks (see # http://seb.dbzteam.org/crypto/python-oauth-timing-hmac.pdf) if strings_differ(sig, input_sig): raise ValueError('Invalid signature') return pickle.loads(pickled)
def check_csrf_token(request, token='csrf_token', header='X-CSRF-Token', raises=True): """ Check the CSRF token in the request's session against the value in ``request.params.get(token)`` or ``request.headers.get(header)``. If a ``token`` keyword is not supplied to this function, the string ``csrf_token`` will be used to look up the token in ``request.params``. If a ``header`` keyword is not supplied to this function, the string ``X-CSRF-Token`` will be used to look up the token in ``request.headers``. If the value supplied by param or by header doesn't match the value supplied by ``request.session.get_csrf_token()``, and ``raises`` is ``True``, this function will raise an :exc:`pyramid.exceptions.BadCSRFToken` exception. If the check does succeed and ``raises`` is ``False``, this function will return ``False``. If the CSRF check is successful, this function will return ``True`` unconditionally. Note that using this function requires that a :term:`session factory` is configured. See :ref:`auto_csrf_checking` for information about how to secure your application automatically against CSRF attacks. .. versionadded:: 1.4a2 """ supplied_token = request.params.get(token, request.headers.get(header, "")) expected_token = request.session.get_csrf_token() if strings_differ(bytes_(expected_token), bytes_(supplied_token)): if raises: raise BadCSRFToken('check_csrf_token(): Invalid token') return False return True
def verify_request(cfg, request): # Reconstruct the original path. Discard any query parameters that come # after the signature, because they can't be trusted. query = request.query_string if '&s=' not in query: # No signature return False query, sig = query.split('&s=', 1) sig = sig.split('&')[0].split(';')[0] path = request.path_info + '?' + query # Try all configured keys to find a match if not cfg.downloadSignatureKey: raise RuntimeError("At least one downloadSignatureKey must be configured") found = False for key in cfg.downloadSignatureKey: sig2 = hmac.new(key, path, hashlib.sha1).hexdigest() # Use constant-time comparison to avoid timing attacks. if not strings_differ(sig, sig2): found = True break if not found: # Signature not valid return False # Now look at the query parameters and ensure that all constraints are met. for name, value in urlparse.parse_qsl(query): if name == 'e': # Expiration expiry = int(value) if time.time() > expiry: return False # Everything checks out, return the constraints to the caller for # verification return True
def check_csrf_token(request, token="csrf_token", header="X-CSRF-Token", raises=True): """ Check the CSRF token in the request's session against the value in ``request.params.get(token)`` or ``request.headers.get(header)``. If a ``token`` keyword is not supplied to this function, the string ``csrf_token`` will be used to look up the token in ``request.params``. If a ``header`` keyword is not supplied to this function, the string ``X-CSRF-Token`` will be used to look up the token in ``request.headers``. If the value supplied by param or by header doesn't match the value supplied by ``request.session.get_csrf_token()``, and ``raises`` is ``True``, this function will raise an :exc:`pyramid.exceptions.BadCSRFToken` exception. If the check does succeed and ``raises`` is ``False``, this function will return ``False``. If the CSRF check is successful, this function will return ``True`` unconditionally. Note that using this function requires that a :term:`session factory` is configured. .. versionadded:: 1.4a2 """ supplied_token = request.params.get(token, request.headers.get(header, "")) if strings_differ(request.session.get_csrf_token(), supplied_token): if raises: raise BadCSRFToken("check_csrf_token(): Invalid token") return False return True
def check_code(self, user, code=None): window = self.req.registry['settings']['email_auth_window'] now = datetime.utcnow() codetocheck = code if code else self.cform.data['code'] return ((not strings_differ(codetocheck, user.generated_code)) and (now < (user.generated_code_time_stamp + timedelta(seconds=window))))
def signed_deserialize(serialized, secret, hmac=hmac): """ Deserialize the value returned from ``signed_serialize``. If the value cannot be deserialized for any reason, a :exc:`ValueError` exception will be raised. This function is useful for deserializing a signed cookie value created by ``signed_serialize``. For example: .. code-block:: python cookieval = request.cookies['signed_cookie'] data = signed_deserialize(cookieval, 'secret') """ # hmac parameterized only for unit tests try: input_sig, pickled = (bytes_(serialized[:40]), base64.b64decode(bytes_(serialized[40:]))) except (binascii.Error, TypeError) as e: # Badly formed data can make base64 die raise ValueError('Badly formed base64 data: %s' % e) try: # bw-compat with pyramid <= 1.5b1 where latin1 is the default secret = bytes_(secret) except UnicodeEncodeError: secret = bytes_(secret, 'utf-8') sig = bytes_(hmac.new(secret, pickled, hashlib.sha1).hexdigest()) # Avoid timing attacks (see # http://seb.dbzteam.org/crypto/python-oauth-timing-hmac.pdf) if strings_differ(sig, input_sig): raise ValueError('Invalid signature') return pickle.loads(pickled)
def check_csrf_token(request, token='csrf_token', header='X-CSRF-Token', raises=True): """ Check the CSRF token in the request's session against the value in ``request.params.get(token)`` or ``request.headers.get(header)``. If a ``token`` keyword is not supplied to this function, the string ``csrf_token`` will be used to look up the token in ``request.params``. If a ``header`` keyword is not supplied to this function, the string ``X-CSRF-Token`` will be used to look up the token in ``request.headers``. If the value supplied by param or by header doesn't match the value supplied by ``request.session.get_csrf_token()``, and ``raises`` is ``True``, this function will raise an :exc:`pyramid.exceptions.BadCSRFToken` exception. If the check does succeed and ``raises`` is ``False``, this function will return ``False``. If the CSRF check is successful, this function will return ``True`` unconditionally. Note that using this function requires that a :term:`session factory` is configured. .. versionadded:: 1.4a2 """ supplied_token = request.params.get(token, request.headers.get(header, "")) if strings_differ(request.session.get_csrf_token(), supplied_token): if raises: raise BadCSRFToken('check_csrf_token(): Invalid token') return False return True
def unsign_session_id(cookie, secret): cookie = bytes_(cookie) input_sig, session_id = (cookie[:32], cookie[32:]) sig = hmac.new(bytes_(secret), session_id, sha1).digest() # Avoid timing attacks (see # http://seb.dbzteam.org/crypto/python-oauth-timing-hmac.pdf) if strings_differ(base64.b32encode(sig), input_sig): raise ValueError('Invalid signature') return session_id
def check_code(self, user): tm = int(time.time() / 30) code_attempt = self.cform.data['code'] # try 30 seconds behind and ahead as well for ix in [-1, 0, 1]: code = get_google_auth_code(user.secret, tm + ix) if not strings_differ(code, str(code_attempt)): return True return False
def check_csrf_token(request, token='csrf_token', header='X-CSRF-Token', raises=True): """ Check the CSRF token in the request's session against the value in ``request.POST.get(token)`` (if a POST request) or ``request.headers.get(header)``. If a ``token`` keyword is not supplied to this function, the string ``csrf_token`` will be used to look up the token in ``request.POST``. If a ``header`` keyword is not supplied to this function, the string ``X-CSRF-Token`` will be used to look up the token in ``request.headers``. If the value supplied by post or by header doesn't match the value supplied by ``request.session.get_csrf_token()``, and ``raises`` is ``True``, this function will raise an :exc:`pyramid.exceptions.BadCSRFToken` exception. If the values differ and ``raises`` is ``False``, this function will return ``False``. If the CSRF check is successful, this function will return ``True`` unconditionally. Note that using this function requires that a :term:`session factory` is configured. See :ref:`auto_csrf_checking` for information about how to secure your application automatically against CSRF attacks. .. versionadded:: 1.4a2 .. versionchanged:: 1.7a1 A CSRF token passed in the query string of the request is no longer considered valid. It must be passed in either the request body or a header. """ supplied_token = "" # If this is a POST/PUT/etc request, then we'll check the body to see if it # has a token. We explicitly use request.POST here because CSRF tokens # should never appear in an URL as doing so is a security issue. We also # explicitly check for request.POST here as we do not support sending form # encoded data over anything but a request.POST. if token is not None: supplied_token = request.POST.get(token, "") # If we were unable to locate a CSRF token in a request body, then we'll # check to see if there are any headers that have a value for us. if supplied_token == "" and header is not None: supplied_token = request.headers.get(header, "") expected_token = request.session.get_csrf_token() if strings_differ(bytes_(expected_token), bytes_(supplied_token)): if raises: raise BadCSRFToken('check_csrf_token(): Invalid token') return False return True
def signed_deserialize(bstruct): try: fstruct = base64.b64decode(bstruct) except (binascii.Error, TypeError) as e: raise ValueError('Badly formed base64 data: %s' % e) cstruct = fstruct[:-digest_size] expected_sig = fstruct[-digest_size:] sig = hmac.new(salted_secret, cstruct, digestmod).digest() if strings_differ(sig, expected_sig): raise ValueError('Invalid signature') return deserialize(cstruct)
def check_token(self, user, token, limit=86400): try: ts_b62, hash = token.split("-") except ValueError: return False try: ts = base62_to_int(ts_b62) except ValueError: return False if strings_differ(self._make_token(user, ts), token): return False if limit: now = int(time.time()) if now > ts + int(limit): return False return True
def check_code(self, user, code=None): try: window = int(self.req.registry.settings.get('sms.auth_window', 120)) except ValueError: logger.error("sms.auth_window is not set to a valid integer. " "Setting to default of 120 seconds") window = 120 codetocheck = code if code else self.cform.data['code'] now = datetime.utcnow() expires_at = user.generated_code_time_stamp + timedelta(seconds=window) # out of time if now >= expires_at: return False # bad code entered if strings_differ(codetocheck, user.generated_code): return False return True
def check_code(self, user, code=None): try: window = int(self.req.registry.settings.get( 'sms.auth_window', 120)) except ValueError: logger.error("sms.auth_window is not set to a valid integer. " "Setting to default of 120 seconds") window = 120 codetocheck = code if code else self.cform.data['code'] now = datetime.utcnow() expires_at = user.generated_code_time_stamp + timedelta(seconds=window) # out of time if now >= expires_at: return False # bad code entered if strings_differ(codetocheck, user.generated_code): return False return True
def parse_ticket(secret, ticket, ip, hashalg='md5'): """ Parse the ticket, returning (timestamp, userid, tokens, user_data). If the ticket cannot be parsed, a ``BadTicket`` exception will be raised with an explanation. """ ticket = text_(ticket).strip('"') digest_size = hashlib.new(hashalg).digest_size * 2 digest = ticket[:digest_size] try: timestamp = int(ticket[digest_size : digest_size + 8], 16) except ValueError as e: raise BadTicket('Timestamp is not a hex integer: %s' % e) try: userid, data = ticket[digest_size + 8 :].split('!', 1) except ValueError: raise BadTicket('userid is not followed by !') userid = unquote(userid) if '!' in data: tokens, user_data = data.split('!', 1) else: # pragma: no cover (never generated) # @@: Is this the right order? tokens = '' user_data = data expected = calculate_digest( ip, timestamp, secret, userid, tokens, user_data, hashalg ) # Avoid timing attacks (see # http://seb.dbzteam.org/crypto/python-oauth-timing-hmac.pdf) if strings_differ(expected, digest): raise BadTicket( 'Digest signature is not correct', expected=(expected, digest) ) tokens = tokens.split(',') return (timestamp, userid, tokens, user_data)
userid, data = ticket[40:].split("!", 1) except ValueError: raise BadTicket("userid is not followed by !") userid = urllib.unquote(userid) if "!" in data: tokens, user_data = data.split("!", 1) else: # pragma: no cover (never generated) # @@: Is this the right order? tokens = "" user_data = data expected = calculate_digest(ip, timestamp, secret, userid, tokens, user_data) # Avoid timing attacks (see # http://seb.dbzteam.org/crypto/python-oauth-timing-hmac.pdf) if strings_differ(expected, digest): raise BadTicket("Digest signature is not correct", expected=(expected, digest)) tokens = tokens.split(",") return (timestamp, userid, tokens, user_data) # this function licensed under the MIT license (stolen from Paste) def calculate_digest(ip, timestamp, secret, userid, tokens, user_data): secret = maybe_encode(secret) userid = maybe_encode(userid) tokens = maybe_encode(tokens) user_data = maybe_encode(user_data) digest0 = md5(encode_ip_timestamp(ip, timestamp) + secret + userid + "\0" + tokens + "\0" + user_data).hexdigest() digest = md5(digest0 + secret).hexdigest()
def check_csrf_token(self, request, supplied_token): """ Returns ``True`` if the ``supplied_token`` is valid.""" expected_token = self.get_csrf_token(request) return not strings_differ(bytes_(expected_token), bytes_(supplied_token))
def check_csrf_token(self, request, supplied_token): """ Returns ``True`` if the ``supplied_token`` is valid.""" expected_token = self.get_csrf_token(request) return not strings_differ( bytes_(expected_token), bytes_(supplied_token))
def _callFUT(self, *args, **kw): from pyramid.util import strings_differ return strings_differ(*args, **kw)
def signed_deserialize(serialized, secret, hmac=hmac): """ Deserialize the value returned from ``signed_serialize``. If the value cannot be deserialized for any reason, a :exc:`ValueError` exception will be raised. This function is useful for deserializing a signed cookie value created by ``signed_serialize``. For example: .. code-block:: python cookieval = request.cookies['signed_cookie'] data = signed_deserialize(cookieval, 'secret') """ # hmac parameterized only for unit tests try: input_sig, pickled = (serialized[:40], base64.standard_b64decode(serialized[40:])) except (binascii.Error, TypeError), e: # Badly formed data can make base64 die raise ValueError('Badly formed base64 data: %s' % e) sig = hmac.new(secret, pickled, sha1).hexdigest() # Avoid timing attacks (see # http://seb.dbzteam.org/crypto/python-oauth-timing-hmac.pdf) if strings_differ(sig, input_sig): raise ValueError('Invalid signature') return pickle.loads(pickled)