You get a bonus - 1 coin for daily activity. Now you have 1 coin

CSRF Attack

Practice



You can't talk about AJAX without mentioning one of the most important aspects of its implementation – protection against CSRF attacks.

CSRF (Cross-Site Request Forgery, also XSRF) – is a very dangerous attack that allows a hacker to perform a variety of actions on an unprotected site on behalf of other, registered visitors.

What these actions are – sending messages, transferring money from one account to another, or changing passwords – depends on the site, but in any case this attack is part of the essential knowledge every web developer must have.

The evil form

The «classic» attack scenario is as follows:

  • Vasya is logged in to a site, let's say,

    mail.com
    . He has a session in his cookies.

  • Vasya ends up on an «evil page», for example a hacker invited him to do so via an email or some other way.

  • The evil page contains a form like this:

    
     
    ...
  • When landing on the evil page, JavaScript calls

    form.submit
    , thereby submitting the form to
    mail.com
    .

  • The site

    mail.com
    checks the cookies, sees that the visitor is authorized, and processes the form. In this example the form implies sending a message.

The result of the attack – Vasya, by visiting the evil page, unwittingly sent a message on his own behalf. The content of the message was crafted by the hacker.

Protection

In the example above, the attack exploited a weak link in authorization.

Cookies allow the site

mail.com

to verify that it was indeed Vasya who came, but they say nothing about the data he's sending.

In other words, cookies do not guarantee that the form was created by Vasya himself. They only verify identity, not data.

A typical way sites protect against this – is a «secret key» (

secret

), a special value that is generated randomly and stored in the visitor's session. Only the server knows it; we won't even show it to the visitor.

Then, based on the key, a «token» is generated (

token

). The token is made so that on one hand it differs from the key – in particular, there can be many tokens for one key – and on the other hand it's easy to verify from the token whether it was generated from a given key or not.

For each token an additional random value is needed, called the «salt»

salt

.

Token computation formula:

token = salt + ":" + MD5(salt + ":" + secret)

For example:

  1. The session stores
    secret="abcdef"
    , this value is created once.
  2. For a new token, we generate
    salt
    , for example let
    salt="1234"
    .
  3. token = "1234" + ":" + MD5("1234" + ":" + "abcdef") = "1234:5ad02792a3285252e524ccadeeda3401"
    .

This value is – on one hand, random, on the other hand – having such a

token

, we can take its first part

1234

as the

salt

and, knowing the

secret

, verify using the formula whether it was computed correctly.

Without knowing the

secret

, it is impossible to generate a token that the server will accept as correct.

Next, the token is added as a hidden field to every form generated on the server.

That is, the «honest» form for sending messages, created on

http://mail.com

, will look like this:

  

When it's submitted, the server checks the

csrf

field, confirms that the token is correct, and only then sends the message.

The «evil page», no matter how hard it tries, cannot generate a similar form, since it does not have the

secret

, and the token will be incorrect.

Such a token is also called the form's «signature», which confirms that the form was generated specifically on the server.

Signature with form fields

This signature indicates that the author of the form is the server, but it guarantees nothing about its content.

There are situations when we want to be sure that some of the form's fields were not changed by the visitor on their own. Then we can include these fields in the MD5 for the token formula, for example:

token = salt + ":" + MD5(salt + ":" + secret + ":" + fields.money)

When the form is submitted, the server checks the signature, substituting into it the

secret
it knows, and the submitted value
fields.money
. If they don't match, either the
secret
is wrong (a hacker), or
fields.money
has been changed.

Token and AJAX

Now let's move on to AJAX requests.

What if sending messages in our interface is implemented via XMLHttpRequest?

As with the form, we must «sign» the request with a token, to guarantee that its contents were sent to the server specifically by the site's interface, and not by an «evil page».

There are several options here, the simplest is an additional cookie.

  1. During authorization, the server sets a cookie named

    CSRF-TOKEN
    , and writes the token into it.

  2. The code performing the XMLHttpRequest reads the cookie and sets the header

    X-CSRF-TOKEN
    with it:

    var request = new XMLHttpRequest(); var csrfCookie = document.cookie.match(/CSRF-TOKEN=([\w-]+)/); if (csrfCookie) { request.setRequestHeader("X-CSRF-TOKEN", csrfCookie ); }
  3. The server checks whether the header is present and whether it contains the correct token.

This protection works because only JavaScript from the same domain can read the cookie. The «evil page» won't be able to «transfer» the cookie into the header.

If you need to not use XMLHttpRequest but, for example, dynamically generate a form from JavaScript – it is also signed in a similar way, a hidden field or an additional URL parameter is generated from the cookie.

Summary

  • A CSRF attack is when an «evil page» sends a form or request to a site where the visitor is presumably logged in.

    If the site only checks cookies, it will accept such a form. And it should not do this, since the form was generated by an evil hacker.

  • To protect against the attack, the forms that

    mail.com
    generates are signed with a special token. Not all forms need this – only those that perform actions on behalf of the visitor, that is, that could be targeted by the attack.

  • To sign the XMLHttpRequest, the token is additionally written into a cookie. Then JavaScript from the domain

    mail.com
    can read it and add it to the header, and the server can check that the header is present and contains a valid token.

  • Dynamically generated forms are signed in a similar way: the token from the cookie is added as a URL parameter or an additional field.

Comments

To leave a comment

If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Lectures and tutorial on "Running server side scripts using PHP as an example (LAMP)"

Terms: Running server side scripts using PHP as an example (LAMP)