Exemplo n.º 1
0
 def clean_security_hash(self):
     """Check the security hash."""
     security_hash_dict = {
         'content_type' : self.data.get("content_type", ""),
         'object_pk' : self.data.get("object_pk", ""),
         'timestamp' : self.data.get("timestamp", ""),
     }
     expected_hash = self.generate_security_hash(**security_hash_dict)
     actual_hash = self.cleaned_data["security_hash"]
     if not constant_time_compare(expected_hash, actual_hash):
         raise forms.ValidationError("Security hash check failed.")
     return actual_hash
Exemplo n.º 2
0
 def decode(self, session_data):
     encoded_data = base64.b64decode(force_bytes(session_data))
     try:
         # could produce ValueError if there is no ':'
         hash, pickled = encoded_data.split(b':', 1)
         expected_hash = self._hash(pickled)
         if not constant_time_compare(hash.decode(), expected_hash):
             raise SuspiciousOperation("Session data corrupted")
         else:
             return pickle.loads(pickled)
     except Exception:
         # ValueError, SuspiciousOperation, unpickling exceptions. If any of
         # these happen, just return an empty dictionary (an empty session).
         return {}
Exemplo n.º 3
0
    def _decode(self, data):
        """
        Safely decodes a encoded text stream back into a list of messages.

        If the encoded text stream contained an invalid hash or was in an
        invalid format, ``None`` is returned.
        """
        if not data:
            return None
        bits = data.split('$', 1)
        if len(bits) == 2:
            hash, value = bits
            if constant_time_compare(hash, self._hash(value)):
                try:
                    # If we get here (and the JSON decode works), everything is
                    # good. In any other case, drop back and return None.
                    return json.loads(value, cls=MessageDecoder)
                except ValueError:
                    pass
        # Mark the data as used (so it gets removed) since something was wrong
        # with the data.
        self.used = True
        return None
Exemplo n.º 4
0
    def check_token(self, user, token):
        """
        Check that a password reset token is correct for a given user.
        """
        # Parse the token
        try:
            ts_b36, hash = token.split("-")
        except ValueError:
            return False

        try:
            ts = base36_to_int(ts_b36)
        except ValueError:
            return False

        # Check that the timestamp/uid has not been tampered with
        if not constant_time_compare(self._make_token_with_timestamp(user, ts), token):
            return False

        # Check the timestamp is within limit
        if (self._num_days(self._today()) - ts) > settings.PASSWORD_RESET_TIMEOUT_DAYS:
            return False

        return True
Exemplo n.º 5
0
 def test_constant_time_compare(self):
     # It's hard to test for constant time, just test the result.
     self.assertTrue(constant_time_compare(b"spam", b"spam"))
     self.assertFalse(constant_time_compare(b"spam", b"eggs"))
     self.assertTrue(constant_time_compare("spam", "spam"))
     self.assertFalse(constant_time_compare("spam", "eggs"))
Exemplo n.º 6
0
 def _check_security_hash(self, token, request, form):
     expected = self.security_hash(request, form)
     return constant_time_compare(token, expected)
Exemplo n.º 7
0
    def process_view(self, request, callback, callback_args, callback_kwargs):

        if getattr(request, 'csrf_processing_done', False):
            return None

        try:
            csrf_token = _sanitize_token(
                request.COOKIES[settings.CSRF_COOKIE_NAME])
            # Use same token next time
            request.META['CSRF_COOKIE'] = csrf_token
        except KeyError:
            csrf_token = None
            # Generate token and store it in the request, so it's
            # available to the view.
            request.META["CSRF_COOKIE"] = _get_new_csrf_key()

        # Wait until request.META["CSRF_COOKIE"] has been manipulated before
        # bailing out, so that get_token still works
        if getattr(callback, 'csrf_exempt', False):
            return None

        # Assume that anything not defined as 'safe' by RC2616 needs protection
        if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
            if getattr(request, '_dont_enforce_csrf_checks', False):
                # Mechanism to turn off CSRF checks for test suite.
                # It comes after the creation of CSRF cookies, so that
                # everything else continues to work exactly the same
                # (e.g. cookies are sent, etc.), but before any
                # branches that call reject().
                return self._accept(request)

            if request.is_secure():
                # Suppose user visits http://example.com/
                # An active network attacker (man-in-the-middle, MITM) sends a
                # POST form that targets https://example.com/detonate-bomb/ and
                # submits it via JavaScript.
                #
                # The attacker will need to provide a CSRF cookie and token, but
                # that's no problem for a MITM and the session-independent
                # nonce we're using. So the MITM can circumvent the CSRF
                # protection. This is true for any HTTP connection, but anyone
                # using HTTPS expects better! For this reason, for
                # https://example.com/ we need additional protection that treats
                # http://example.com/ as completely untrusted. Under HTTPS,
                # Barth et al. found that the Referer header is missing for
                # same-domain requests in only about 0.2% of cases or less, so
                # we can use strict Referer checking.
                referer = request.META.get('HTTP_REFERER')
                if referer is None:
                    logger.warning('Forbidden (%s): %s',
                                   REASON_NO_REFERER, request.path,
                        extra={
                            'status_code': 403,
                            'request': request,
                        }
                    )
                    return self._reject(request, REASON_NO_REFERER)

                # Note that request.get_host() includes the port.
                good_referer = 'https://%s/' % request.get_host()
                if not same_origin(referer, good_referer):
                    reason = REASON_BAD_REFERER % (referer, good_referer)
                    logger.warning('Forbidden (%s): %s', reason, request.path,
                        extra={
                            'status_code': 403,
                            'request': request,
                        }
                    )
                    return self._reject(request, reason)

            if csrf_token is None:
                # No CSRF cookie. For POST requests, we insist on a CSRF cookie,
                # and in this way we can avoid all CSRF attacks, including login
                # CSRF.
                logger.warning('Forbidden (%s): %s',
                               REASON_NO_CSRF_COOKIE, request.path,
                    extra={
                        'status_code': 403,
                        'request': request,
                    }
                )
                return self._reject(request, REASON_NO_CSRF_COOKIE)

            # Check non-cookie token for match.
            request_csrf_token = ""
            if request.method == "POST":
                request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')

            if request_csrf_token == "":
                # Fall back to X-CSRFToken, to make things easier for AJAX,
                # and possible for PUT/DELETE.
                request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '')

            if not constant_time_compare(request_csrf_token, csrf_token):
                logger.warning('Forbidden (%s): %s',
                               REASON_BAD_TOKEN, request.path,
                    extra={
                        'status_code': 403,
                        'request': request,
                    }
                )
                return self._reject(request, REASON_BAD_TOKEN)

        return self._accept(request)
Exemplo n.º 8
0
 def verify(self, password, encoded):
     crypt = self._load_library()
     algorithm, salt, data = encoded.split('$', 2)
     assert algorithm == self.algorithm
     return constant_time_compare(data, crypt.crypt(password, data))
Exemplo n.º 9
0
 def verify(self, password, encoded):
     encoded_2 = self.encode(password, '')
     return constant_time_compare(encoded, encoded_2)
Exemplo n.º 10
0
 def verify(self, password, encoded):
     algorithm, salt, hash = encoded.split('$', 2)
     assert algorithm == self.algorithm
     encoded_2 = self.encode(password, salt)
     return constant_time_compare(encoded, encoded_2)
Exemplo n.º 11
0
 def verify(self, password, encoded):
     algorithm, data = encoded.split('$', 1)
     assert algorithm == self.algorithm
     bcrypt = self._load_library()
     return constant_time_compare(data, bcrypt.hashpw(password, data))