Changeset - 9b74296e6af6
[Not reviewed]
stable
0 1 0
Søren Løvborg - 10 years ago 2016-04-19 18:02:56
sorenl@unity3d.com
auth: further sanitize requests to prevent GET CSRF (CVE-2016-3691)

Routes allows GET requests to override the HTTP method, which breaks
the Kallithea CSRF protection (which only applies to POST requests).

This commit blocks such GET request, preventing CSRF attacks.
1 file changed with 10 insertions and 0 deletions:
0 comments (0 inline, 0 general)
kallithea/lib/auth.py
Show inline comments
 
@@ -745,48 +745,58 @@ class LoginRequired(object):
 

	
 
        # check if we used an API key and it's a valid one
 
        api_key = request.GET.get('api_key')
 
        if api_key is not None:
 
            # explicit controller is enabled or API is in our whitelist
 
            if self.api_access or allowed_api_access(loc, api_key=api_key):
 
                if api_key in user.api_keys:
 
                    log.info('user %s authenticated with API key ****%s @ %s',
 
                             user, api_key[-4:], loc)
 
                    return func(*fargs, **fkwargs)
 
                else:
 
                    log.warning('API key ****%s is NOT valid', api_key[-4:])
 
                    return redirect_to_login(_('Invalid API key'))
 
            else:
 
                # controller does not allow API access
 
                log.warning('API access to %s is not allowed', loc)
 
                return abort(403)
 

	
 
        # Only allow the following HTTP request methods. (We sometimes use POST
 
        # requests with a '_method' set to 'PUT' or 'DELETE'; but that is only
 
        # used for the route lookup, and does not affect request.method.)
 
        if request.method not in ['GET', 'HEAD', 'POST', 'PUT']:
 
            return abort(405)
 

	
 
        # Also verify the _method override. This is only permitted in POST
 
        # requests, and can specify PUT or DELETE.
 
        _method = request.params.get('_method')
 
        if _method is None:
 
            pass # no override, no problem
 
        elif request.method == 'POST' and _method.upper() in ['PUT', 'DELETE']:
 
            pass # permitted override
 
        else:
 
            raise HTTPMethodNotAllowed()
 

	
 
        # Make sure CSRF token never appears in the URL. If so, invalidate it.
 
        if secure_form.token_key in request.GET:
 
            log.error('CSRF key leak detected')
 
            session.pop(secure_form.token_key, None)
 
            session.save()
 
            from kallithea.lib import helpers as h
 
            h.flash(_("CSRF token leak has been detected - all form tokens have been expired"),
 
                    category='error')
 

	
 
        # CSRF protection: Whenever a request has ambient authority (whether
 
        # through a session cookie or its origin IP address), it must include
 
        # the correct token, unless the HTTP method is GET or HEAD (and thus
 
        # guaranteed to be side effect free. In practice, the only situation
 
        # where we allow side effects without ambient authority is when the
 
        # authority comes from an API key; and that is handled above.
 
        if request.method not in ['GET', 'HEAD']:
 
            token = request.POST.get(secure_form.token_key)
 
            if not token or token != secure_form.authentication_token():
 
                log.error('CSRF check failed')
 
                return abort(403)
 

	
 
        # WebOb already ignores request payload parameters for anything other
 
        # than POST/PUT, but double-check since other Kallithea code relies on
 
        # this assumption.
0 comments (0 inline, 0 general)