Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
 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))))
Ejemplo n.º 6
0
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)
Ejemplo n.º 7
0
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
Ejemplo n.º 8
0
 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))))
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
    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
Ejemplo n.º 11
0
    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
Ejemplo n.º 12
0
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
Ejemplo n.º 13
0
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
Ejemplo n.º 14
0
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
Ejemplo n.º 15
0
    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)
Ejemplo n.º 16
0
    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)
Ejemplo n.º 17
0
    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
Ejemplo n.º 18
0
    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
Ejemplo n.º 19
0
    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
Ejemplo n.º 20
0
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)
Ejemplo n.º 21
0
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)
Ejemplo n.º 22
0
        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()
Ejemplo n.º 23
0
 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))
Ejemplo n.º 24
0
 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))
Ejemplo n.º 25
0
    def _callFUT(self, *args, **kw):
        from pyramid.util import strings_differ

        return strings_differ(*args, **kw)
Ejemplo n.º 26
0
 def _callFUT(self, *args, **kw):
     from pyramid.util import strings_differ
     return strings_differ(*args, **kw)
Ejemplo n.º 27
0
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)