Exemple #1
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):
            # Fallback to Django 1.2 method for compatibility.
            # PendingDeprecationWarning <- here to remind us to remove this in
            # Django 1.5
            if not constant_time_compare(self._make_token_with_timestamp_old(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
Exemple #2
0
def rauth(request):
    """
        An implementation of Jille Timmermans' rauth scheme
        The token that is given to the authenticated user is only valid until
        the end of the day.
    """
    if request.REQUEST.get('url') is None:
        raise Http404
    if (request.REQUEST.get('validate') is not None and
            request.REQUEST.get('user') is not None):
        token = sha256('%s|%s|%s|%s' % (
            request.REQUEST['user'],
            date.today(),
            request.REQUEST['url'],
            settings.SECRET_KEY)).hexdigest()
        if constant_time_compare(request.REQUEST['validate'], token):
            return HttpResponse("OK")
        return HttpResponse("INVALID")

    '''
    The next check will allow you to request information about the user that
    is currently logged in using the 'fetch'-get attribute with the property
    names seperated by commas.
    A JSON string will be returned containing the information.
    '''
    if (request.REQUEST.get('fetch') is not None and
            request.REQUEST.get('user') is not None):
        token = sha256('%s|%s|%s|%s' % (
            request.REQUEST['user'],
            date.today(),
            request.REQUEST['url'],
            settings.SECRET_KEY)).hexdigest()
        if constant_time_compare(request.REQUEST['token'], token):
            user = Es.by_name(request.REQUEST['user'])
            properties = {
                'firstname': user.first_name,
                'lastname': user.last_name,
                'fullname': user.full_name,
                'groups': list(user.cached_groups_names)
            }
            return HttpResponse(json.dumps(dict([
                (k, properties[k]) for k in
                set(s.strip() for s in request.REQUEST.get('fetch').split(','))
                if k in properties
            ])))
        return HttpResponse("INVALID TOKEN")
    if not request.user.is_authenticated():
        return redirect_to_login('%s?url=%s' % (
            reverse('rauth'),
            urlquote(request.REQUEST['url'])))
    token = sha256('%s|%s|%s|%s' % (str(request.user.name),
                                    date.today(),
                                    request.REQUEST['url'],
                                    settings.SECRET_KEY)).hexdigest()
    return HttpResponseRedirect('%s%suser=%s&token=%s' % (
        request.REQUEST['url'],
        '?' if request.REQUEST['url'].find('?') == -1 else '&',
        str(request.user.name), token))
Exemple #3
0
 def flag_is_correct(self, flag):
     """ Test if a flag matches the challenge metadata.
     """
     expected = self.flag.lower()
     provided = flag.strip().lower()
     wrapped = 'flag{%s}' % (provided,)
     if constant_time_compare(expected, provided) or \
             constant_time_compare(expected, wrapped):
         return True
     else:
         return False
    def clean_hash(self):
        hash = self.cleaned_data["hash"]

        if not constant_time_compare(hash, self.make_hash(self.data)):
            raise ValidationError("Tamper alert")

        return hash
Exemple #5
0
    def wrapper(request, *args, **kwargs):
        authentication = app_settings.RECURLY_WEBHOOK_HTTP_AUTHENTICATION

        # If the user has not setup settings.RECURLY_WEBHOOK_HTTP_AUTHENTICATION then
        # we trust they are doing it at the web server level.
        if authentication is None:
            return fn(request, *args, **kwargs)

        try:
            method, auth = request.META['HTTP_AUTHORIZATION'].split(' ', 1)
        except KeyError:
            response = HttpResponse()
            response.status_code = 401
            response['WWW-Authenticate'] = 'Basic realm="Restricted"'
            return response

        try:
            if method.lower() != 'basic':
                raise ValueError()

            if not constant_time_compare(auth.strip().decode('base64'), authentication):
                return HttpResponseForbidden()
        except Exception:
            return HttpResponseBadRequest()

        return fn(request, *args, **kwargs)
    def check_phpsessid(self, request):
        if request.user.is_authenticated:
            backend = auth.load_backend(request.session[auth.BACKEND_SESSION_KEY])
            if not isinstance(backend, FlourishSessionBackend):
                return

            if not constant_time_compare(request.session['PHPSESSID'],
                                         request.COOKIES.get('PHPSESSID')):

                # The user has changed session or logged out without us knowing.
                # This should not happen. Clean up the both sessions just in case.
                auth.logout(request)

            return

        try:
            rawphpsessid = request.COOKIES['PHPSESSID']
        except KeyError:
            return

        # Try to authenticate this user. It's pretty likely that
        # FlourishSessionBackend will succeed, but not guaranteed.
        #
        # Change the order of AUTHENTICATION_BACKENDS if this causes
        # you problems.
        user = auth.authenticate(request, rawphpsessid=rawphpsessid)
        if user:
            request.user = user
            auth.login(request, user)
Exemple #7
0
def get_user(request):
    """
    Returns the user model instance associated with the given request session.
    If no user is retrieved an instance of `AnonymousUser` is returned.
    """
    from .models import AnonymousUser
    user = None
    try:
        user_id = _get_user_session_key(request)
        backend_path = request.session[BACKEND_SESSION_KEY]
    except KeyError:
        pass
    else:
        if backend_path in settings.AUTHENTICATION_BACKENDS:
            backend = load_backend(backend_path)
            user = backend.get_user(user_id)
            # Verify the session
            if hasattr(user, 'get_session_auth_hash'):
                session_hash = request.session.get(HASH_SESSION_KEY)
                session_hash_verified = session_hash and constant_time_compare(
                    session_hash,
                    user.get_session_auth_hash()
                )
                if not session_hash_verified:
                    request.session.flush()
                    user = None

    return user or AnonymousUser()
Exemple #8
0
    def process_view(self, request, view_func, args, kwargs):
        """Check the CSRF token if this is a POST."""
        if getattr(request, "csrf_processing_done", False):
            return

        # Allow @csrf_exempt views.
        if getattr(view_func, "csrf_exempt", False):
            return

        # Bail if this isn't a POST.
        if request.method != "POST":
            return self._accept(request)

        # The test client uses this to get around CSRF processing.
        if getattr(request, "_dont_enforce_csrf_checks", False):
            return self._accept(request)

        # Try to get the token from the POST and fall back to looking at the
        # X-CSRFTOKEN header.
        user_token = request.POST.get("csrfmiddlewaretoken", "")
        if user_token == "":
            user_token = request.META.get("HTTP_X_CSRFTOKEN", "")

        request_token = getattr(request, "csrf_token", "")

        # Check that both strings aren't empty and then check for a match.
        if not ((user_token or request_token) and crypto.constant_time_compare(user_token, request_token)):
            reason = django_csrf.REASON_BAD_TOKEN
            django_csrf.logger.warning(
                "Forbidden (%s): %s" % (reason, request.path), extra=dict(status_code=403, request=request)
            )
            return self._reject(request, reason)
        else:
            return self._accept(request)
Exemple #9
0
    def project_key_from_auth(self, auth):
        if not auth.public_key:
            raise APIUnauthorized('Invalid api key')

        # Make sure the key even looks valid first, since it's
        # possible to get some garbage input here causing further
        # issues trying to query it from cache or the database.
        if not ProjectKey.looks_like_api_key(auth.public_key):
            raise APIUnauthorized('Invalid api key')

        try:
            pk = ProjectKey.objects.get_from_cache(public_key=auth.public_key)
        except ProjectKey.DoesNotExist:
            raise APIUnauthorized('Invalid api key')

        # a secret key may not be present which will be validated elsewhere
        if not constant_time_compare(pk.secret_key, auth.secret_key or pk.secret_key):
            raise APIUnauthorized('Invalid api key')

        if not pk.is_active:
            raise APIUnauthorized('API key is disabled')

        if not pk.roles.store:
            raise APIUnauthorized('Key does not allow event storage access')

        return pk
def logout(request):
    name = request.GET.get('app', '')
    service = Service.objects.filter(name=name).first()
    if not service:
        return redirect('/')

    time = request.GET.get('time', '0')
    time = int(time) if time.isdigit() else 0

    date = datetime.datetime.fromtimestamp(time, timezone.utc)
    now = timezone.now()
    if abs((now - date).total_seconds()) > 10:
        return redirect(service.main_url)

    sm = ServiceMap.objects.filter(user=request.user, service=service).first()
    if not sm:
        return redirect(service.main_url)

    m = hmac.new(str(service.secret_key),
                 str('%s:%s' % (time, sm.sid))).hexdigest()
    m_client = request.GET.get('m', '')
    if constant_time_compare(m, m_client):
        logger.info('logout', {'r': request})
        auth.logout(request)

    return redirect(service.main_url)
Exemple #11
0
def check_password(raw_password, enc_password):
    """
    Returns a boolean of whether the raw_password was correct. Handles
    encryption formats behind the scenes.
    """
    algo, salt, hsh = enc_password.split('$')
    return constant_time_compare(hsh, get_hexdigest(algo, salt, raw_password))
    def authenticate_credentials(self, payload):
        """
        Return a non-deleted user that matches the payload's user id.

        Mimic what our UserAndAddrMiddleware and django's get_user() do when
        authenticating, because otherwise that behaviour would be missing in
        the API since API auth happens after the middleware process request
        phase.
        """
        if 'user_id' not in payload:
            log.info('No user_id in token payload {}'.format(payload))
            raise exceptions.AuthenticationFailed()
        try:
            user = UserProfile.objects.filter(deleted=False).get(
                pk=payload['user_id'])
        except UserProfile.DoesNotExist:
            log.info('User not found from token payload {}'.format(payload))
            raise exceptions.AuthenticationFailed()

        # Check get_session_auth_hash like django's get_user() does.
        session_auth_hash = user.get_session_auth_hash()
        payload_auth_hash = payload.get('auth_hash', '')
        if not constant_time_compare(payload_auth_hash, session_auth_hash):
            log.info('User tried to authenticate with invalid auth hash in'
                     'payload {}'.format(payload))
            raise exceptions.AuthenticationFailed()

        # Set user in thread like UserAndAddrMiddleware does.
        core.set_user(user)
        return user
Exemple #13
0
 def unsign(self, signed_value):
     if self.sep not in signed_value:
         raise BadSignature('No "%s" found in value' % self.sep)
     value, sig = signed_value.rsplit(self.sep, 1)
     if constant_time_compare(sig, self.signature(value)):
         return value
     raise BadSignature('Signature "%s" does not match' % sig)
Exemple #14
0
async def get_user(scope: Dict[str, Any]) -> Dict[str, Any]:
    """
    Returns a user id from a channels-scope-session.

    If no user is retrieved, return {'id': 0}.
    """
    # This code is basicly from channels.auth:
    # https://github.com/django/channels/blob/d5e81a78e96770127da79248349808b6ee6ec2a7/channels/auth.py#L16
    if "session" not in scope:
        raise ValueError(
            "Cannot find session in scope. You should wrap your consumer in SessionMiddleware."
        )
    session = scope["session"]
    user: Optional[Dict[str, Any]] = None
    try:
        user_id = _get_user_session_key(session)
        backend_path = session[BACKEND_SESSION_KEY]
    except KeyError:
        pass
    else:
        if backend_path in settings.AUTHENTICATION_BACKENDS:
            user = await element_cache.get_element_full_data("users/user", user_id)
            if user:
                # Verify the session
                session_hash = session.get(HASH_SESSION_KEY)
                session_hash_verified = session_hash and constant_time_compare(
                    session_hash, user["session_auth_hash"]
                )
                if not session_hash_verified:
                    session.flush()
                    user = None
    return user or {"id": 0}
def validate_request(request):
    """Check an incoming request.

    Returns:
        - True if authentication passed
        - Adding request['REMOTE_USER'] as authenticated username.
    """
    if getattr(settings, 'BASICAUTH_DISABLE', False):
        # Not to use this env
        return True

    if 'HTTP_AUTHORIZATION' not in request.META:
        return False

    authorization_header = request.META['HTTP_AUTHORIZATION']
    ret = extract_basicauth(authorization_header)
    if not ret:
        return False

    username, password = ret

    raw_pass = settings.BASICAUTH_USERS.get(username)
    if raw_pass is None:
        return False

    # To avoid timing atacks
    # https://security.stackexchange.com/questions/83660/simple-string-comparisons-not-secure-against-timing-attacks
    if not constant_time_compare(raw_pass, password):
        return False

    request.META['REMOTE_USER'] = username
    return True
Exemple #16
0
 def _decode_old(self, session_data):
     encoded_data = base64.decodestring(session_data)
     pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
     if not constant_time_compare(md5_constructor(pickled + settings.SECRET_KEY).hexdigest(),
                                  tamper_check):
         raise SuspiciousOperation("User tampered with session cookie.")
     return pickle.loads(pickled)
Exemple #17
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) > REGISTRATION_TIMEOUT_DAYS:
            return False

        return True
Exemple #18
0
def _compare_salted_tokens(request_csrf_token, csrf_token):
    # Assume both arguments are sanitized -- that is, strings of
    # length CSRF_TOKEN_LENGTH, all CSRF_ALLOWED_CHARS.
    return constant_time_compare(
        _unsalt_cipher_token(request_csrf_token),
        _unsalt_cipher_token(csrf_token),
    )
Exemple #19
0
    def check_token(self, newsletter_recipient, token):
        """
        Check that a newsletter unsubscribe token is correct
        for a given recipient.

        """
        # 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(
                    newsletter_recipient, ts
                ), token
        ):
            return False

        return True
Exemple #20
0
def get_user(scope):
    """
    Return the user model instance associated with the given scope.
    If no user is retrieved, return an instance of `AnonymousUser`.
    """
    if "session" not in scope:
        raise ValueError(
            "Cannot find session in scope. You should wrap your consumer in SessionMiddleware."
        )
    session = scope["session"]
    user = None
    try:
        user_id = _get_user_session_key(session)
        backend_path = session[BACKEND_SESSION_KEY]
    except KeyError:
        pass
    else:
        if backend_path in settings.AUTHENTICATION_BACKENDS:
            backend = load_backend(backend_path)
            user = backend.get_user(user_id)
            # Verify the session
            if hasattr(user, "get_session_auth_hash"):
                session_hash = session.get(HASH_SESSION_KEY)
                session_hash_verified = session_hash and constant_time_compare(
                    session_hash, user.get_session_auth_hash()
                )
                if not session_hash_verified:
                    session.flush()
                    user = None
    return user or AnonymousUser()
Exemple #21
0
    def check_token(self, user, token):
        """
        Check that a password reset token is correct for a given user.
        """
        if not (user and token):
            return False
        # 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. Timestamps are rounded to
        # midnight (server time) providing a resolution of only 1 day. If a
        # link is generated 5 minutes before midnight and used 6 minutes later,
        # that counts as 1 day. Therefore, PASSWORD_RESET_TIMEOUT_DAYS = 1 means
        # "at least 1 day, could be up to 2."
        if (self._num_days(self._today()) - ts) > settings.PASSWORD_RESET_TIMEOUT_DAYS:
            return False

        return True
 def _check_security_hash(self, token, request, form):
     expected = self.security_hash(request, form)
     if constant_time_compare(token, expected):
         return True
     else:
         raise
         return False
    def check_token(self, instance, token):
        """
        Check that a token is correct for a given instance.

        """
        # Parse the token
        try:
            nd_b36, hash = token.split("-")
        except ValueError:
            return False

        try:
            nd = base36_to_int(nd_b36)
        except ValueError:
            return False

        # Check that the num_days/uid has not been tampered with
        if not constant_time_compare(self._make_token_with_timestamp(instance, nd), token):
            return False

        # Check the num_days is within limit
        if (self._num_days(self._today()) - nd) > self._timeout_days():
            return False

        return True
Exemple #24
0
def get_express_session(req, cookie_name='express_sess'):
    """
    get the Express.js session dict. 

    default session cookie name of express:sess does now work with django.
    """
    key = settings.SECRET_KEY
    cookie_value = req.COOKIES.get(cookie_name)
    cookie_sig = req.COOKIES.get(cookie_name + '.sig')
    if not cookie_value or not cookie_sig:
        return {}

    cookie = cookie_name + '=' + cookie_value
    hmac = Hmac.new(key, cookie, hashlib.sha1)
    digest = signing.b64_encode(hmac.digest())
    valid_sig = crypto.constant_time_compare(digest, cookie_sig)
    if not valid_sig:
        return {}

    try:
        json_data = signing.b64_decode(cookie_value)
        session = json.loads(json_data)
    except:
        return {}
    return session
Exemple #25
0
    def check_token(self, user, token, token_expires=True):
        """
        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
        token_is_expired = all(
            token_expires,
            (self._num_days(self._today()) - ts) > settings.PASSWORD_RESET_TIMEOUT_DAYS,
        )
        if token_is_expired:
            return False

        return True
    def auth_complete(self, *args, **kwargs):
        """Completes loging process, must return user instance"""
        if self.data.get('error'):
            error = self.data.get('error_description') or self.data['error']
            raise AuthFailed(self, error)

        if self.FORCE_STATE_CHECK:
            if 'state' not in self.data:
                raise AuthMissingParameter(self, 'state')
            state = self.request.session[self.AUTH_BACKEND.name + '_state']
            if not constant_time_compare(self.data['state'], state):
                raise AuthForbidden(self)

        client_id, client_secret = self.get_key_and_secret()
        params = {'grant_type': 'authorization_code',  # request auth code
                  'code': self.data.get('code', ''),  # server response code
                  'client_id': client_id,
                  'client_secret': client_secret,
                  'redirect_uri': self.redirect_uri}
        headers = {'Content-Type': 'application/x-www-form-urlencoded',
                    'Accept': 'application/json'}
        request = Request(self.ACCESS_TOKEN_URL, data=urlencode(params),
                          headers=headers)

        try:
            response = simplejson.loads(urlopen(request).read())
        except HTTPError, e:
            if e.code == 400:
                raise AuthCanceled(self)
            else:
                raise
Exemple #27
0
def health(request):
    secret = settings.HEALTH_SECRET
    if secret is not None and not request.user.is_superuser:
        token = request.META.get('HTTP_X_TOKEN', None)
        if token is None or not constant_time_compare(token, secret):
            raise PermissionDenied()
    conn = get_redis_connection()
    workers = Worker.all(connection=conn)

    queues = defaultdict(lambda: defaultdict(int))
    for worker in workers:
        for queue in worker.queues:
            queues[queue.name]['workers'] += 1
            queues[queue.name]['tasks'] = queue.count

    data = {
        'queues': queues,
        'users': {
            'total': User.objects.all().count(),
            'active': User.objects.filter(is_suspended=False).count(),
        },
        'feeds': {
            'total': Feed.objects.all().count(),
            'unique': UniqueFeed.objects.all().count(),
        },
    }
    response = HttpResponse(json.dumps(data))
    response['Content-Type'] = 'application/json'
    return response
    def _test_signature(self, request):
        """ Return True/False if the signature is recognized

        Note, we accept from UI server, admin server and MI server.

        Note, we set the `server_name` attribute of the matched server on
        request for permission management.

        """
        offered = request.META.get("HTTP_X_SIGNATURE")
        if not offered:
            return False

        # check each server secret for a match
        servers = [
            (settings.UI_SECRET, 'ui'),
            (settings.ADMIN_SECRET, 'admin'),
            (settings.MI_SECRET, 'mi'),
            (settings.DATA_SECRET, 'data')
        ]
        for secret, server_name in servers:
            generated = self._generate_signature(
                secret,
                request.get_full_path(),
                request.body,
            )
            if constant_time_compare(generated, offered):
                request.server_name = server_name
                return True
def get_user(request):
    """
    Returns the user model instance associated with the given request session.
    If no user is retrieved an instance of `MojAnonymousUser` is returned.
    """
    user = None
    try:
        user_id = request.session[SESSION_KEY]
        token = request.session[AUTH_TOKEN_SESSION_KEY]
        user_data = request.session[USER_DATA_SESSION_KEY]
        backend_path = request.session[BACKEND_SESSION_KEY]
    except KeyError:
        pass
    else:
        if backend_path in settings.AUTHENTICATION_BACKENDS:
            backend = load_backend(backend_path)
            user = backend.get_user(user_id, token, user_data)
            # Verify the session
            if hasattr(user, "get_session_auth_hash"):
                session_hash = request.session.get(HASH_SESSION_KEY)
                session_hash_verified = session_hash and constant_time_compare(
                    session_hash, user.get_session_auth_hash()
                )
                if not session_hash_verified:
                    request.session.flush()
                    user = None

    return user or MojAnonymousUser()
 def _broadcast(self, model, pk, action):
     signature = self.request.headers.get('X-Signature', None)
     if not signature:
         raise HTTPError(400)
     try:
         result = self.application.signer.unsign(signature, max_age=60 * 1)
     except (BadSignature, SignatureExpired):
         raise HTTPError(400)
     else:
         expected = '{method}:{url}:{body}'.format(
             method=self.request.method.lower(),
             url=self.request.full_url(),
             body=hashlib.sha256(self.request.body).hexdigest(),
         )
         if not constant_time_compare(result, expected):
             raise HTTPError(400)
     try:
         body = json.loads(self.request.body.decode('utf-8'))
     except ValueError:
         body = None
     message = json.dumps({
         'model': model,
         'id': pk,
         'action': action,
         'body': body,
     })
     self.application.broadcast(message)
     self.write("Ok")
Exemple #31
0
def check_http_auth(request):
    """
    Check if a request includes HTTP authentication.

    If HTTP authentication is permitted for the given request, and a
    valid username and password are provided, set request.user to the
    corresponding user object.  Otherwise, the request is not
    modified.

    For safety, HTTP authentication is only used for certain requests
    from non-interactive user agents; see http_auth_allowed().

    This should be invoked at the start of the view before checking
    user credentials, and should be paired with require_http_auth().
    """

    if 'HTTP_AUTHORIZATION' in request.META:
        # If an Authorization header is supplied, but this request is
        # not allowed to use HTTP authentication, ignore the header.
        if not http_auth_allowed(request):
            return

        # If the user is already authenticated, ignore the header.
        if request.user.is_authenticated:
            return

        try:
            uid = request.session['pn_httpauth_uid']
            authhash = request.session['pn_httpauth_hash']
            user = User.objects.get(id=uid)
        except (KeyError, User.DoesNotExist):
            pass
        else:
            # Existing session is valid only if the password has not
            # changed.
            if constant_time_compare(user.get_session_auth_hash(),
                                     authhash) and user.is_active:
                request.user = user
                return

        tokens = request.META['HTTP_AUTHORIZATION'].split()
        if len(tokens) == 2 and tokens[0].lower() == 'basic':
            try:
                data = base64.b64decode(tokens[1], validate=True).decode()
                username, password = data.split(':', 1)
            except Exception:
                return

            user = auth.authenticate(request=request,
                                     username=username,
                                     password=password)
            if user and user.is_active:
                request.user = user

                # If the client supports cookies, save the state so
                # that we don't have to verify the password on
                # subsequent requests.  If the client doesn't support
                # cookies, don't bother.
                if request.COOKIES:
                    # We don't invoke auth.login() here, specifically
                    # so that this session ID cannot be reused to
                    # access URLs that don't permit HTTP
                    # authentication.
                    request.session['pn_httpauth_uid'] = user.id
                    request.session['pn_httpauth_hash'] \
                        = user.get_session_auth_hash()
Exemple #32
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'))
Exemple #33
0
 def verify(self, password, encoded):
     encoded_2 = self.encode(password, '')
     return constant_time_compare(encoded, encoded_2)
 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)
Exemple #35
0
 def check_and_unfollow(self, check):
     secret = self.get_follow_secret()
     if constant_time_compare(check, secret):
         self.delete()
         return True
     return False
Exemple #36
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 RFC2616 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:
                    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)
                    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.
                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):
                return self._reject(request, REASON_BAD_TOKEN)

        return self._accept(request)
Exemple #37
0
 def verify(self, password, encoded):
     crypt = self._load_library()
     decoded = self.decode(encoded)
     data = crypt.crypt(password, decoded['hash'])
     return constant_time_compare(decoded['hash'], data)
Exemple #38
0
 def verify(self, password, encoded):
     if len(encoded) == 37 and encoded.startswith('md5$$'):
         encoded = encoded[5:]
     encoded_2 = self.encode(password, '')
     return constant_time_compare(encoded, encoded_2)
Exemple #39
0
 def verify(self, password, encoded):
     algorithm, data = encoded.split('$', 1)
     assert algorithm == self.algorithm
     encoded_2 = self.encode(password, data.encode('ascii'))
     return constant_time_compare(encoded, encoded_2)
Exemple #40
0
 def verify(self, password, encoded):
     decoded = self.decode(encoded)
     encoded_2 = self.encode(password, decoded['salt'])
     return constant_time_compare(encoded, encoded_2)
Exemple #41
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(force_str(password), data))
Exemple #42
0
 def verify(self, password, encoded):
     decoded = self.decode(encoded)
     encoded_2 = self.encode(password, decoded["salt"],
                             decoded["iterations"])
     return constant_time_compare(encoded, encoded_2)
 def check_password(self, raw_password):
     hasher = sha256()
     raw_password = raw_password + '_' + self.salt
     hasher.update(raw_password.encode('utf-8'))
     result = constant_time_compare(hasher.hexdigest(), self.password)
     return result
Exemple #44
0
    def post(self, request):
        grant_type = request.POST.get('grant_type')

        if grant_type == 'authorization_code':
            client_id = request.POST.get('client_id')
            client_secret = request.POST.get('client_secret')
            redirect_uri = request.POST.get('redirect_uri')
            code = request.POST.get('code')

            if not client_id:
                return self.error('invalid_client')

            if not client_secret:
                return self.error('invalid_client')

            try:
                application = ApiApplication.objects.get(
                    client_id=client_id,
                    status=ApiApplicationStatus.active,
                )
            except ApiApplication.DoesNotExist:
                return self.error('invalid_client')

            if not constant_time_compare(client_secret, application.client_secret):
                return self.error('invalid_client')

            try:
                grant = ApiGrant.objects.get(application=application, code=code)
            except ApiGrant.DoesNotExist:
                return self.error('invalid_grant')

            if grant.is_expired():
                return self.error('invalid_grant')

            if not redirect_uri:
                redirect_uri = application.get_default_redirect_uri()
            elif grant.redirect_uri != redirect_uri:
                return self.error('invalid_grant')

            token = ApiToken.from_grant(grant)
        elif grant_type == 'refresh_token':
            refresh_token = request.POST.get('refresh_token')
            scope = request.POST.get('scope')
            client_id = request.POST.get('client_id')
            client_secret = request.POST.get('client_secret')

            if not refresh_token:
                return self.error('invalid_request')

            # TODO(dcramer): support scope
            if scope:
                return self.error('invalid_request')

            if not client_id:
                return self.error('invalid_client')

            if not client_secret:
                return self.error('invalid_client')

            try:
                application = ApiApplication.objects.get(
                    client_id=client_id,
                    status=ApiApplicationStatus.active,
                )
            except ApiApplication.DoesNotExist:
                return self.error('invalid_client')

            if not constant_time_compare(client_secret, application.client_secret):
                return self.error('invalid_client')

            try:
                token = ApiToken.objects.get(
                    application=application,
                    refresh_token=refresh_token,
                )
            except ApiToken.DoesNotExist:
                return self.error('invalid_grant')

            token.refresh()
        else:
            return self.error('unsupported_grant_type')

        return HttpResponse(json.dumps({
            'access_token': token.token,
            'refresh_token': token.refresh_token,
            'expires_in': (timezone.now() - token.expires_at).total_seconds(),
            'expires_at': token.expires_at,
            'token_type': 'bearer',
            'scope': ' '.join(token.get_scopes()),  # NOQA
            'user': {
                'id': six.text_type(token.user.id),
                # we might need these to become scope based
                'name': token.user.name,
                'email': token.user.email,
            },
        }), content_type='application/json')
Exemple #45
0
def constant_time_compare(val1, val2):
    """Performs constant_time_compare with consistent typing"""
    return crypto.constant_time_compare(binary_type(val1), binary_type(val2))
Exemple #46
0
 def _check_security_hash(self, token, request, form):
     expected = self.security_hash(request, form)
     return constant_time_compare(token, expected)
Exemple #47
0
 def from_request(cls, request, token):
     """Returns a system token if this is a valid system request."""
     system_token = get_system_token()
     if constant_time_compare(system_token, token) and is_internal_ip(request):
         return cls()
     return None
Exemple #48
0
 def check_token(self, user, token):
     return constant_time_compare(token, self._make_token(user))
Exemple #49
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

        # 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 RFC2616 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 = force_text(
                    request.META.get('HTTP_REFERER'),
                    strings_only=True,
                    errors='replace'
                )
                if referer is None:
                    return self._reject(request, REASON_NO_REFERER)

                referer = urlparse(referer)

                # Make sure we have a valid URL for Referer.
                if '' in (referer.scheme, referer.netloc):
                    return self._reject(request, REASON_MALFORMED_REFERER)

                # Ensure that our Referer is also secure.
                if referer.scheme != 'https':
                    return self._reject(request, REASON_INSECURE_REFERER)

                # If there isn't a CSRF_COOKIE_DOMAIN, assume we need an exact
                # match on host:port. If not, obey the cookie rules.
                if settings.CSRF_COOKIE_DOMAIN is None:
                    # request.get_host() includes the port.
                    good_referer = request.get_host()
                else:
                    good_referer = settings.CSRF_COOKIE_DOMAIN
                    server_port = request.META['SERVER_PORT']
                    if server_port not in ('443', '80'):
                        good_referer = '%s:%s' % (good_referer, server_port)

                # Here we generate a list of all acceptable HTTP referers,
                # including the current host since that has been validated
                # upstream.
                good_hosts = list(settings.CSRF_TRUSTED_ORIGINS)
                good_hosts.append(good_referer)

                if not any(is_same_domain(referer.netloc, host) for host in good_hosts):
                    reason = REASON_BAD_REFERER % referer.geturl()
                    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.
                return self._reject(request, REASON_NO_CSRF_COOKIE)

            # Check non-cookie token for match.
            request_csrf_token = ""
            if request.method == "POST":
                try:
                    request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
                except IOError:
                    # Handle a broken connection before we've completed reading
                    # the POST data. process_view shouldn't raise any
                    # exceptions, so we'll ignore and serve the user a 403
                    # (assuming they're still listening, which they probably
                    # aren't because of the error).
                    pass

            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(settings.CSRF_HEADER_NAME, '')

            if not constant_time_compare(request_csrf_token, csrf_token):
                return self._reject(request, REASON_BAD_TOKEN)

        return self._accept(request)
Exemple #50
0
    def process_view(self, request, callback, callback_args, callback_kwargs):
        # 如果请求里面设置了csrf_done,则没有任何处理,一旦这个设置了,那么整个中间件都
        # 不会产生作用
        if getattr(request, 'csrf_processing_done', False):
            return None

        try:
            # 从cookie里面拿出之前设置的cookie,将其净化
            csrf_token = _sanitize_token(
                request.COOKIES[settings.CSRF_COOKIE_NAME])
            # Use same token next time
            request.META['CSRF_COOKIE'] = csrf_token
        # 没有设置过,则在request中设置一个CSRF_COOKIE,这次请求必须是一个GET请求.
        # 如果开发的网站使用GET,HEAD等请求更新数据库(不符合规范),那么CSRF中间层不会
        # 正确的验证,因此绝对不要这样.
        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()

        # TODO:设置了就跳过这里的处理,下面的注释的意思
        # 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 RFC2616 needs protection
        if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
            # 如果请求中设置了不要开启csrf检查则直接ok,应该是其他中间件可以控制的,如
            # 果这个设置了,中间件只是处理response验证.以及设置个Cookie
            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)

            # 如果使用HTTPS,那么必须设置了refer并且和目标HOST一致.
            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 = force_text(request.META.get('HTTP_REFERER'),
                                     strings_only=True,
                                     errors='replace')
                if referer is None:
                    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)
                    return self._reject(request, reason)

            # 没有csrf_token则拒绝,也就是说对网站的第一个请求必须是get,因为之后会设置csrf.
            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.
                return self._reject(request, REASON_NO_CSRF_COOKIE)

            # Check non-cookie token for match.
            # 拿到其中的另一个csrf设置,对于POST,是csrfmt,对于其他,是HTTP_X_CSRFTOKEN
            # 判断这两个和POST中的是否一致.  可以POST.因为存在cookie中,而其他程序拿不到cookie值
            # 能发送但是不能拿到,然后在加上另外的值其他程序就没办法了
            request_csrf_token = ""
            if request.method == "POST":
                try:
                    # 是Django模板系统设置的.
                    request_csrf_token = request.POST.get(
                        'csrfmiddlewaretoken', '')
                except IOError:
                    # Handle a broken connection before we've completed reading
                    # the POST data. process_view shouldn't raise any
                    # exceptions, so we'll ignore and serve the user a 403
                    # (assuming they're still listening, which they probably
                    # aren't because of the error).
                    pass

            if request_csrf_token == "":
                # Fall back to X-CSRFToken, to make things easier for AJAX,
                # and possible for PUT/DELETE.
                # TODO: 是哪里设置的?:视图,模板等设置的.
                request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '')
            if not constant_time_compare(request_csrf_token, csrf_token):
                return self._reject(request, REASON_BAD_TOKEN)

        return self._accept(request)
Exemple #51
0
 def check_token(self, token, path):
     return constant_time_compare(
         token,
         salted_hmac(self.key_salt, path).hexdigest()[::2])
Exemple #52
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))
Exemple #53
0
 def check_confirmation_secret(self, secret, *args):
     return constant_time_compare(secret,
                                  self.generate_confirmation_secret(*args))
Exemple #54
0
 def check_autologin_secret(self, secret):
     return constant_time_compare(self.generate_autologin_secret(), secret)
Exemple #55
0
 def verify_project_token(cls, token, project_slug):
     expected_token = cls.get_project_token(project_slug)
     return constant_time_compare(token, expected_token)
Exemple #56
0
 def has_permission(self, request, view):
     return constant_time_compare(
         request.GET.get('token'),
         settings.CSV_DUMP_AUTH_TOKEN
     )
Exemple #57
0
 def verify(self, payload, key, signature):
     return constant_time_compare(
         signature,
         hmac.new(key=key.encode("utf-8"), msg=payload,
                  digestmod=sha256).hexdigest(),
     )
Exemple #58
0
    def get_session_data(self, current_datetime=None):
        """
        Return the current session data, with native types coerced.
        """
        request = self.request
        data = request.session.get(SESSION_KEY)

        try:
            cookie_token = request.get_signed_cookie(
                key=COOKIE_NAME,
                default=None,
                salt=COOKIE_SALT,
                max_age=MAX_AGE.total_seconds())
        except BadSignature:
            logger.exception(
                "superuser.bad-cookie-signature",
                extra={
                    "ip_address": request.META["REMOTE_ADDR"],
                    "user_id": request.user.id
                },
            )
            return

        if not cookie_token:
            if data:
                logger.warn(
                    "superuser.missing-cookie-token",
                    extra={
                        "ip_address": request.META["REMOTE_ADDR"],
                        "user_id": request.user.id
                    },
                )
            return False
        elif not data:
            logger.warn(
                "superuser.missing-session-data",
                extra={
                    "ip_address": request.META["REMOTE_ADDR"],
                    "user_id": request.user.id
                },
            )
            return

        session_token = data.get("tok")
        if not session_token:
            logger.warn(
                "superuser.missing-session-token",
                extra={
                    "ip_address": request.META["REMOTE_ADDR"],
                    "user_id": request.user.id
                },
            )
            return

        if not constant_time_compare(cookie_token, session_token):
            logger.warn(
                "superuser.invalid-token",
                extra={
                    "ip_address": request.META["REMOTE_ADDR"],
                    "user_id": request.user.id
                },
            )
            return

        if data["uid"] != six.text_type(request.user.id):
            logger.warn(
                "superuser.invalid-uid",
                extra={
                    "ip_address": request.META["REMOTE_ADDR"],
                    "user_id": request.user.id,
                    "expected_user_id": data["uid"],
                },
            )
            return

        if current_datetime is None:
            current_datetime = timezone.now()

        try:
            data["idl"] = datetime.utcfromtimestamp(float(
                data["idl"])).replace(tzinfo=timezone.utc)
        except (TypeError, ValueError):
            logger.warn(
                "superuser.invalid-idle-expiration",
                extra={
                    "ip_address": request.META["REMOTE_ADDR"],
                    "user_id": request.user.id
                },
                exc_info=True,
            )
            return

        if data["idl"] < current_datetime:
            logger.info(
                "superuser.session-expired",
                extra={
                    "ip_address": request.META["REMOTE_ADDR"],
                    "user_id": request.user.id
                },
            )
            return

        try:
            data["exp"] = datetime.utcfromtimestamp(float(
                data["exp"])).replace(tzinfo=timezone.utc)
        except (TypeError, ValueError):
            logger.warn(
                "superuser.invalid-expiration",
                extra={
                    "ip_address": request.META["REMOTE_ADDR"],
                    "user_id": request.user.id
                },
                exc_info=True,
            )
            return

        if data["exp"] < current_datetime:
            logger.info(
                "superuser.session-expired",
                extra={
                    "ip_address": request.META["REMOTE_ADDR"],
                    "user_id": request.user.id
                },
            )
            return

        return data
Exemple #59
0
    def process_view(self, request, callback, callback_args, callback_kwargs):
        if getattr(request, 'csrf_processing_done', False):
            return None

        # If the user doesn't have a CSRF cookie, generate one and store it in the
        # request, so it's available to the view.  We'll store it in a cookie when
        # we reach the response.
        try:
            # In case of cookies from untrusted sources, we strip anything
            # dangerous at this point, so that the cookie + token will have the
            # same, sanitized value.
            request.META["CSRF_COOKIE"] = _sanitize_token(
                request.COOKIES[settings.CSRF_COOKIE_NAME])
            cookie_is_new = False
        except KeyError:
            # No cookie, so create one.  This will be sent with the next
            # response.
            request.META["CSRF_COOKIE"] = _get_new_csrf_key()
            # Set a flag to allow us to fall back and allow the session id in
            # place of a CSRF cookie for this request only.
            cookie_is_new = True

        # 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

        if request.method == 'POST':
            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 the
                # any branches that call reject()
                return self._accept(request)

            if request.is_ajax():
                # .is_ajax() is based on the presence of X-Requested-With.  In
                # the context of a browser, this can only be sent if using
                # XmlHttpRequest.  Browsers implement careful policies for
                # XmlHttpRequest:
                #
                #  * Normally, only same-domain requests are allowed.
                #
                #  * Some browsers (e.g. Firefox 3.5 and later) relax this
                #    carefully:
                #
                #    * if it is a 'simple' GET or POST request (which can
                #      include no custom headers), it is allowed to be cross
                #      domain.  These requests will not be recognized as AJAX.
                #
                #    * if a 'preflight' check with the server confirms that the
                #      server is expecting and allows the request, cross domain
                #      requests even with custom headers are allowed. These
                #      requests will be recognized as AJAX, but can only get
                #      through when the developer has specifically opted in to
                #      allowing the cross-domain POST request.
                #
                # So in all cases, it is safe to allow these requests through.
                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 which targets https://example.com/detonate-bomb/ and
                # submits it via javascript.
                #
                # The attacker will need to provide a CSRF cookie and token, but
                # that is no problem for a MITM and the session independent
                # nonce we are 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_COOKIE, request.path),
                                   extra={
                                       'status_code': 403,
                                       'request': request,
                                   })
                    return self._reject(request, REASON_NO_REFERER)

                # The following check ensures that the referer is HTTPS,
                # the domains match and the ports match - the same origin policy.
                good_referer = 'https://%s/' % request.get_host()
                if not referer.startswith(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 the user didn't already have a CSRF cookie, then fall back to
            # the Django 1.1 method (hash of session ID), so a request is not
            # rejected if the form was sent to the user before upgrading to the
            # Django 1.2 method (session independent nonce)
            if cookie_is_new:
                try:
                    session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
                    csrf_token = _make_legacy_session_token(session_id)
                except KeyError:
                    # No CSRF cookie and no session 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_COOKIE, request.path),
                                   extra={
                                       'status_code': 403,
                                       'request': request,
                                   })
                    return self._reject(request, REASON_NO_COOKIE)
            else:
                csrf_token = request.META["CSRF_COOKIE"]

            # check incoming token
            request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
            if not constant_time_compare(request_csrf_token, csrf_token):
                if cookie_is_new:
                    # probably a problem setting the CSRF cookie
                    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)
                else:
                    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)
Exemple #60
0
 def get_email(self):
     expected_digest = salted_hmac(BLACKLIST_HMAC_SALT, self.kwargs['email'])
     if not constant_time_compare(expected_digest.hexdigest(), self.kwargs['digest']):
         raise Http404
     return self.kwargs['email']