Learning Python Network Programming

(Sean Pound) #1

Applications for the Web


CSRF

The second form of attack is the Cross-Site Request Forgery (CSRF). In this attack,
a site is tricked into carrying out actions in the security context of a user, without
the user's knowledge or consent. Frequently this is initiated by an XSS attack that
causes a user's browser to perform an operation on the target site while the user is
logged in. It should be noted that this can affect sites even when a user isn't actively
browsing them; sites often clear cookie authentication tokens only when a user
explicitly logs out, and hence from the site and browser's point of view, any request
coming from the browser even after the user has stopped browsing a site—if they
haven't logged out—will be as if the user is still logged in.


One technique to help prevent CSRF attacks is to make potentially abusable
operations, such as submitting forms, require a one-time nonce value that is
only known to the server and the client. CRSF attacks often take the form of a
pre-composed HTTP request, mimicking a user submitting a form or similar.
However, if every time a server sends a form to a client it includes a different
nonce value, then the attacker has no way of including this in the pre-composed
request, and hence the attack attempt can be detected and rejected. This technique
is less effective against XSS initiated attacks, and attacks where an attacker is
eavesdropping the HTTP traffic of a browsing session. The former is difficult to
completely protect against, and the best solution is to ensure XSS vulnerabilities are
not present in the first place. The latter can be mitigated using HTTPS rather than
HTTP. See the OWASP pages linked to below for further information.


Different frameworks have different approaches to providing nonce-based CSRF
protection. Flask doesn't have this functionality built in, but it is very easy to add
something, for example:


@app.before_request
def csrf_protect():
if request.method == "POST":
token = session.pop('_csrf_token', None)
if not token or token != request.form.get('_csrf_token'):
abort(403)

def generate_csrf_token():
if '_csrf_token' not in session:
session['_csrf_token'] = some_random_string()
return session['_csrf_token']

app.jinja_env.globals['csrf_token'] = generate_csrf_token
Free download pdf