Exemple #1
0
def signed_serialize(data, secret):
    """Serialize any pickleable structure (``data``) and sign it
    using the ``secret`` (must be a string).  Return the
    serialization, which includes the signature as its first 40 bytes.
    The ``signed_deserialize`` method will deserialize such a value.

    This function is useful for creating signed cookies.  For example:

    .. code-block:: python

       cookieval = signed_serialize({'a':1}, 'secret')
       response.set_cookie('signed_cookie', cookieval)

    .. deprecated:: 1.10

       This function will be removed in :app:`Pyramid` 2.0. It is using
       pickle-based serialization, which is considered vulnerable to remote
       code execution attacks and will no longer be used by the default
       session factories at that time.

    """
    pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
    try:
        # bw-compat with pyramid <= 1.5b1 where latin1 is the default
        secret = bytes_(secret)
    except UnicodeEncodeError:
        secret = bytes_(secret, 'utf-8')
    sig = hmac.new(secret, pickled, hashlib.sha1).hexdigest()
    return sig + native_(base64.b64encode(pickled))
Exemple #2
0
 def test_dumps(self):
     obj = Dummy()
     serializer = self._makeOne()
     result = serializer.dumps(obj)
     expected_result = pickle.dumps(obj, protocol=pickle.HIGHEST_PROTOCOL)
     self.assertEqual(result, expected_result)
     self.assertIsInstance(result, bytes)
        def _set_cookie(self, response):
            if not self._cookie_on_exception:
                exception = getattr(self.request, 'exception', None)
                if exception is not None:  # dont set a cookie during exceptions
                    return False

            cookieval = self.new and get_random() or self._get_cookie()
            if not cookieval:
                return False

            value = self._to_pickle and pickle.dumps(dict(self)) or dict(self)
            data = dict(accessed=self.accessed,
                        created=self.created,
                        value=value,
                        pickled=self._to_pickle,
                        _id=cookieval)
            self._collection.replace_one({'_id': cookieval}, data, upsert=True)

            response.set_cookie(self._cookie_name,
                                value=cookieval,
                                max_age=self._cookie_max_age,
                                path=self._cookie_path,
                                domain=self._cookie_domain,
                                secure=self._cookie_secure,
                                httponly=self._cookie_httponly)
            return True
Exemple #4
0
        def _set_cookie(self, response):
            # Save the value in the database
            data = Binary(pickle.dumps(dict(self)))
            sessioneid = self.sessioneid

            with self.request.registry['cubicweb.repository'].internal_cnx(
            ) as cnx:
                if not sessioneid:
                    session = cnx.create_entity('CWSession',
                                                cwsessiondata=data)
                    sessioneid = session.eid
                else:
                    try:
                        session = cnx.entity_from_eid(sessioneid)
                    except UnknownEid:
                        # Might occur if CWSession entity got dropped (e.g.
                        # the whole db got recreated) while user's cookie is
                        # still valid. We recreate the CWSession in this case.
                        sessioneid = cnx.create_entity('CWSession',
                                                       cwsessiondata=data).eid
                    else:
                        session.cw_set(cwsessiondata=data)
                cnx.commit()

            # Only if needed actually set the cookie
            if self.new or self.accessed - self.renewed > self._reissue_time:
                dict.clear(self)
                dict.__setitem__(self, 'sessioneid', sessioneid)
                return super(CWSession, self)._set_cookie(response)

            return True
        def _set_cookie(self, response):
            if not self._cookie_on_exception:
                exception = getattr(self.request, 'exception', None)
                if exception is not None:  # dont set a cookie during exceptions
                    return False

            cookieval = self.new and get_random() or self._get_cookie()
            if not cookieval:
                return False

            value = self._to_pickle and pickle.dumps(dict(self)) or dict(self)
            data = dict(accessed=self.accessed,
                        created=self.created,
                        value=value,
                        pickled=self._to_pickle,
                        _id=cookieval)
            self._collection.replace_one({'_id': cookieval}, data, upsert=True)

            response.set_cookie(
                self._cookie_name,
                value=cookieval,
                max_age=self._cookie_max_age,
                path=self._cookie_path,
                domain=self._cookie_domain,
                secure=self._cookie_secure,
                httponly=self._cookie_httponly)
            return True
    def _serialize(self, value, secret, nonce):
        import base64
        from pyramid.compat import pickle
        from nacl.secret import SecretBox

        cstruct = pickle.dumps(value, pickle.HIGHEST_PROTOCOL)
        fstruct = SecretBox(secret).encrypt(cstruct, nonce)
        return base64.urlsafe_b64encode(fstruct).rstrip(b"=")
    def _serialize(self, value, secret, nonce):
        import base64
        from pyramid.compat import pickle
        from nacl.secret import SecretBox

        cstruct = pickle.dumps(value, pickle.HIGHEST_PROTOCOL)
        fstruct = SecretBox(secret).encrypt(cstruct, nonce)
        return base64.urlsafe_b64encode(fstruct).rstrip(b'=')
Exemple #8
0
def serialize(data, secret):
    import hmac
    import base64
    from hashlib import sha1
    from pyramid.compat import bytes_
    from pyramid.compat import native_
    from pyramid.compat import pickle
    pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
    sig = hmac.new(bytes_(secret), pickled, sha1).hexdigest()
    return sig + native_(base64.b64encode(pickled))
Exemple #9
0
    def _serialize(self, value, salt=b'pyramid.session.', hashalg='sha512'):
        import base64
        import hashlib
        import hmac
        import pickle

        digestmod = lambda: hashlib.new(hashalg)
        cstruct = pickle.dumps(value, pickle.HIGHEST_PROTOCOL)
        sig = hmac.new(salt + b'secret', cstruct, digestmod).digest()
        return base64.urlsafe_b64encode(sig + cstruct).rstrip(b'=')
Exemple #10
0
def serialize(data, secret):
    import hmac
    import base64
    from hashlib import sha1
    from pyramid.compat import bytes_
    from pyramid.compat import native_
    from pyramid.compat import pickle
    pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
    sig = hmac.new(bytes_(secret), pickled, sha1).hexdigest()
    return sig + native_(base64.b64encode(pickled))
    def _serialize(self, value):
        import os
        import hashlib

        cookieval = hashlib.md5(os.urandom(32)).hexdigest()
        val = pickle.dumps(value['value'])
        value.update({'_id': cookieval, 'value': val})

        collection.replace_one({'_id': cookieval}, value, upsert=True)
        return cookieval
Exemple #12
0
    def _serialize(self, value):
        import os
        import hashlib

        cookieval = hashlib.md5(os.urandom(32)).hexdigest()
        val = pickle.dumps(value['value'])
        value.update({'_id': cookieval, 'value': val})

        collection.replace_one({'_id': cookieval}, value, upsert=True)
        return cookieval
    def dumps(self, session_state):
        """Encrypt session state.

        :type session_state: :class:`dict` / picklable mapping
        :param session_state: the session state to be encrypted.

        :rtype: bytes
        :returns: the encrypted session state
        """
        pickled = pickle.dumps(session_state)
        nonce = random(SecretBox.NONCE_SIZE)
        return urlsafe_b64encode(self.box.encrypt(pickled, nonce))
    def test_loads_with_tampered_content(self):
        import base64
        from pyramid.compat import pickle
        from nacl.secret import SecretBox

        secret = b'SEEKRIT!' * 4
        appstruct = {'foo': 'bar'}
        nonce = b'\x01' * 24
        cstruct = pickle.dumps(appstruct, pickle.HIGHEST_PROTOCOL)
        fstruct = SecretBox(secret).encrypt(cstruct, nonce)
        fstruct = b'tamper' + fstruct
        bstruct = base64.urlsafe_b64encode(fstruct).rstrip(b'=')

        eps = self._makeOne(b'SEEKRIT!' * 4)
        self.assertRaises(ValueError, eps.loads, bstruct)
    def test_loads_with_tampered_content(self):
        import base64
        from pyramid.compat import pickle
        from nacl.secret import SecretBox

        secret = b"SEEKRIT!" * 4
        appstruct = {"foo": "bar"}
        nonce = b"\x01" * 24
        cstruct = pickle.dumps(appstruct, pickle.HIGHEST_PROTOCOL)
        fstruct = SecretBox(secret).encrypt(cstruct, nonce)
        fstruct = b"tamper" + fstruct
        bstruct = base64.urlsafe_b64encode(fstruct).rstrip(b"=")

        eps = self._makeOne(b"SEEKRIT!" * 4)
        self.assertRaises(ValueError, eps.loads, bstruct)
Exemple #16
0
def signed_serialize(data, secret):
    """ Serialize any pickleable structure (``data``) and sign it
    using the ``secret`` (must be a string).  Return the
    serialization, which includes the signature as its first 40 bytes.
    The ``signed_deserialize`` method will deserialize such a value.

    This function is useful for creating signed cookies.  For example:

    .. code-block:: python

       cookieval = signed_serialize({'a':1}, 'secret')
       response.set_cookie('signed_cookie', cookieval)
    """
    pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
    sig = hmac.new(bytes_(secret), pickled, sha1).hexdigest()
    return sig + native_(base64.b64encode(pickled))
Exemple #17
0
def signed_serialize(data, secret):
    """ Serialize any pickleable structure (``data``) and sign it
    using the ``secret`` (must be a string).  Return the
    serialization, which includes the signature as its first 40 bytes.
    The ``signed_deserialize`` method will deserialize such a value.

    This function is useful for creating signed cookies.  For example:

    .. code-block:: python

       cookieval = signed_serialize({'a':1}, 'secret')
       response.set_cookie('signed_cookie', cookieval)
    """
    pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
    sig = hmac.new(bytes_(secret), pickled, sha1).hexdigest()
    return sig + native_(base64.b64encode(pickled))
 def test_loads(self):
     from pyramid.compat import pickle
     from .. import serializer as MUT
     SECRET = 'SEEKRIT!' * 4  # 32 bytes
     NONCE = b'\x01' * 24
     APPSTRUCT = {'foo': 'bar'}
     PICKLED = pickle.dumps(APPSTRUCT)
     CIPHERTEXT = PICKLED + b':' + NONCE
     _base64_called = []
     def _base64_decode(what):
         _base64_called.append(what)
         return what
     with _Monkey(MUT, SecretBox=_SecretBox,
                  urlsafe_b64decode=_base64_decode):
         eps = self._makeOne(SECRET)
         loaded = eps.loads(CIPHERTEXT)
         self.assertEqual(loaded, APPSTRUCT)
         self.assertEqual(_base64_called, [CIPHERTEXT])
Exemple #19
0
def signed_serialize(data, secret):
    """ Serialize any pickleable structure (``data``) and sign it
    using the ``secret`` (must be a string).  Return the
    serialization, which includes the signature as its first 40 bytes.
    The ``signed_deserialize`` method will deserialize such a value.

    This function is useful for creating signed cookies.  For example:

    .. code-block:: python

       cookieval = signed_serialize({'a':1}, 'secret')
       response.set_cookie('signed_cookie', cookieval)
    """
    pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
    try:
        # bw-compat with pyramid <= 1.5b1 where latin1 is the default
        secret = bytes_(secret)
    except UnicodeEncodeError:
        secret = bytes_(secret, 'utf-8')
    sig = hmac.new(secret, pickled, hashlib.sha1).hexdigest()
    return sig + native_(base64.b64encode(pickled))
Exemple #20
0
def signed_serialize(data, secret):
    """ Serialize any pickleable structure (``data``) and sign it
    using the ``secret`` (must be a string).  Return the
    serialization, which includes the signature as its first 40 bytes.
    The ``signed_deserialize`` method will deserialize such a value.

    This function is useful for creating signed cookies.  For example:

    .. code-block:: python

       cookieval = signed_serialize({'a':1}, 'secret')
       response.set_cookie('signed_cookie', cookieval)
    """
    pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
    try:
        # bw-compat with pyramid <= 1.5b1 where latin1 is the default
        secret = bytes_(secret)
    except UnicodeEncodeError:
        secret = bytes_(secret, "utf-8")
    sig = hmac.new(secret, pickled, hashlib.sha1).hexdigest()
    return sig + native_(base64.b64encode(pickled))
 def test_dumps(self):
     from pyramid.compat import pickle
     from .. import serializer as MUT
     SECRET = 'SEEKRIT!' * 4  # 32 bytes
     NONCE = b'\x01' * 24
     APPSTRUCT = {'foo': 'bar'}
     PICKLED = pickle.dumps(APPSTRUCT)
     _base64_called = []
     def _base64_encode(what):
         _base64_called.append(what)
         return what
     with _Monkey(MUT,
                  SecretBox=_SecretBox,
                  random=lambda size: NONCE,
                  urlsafe_b64encode=_base64_encode):
         eps = self._makeOne(SECRET)
         encrypted = eps.dumps(APPSTRUCT)
         pickled, nonce = encrypted[:-25], encrypted[-24:]
         self.assertEqual(pickled, PICKLED)
         self.assertEqual(nonce, NONCE)
         self.assertEqual(_base64_called, [encrypted])
Exemple #22
0
 def dumps(self, appstruct):
     """Accept a Python object and return bytes."""
     return pickle.dumps(appstruct, self.protocol)
Exemple #23
0
 def dumps(self, appstruct):
     return pickle.dumps(appstruct, pickle.HIGHEST_PROTOCOL)
Exemple #24
0
 def dumps(self, appstruct):
     return pickle.dumps(appstruct, pickle.HIGHEST_PROTOCOL)
Exemple #25
0
def dummy_signed_serialize(data, secret):
    import base64
    from pyramid.compat import pickle, bytes_
    pickled = pickle.dumps(data)
    return base64.b64encode(bytes_(secret)) + base64.b64encode(pickled)
Exemple #26
0
 def dumps(self, appstruct):
     """Accept a Python object and return bytes."""
     return pickle.dumps(appstruct, self.protocol)
Exemple #27
0
def dummy_signed_serialize(data, secret):
    import base64
    from pyramid.compat import pickle, bytes_
    pickled = pickle.dumps(data)
    return base64.b64encode(bytes_(secret)) + base64.b64encode(pickled)
Exemple #28
0
def SignedCookieSessionFactory(
    secret,
    cookie_name='session',
    max_age=None,
    path='/',
    domain=None,
    secure=False,
    httponly=False,
    set_on_exception=True,
    timeout=1200,
    reissue_time=0,
    hashalg='sha512',
    salt='pyramid.session.',
    serialize=None,
    deserialize=None,
    ):
    """
    .. versionadded:: 1.5
    
    Configure a :term:`session factory` which will provide signed
    cookie-based sessions.  The return value of this
    function is a :term:`session factory`, which may be provided as
    the ``session_factory`` argument of a
    :class:`pyramid.config.Configurator` constructor, or used
    as the ``session_factory`` argument of the
    :meth:`pyramid.config.Configurator.set_session_factory`
    method.

    The session factory returned by this function will create sessions
    which are limited to storing fewer than 4000 bytes of data (as the
    payload must fit into a single cookie).

    Parameters:

    ``secret``
      A string which is used to sign the cookie. The secret should be at
      least as long as the block size of the selected hash algorithm. For
      ``sha512`` this would mean a 128 bit (64 character) secret.  It should
      be unique within the set of secret values provided to Pyramid for
      its various subsystems (see :ref:`admonishment_against_secret_sharing`).

    ``hashalg``
      The HMAC digest algorithm to use for signing. The algorithm must be
      supported by the :mod:`hashlib` library. Default: ``'sha512'``.

    ``salt``
      A namespace to avoid collisions between different uses of a shared
      secret. Reusing a secret for different parts of an application is
      strongly discouraged (see :ref:`admonishment_against_secret_sharing`).
      Default: ``'pyramid.session.'``.

    ``cookie_name``
      The name of the cookie used for sessioning. Default: ``'session'``.

    ``max_age``
      The maximum age of the cookie used for sessioning (in seconds).
      Default: ``None`` (browser scope).

    ``path``
      The path used for the session cookie. Default: ``'/'``.

    ``domain``
      The domain used for the session cookie.  Default: ``None`` (no domain).

    ``secure``
      The 'secure' flag of the session cookie. Default: ``False``.

    ``httponly``
      Hide the cookie from Javascript by setting the 'HttpOnly' flag of the
      session cookie. Default: ``False``.

    ``timeout``
      A number of seconds of inactivity before a session times out. If
      ``None`` then the cookie never expires. Default: 1200.

    ``reissue_time``
      The number of seconds that must pass before the cookie is automatically
      reissued as the result of a request which accesses the session. The
      duration is measured as the number of seconds since the last session
      cookie was issued and 'now'.  If this value is ``0``, a new cookie
      will be reissued on every request accesses the session. If ``None``
      then the cookie's lifetime will never be extended.

      A good rule of thumb: if you want auto-expired cookies based on
      inactivity: set the ``timeout`` value to 1200 (20 mins) and set the
      ``reissue_time`` value to perhaps a tenth of the ``timeout`` value
      (120 or 2 mins).  It's nonsensical to set the ``timeout`` value lower
      than the ``reissue_time`` value, as the ticket will never be reissued.
      However, such a configuration is not explicitly prevented.

      Default: ``0``.

    ``set_on_exception``
      If ``True``, set a session cookie even if an exception occurs
      while rendering a view. Default: ``True``.

    ``serialize``
      A callable accepting a Python object and returning a bytestring. A
      ``ValueError`` should be raised for malformed inputs.
      Default: :func:`pickle.dumps`.

    ``deserialize``
      A callable accepting a bytestring and returning a Python object. A
      ``ValueError`` should be raised for malformed inputs.
      Default: :func:`pickle.loads`.

    .. versionadded: 1.5a3
    """

    if serialize is None:
        serialize = lambda v: pickle.dumps(v, pickle.HIGHEST_PROTOCOL)

    if deserialize is None:
        deserialize = pickle.loads

    digestmod = lambda string=b'': hashlib.new(hashalg, string)
    digest_size = digestmod().digest_size

    salted_secret = bytes_(salt or '') + bytes_(secret)

    def signed_serialize(appstruct):
        cstruct = serialize(appstruct)
        sig = hmac.new(salted_secret, cstruct, digestmod).digest()
        return base64.b64encode(cstruct + sig)

    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)

    return BaseCookieSessionFactory(
        signed_serialize,
        signed_deserialize,
        cookie_name=cookie_name,
        max_age=max_age,
        path=path,
        domain=domain,
        secure=secure,
        httponly=httponly,
        timeout=timeout,
        reissue_time=reissue_time,
        set_on_exception=set_on_exception,
    )
Exemple #29
0
def SignedCookieSessionFactory(
    secret,
    cookie_name='session',
    max_age=None,
    path='/',
    domain=None,
    secure=False,
    httponly=False,
    set_on_exception=True,
    timeout=1200,
    reissue_time=0,
    hashalg='sha512',
    salt='pyramid.session.',
    serialize=None,
    deserialize=None,
):
    """
    .. versionadded:: 1.5
    
    Configure a :term:`session factory` which will provide signed
    cookie-based sessions.  The return value of this
    function is a :term:`session factory`, which may be provided as
    the ``session_factory`` argument of a
    :class:`pyramid.config.Configurator` constructor, or used
    as the ``session_factory`` argument of the
    :meth:`pyramid.config.Configurator.set_session_factory`
    method.

    The session factory returned by this function will create sessions
    which are limited to storing fewer than 4000 bytes of data (as the
    payload must fit into a single cookie).

    Parameters:

    ``secret``
      A string which is used to sign the cookie. The secret should be at
      least as long as the block size of the selected hash algorithm. For
      ``sha512`` this would mean a 128 bit (64 character) secret.  It should
      be unique within the set of secret values provided to Pyramid for
      its various subsystems (see :ref:`admonishment_against_secret_sharing`).

    ``hashalg``
      The HMAC digest algorithm to use for signing. The algorithm must be
      supported by the :mod:`hashlib` library. Default: ``'sha512'``.

    ``salt``
      A namespace to avoid collisions between different uses of a shared
      secret. Reusing a secret for different parts of an application is
      strongly discouraged (see :ref:`admonishment_against_secret_sharing`).
      Default: ``'pyramid.session.'``.

    ``cookie_name``
      The name of the cookie used for sessioning. Default: ``'session'``.

    ``max_age``
      The maximum age of the cookie used for sessioning (in seconds).
      Default: ``None`` (browser scope).

    ``path``
      The path used for the session cookie. Default: ``'/'``.

    ``domain``
      The domain used for the session cookie.  Default: ``None`` (no domain).

    ``secure``
      The 'secure' flag of the session cookie. Default: ``False``.

    ``httponly``
      Hide the cookie from Javascript by setting the 'HttpOnly' flag of the
      session cookie. Default: ``False``.

    ``timeout``
      A number of seconds of inactivity before a session times out. If
      ``None`` then the cookie never expires. Default: 1200.

    ``reissue_time``
      The number of seconds that must pass before the cookie is automatically
      reissued as the result of a request which accesses the session. The
      duration is measured as the number of seconds since the last session
      cookie was issued and 'now'.  If this value is ``0``, a new cookie
      will be reissued on every request accesses the session. If ``None``
      then the cookie's lifetime will never be extended.

      A good rule of thumb: if you want auto-expired cookies based on
      inactivity: set the ``timeout`` value to 1200 (20 mins) and set the
      ``reissue_time`` value to perhaps a tenth of the ``timeout`` value
      (120 or 2 mins).  It's nonsensical to set the ``timeout`` value lower
      than the ``reissue_time`` value, as the ticket will never be reissued.
      However, such a configuration is not explicitly prevented.

      Default: ``0``.

    ``set_on_exception``
      If ``True``, set a session cookie even if an exception occurs
      while rendering a view. Default: ``True``.

    ``serialize``
      A callable accepting a Python object and returning a bytestring. A
      ``ValueError`` should be raised for malformed inputs.
      Default: :func:`pickle.dumps`.

    ``deserialize``
      A callable accepting a bytestring and returning a Python object. A
      ``ValueError`` should be raised for malformed inputs.
      Default: :func:`pickle.loads`.

    .. versionadded: 1.5a3
    """

    if serialize is None:
        serialize = lambda v: pickle.dumps(v, pickle.HIGHEST_PROTOCOL)

    if deserialize is None:
        deserialize = pickle.loads

    digestmod = lambda string=b'': hashlib.new(hashalg, string)
    digest_size = digestmod().digest_size

    salted_secret = bytes_(salt or '') + bytes_(secret)

    def signed_serialize(appstruct):
        cstruct = serialize(appstruct)
        sig = hmac.new(salted_secret, cstruct, digestmod).digest()
        return base64.b64encode(cstruct + sig)

    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)

    return BaseCookieSessionFactory(
        signed_serialize,
        signed_deserialize,
        cookie_name=cookie_name,
        max_age=max_age,
        path=path,
        domain=domain,
        secure=secure,
        httponly=httponly,
        timeout=timeout,
        reissue_time=reissue_time,
        set_on_exception=set_on_exception,
    )