Take the 2-minute tour ×
Information Security Stack Exchange is a question and answer site for Information security professionals. It's 100% free, no registration required.

Consider the following scenario:

1. When user visits a webapp, server:
    a) initialize the session;
    b) generates CSRF token;
    c) saves token to session;
    d) saves token to client's cookie via Set-Cookie header.
2. On each POST request server compares cookie token (which comes automatically with Cookie header) with session token, and if not equal - return 403.
3. On each request (POST, GET - no matter) server regenerates the token and saves it to session and cookie.

By doing this way we:

1) perform rapidly expiring token, which makes harder for attacker to exploit the webapp;
2) ensure that browser tabbing and clicking "back" button will not break the session. This is because every time the server regenerates the token it reflects in client's cookie.

My questions is: can I use this approach in production webapp, or it has vulnerabilities?

Thank you.

share|improve this question
    
You need the token to be sent in the request outside of the cookie mechanism (e.g. POST data). If sessions are managed via a session ID contained within a cookie, your approach doesn't prevent CSRF. –  SilverlightFox Feb 10 at 10:28
    
@SilverlightFox Thank you for your comment. But I cannot understand why it doesn't prevent CSRF. Can you explain it in details please? –  Curious Feb 10 at 10:46

1 Answer 1

up vote 2 down vote accepted

You need the token to be sent in the request outside of the cookie mechanism (e.g. POST data). If sessions are managed via a session ID contained within a cookie, your approach doesn't prevent CSRF.

In your current implementation:

  1. save token to session;
  2. save token to client's cookie via Set-Cookie header.

This will have the effect of the token being saved in two locations, but both locations will be identified by cookie values.

e.g. if the token is "12345678" it will be saved in session (pseudocode):

Session["SessionCSRFToken"] = "12345678";

and in cookies

Cookies.Add("CSRFToken", "12345678");

However, in order to save the value in session, the web application framework will create a cookie to identify the session, so you will get two cookies set:

Set-Cookie: CSRFToken=12345678;
Set-Cookie: SessionID=987654321;

If a user is logged into your website at www.foo.com and then the user visits www.evil.com, there could be a hidden form tag embedded into the page of www.evil.com (possibly within a hidden IFrame) which is automatically submitted by JavaScript:

<form method="post" action="https://www.foo.com/Account/DeleteAccount">
</form>

When the browser automatically submits the form, both cookies will be sent with the request (CSRFToken=12345678, SessionID=987654321) and your cookie token (CSRFToken) and session token (SessionCSRFToken) will match and the effect will be that the user's account is closed on your system without their knowledge.

To prevent this, you need to store a CSRF token in the page itself (e.g. within a hidden input). This way your form could only be submitted as follows:

<form method="post" action="/Account/DeleteAccount">
    <input type="hidden" name="CSRFToken" value="12345678" />
</form>

Now www.evil.com has no way of including the hidden input within their own HTML as they have no way of knowing the value of the CSRFToken. The value of CSRFToken can be the same as the cookie (the session value is now no longer needed), but it only needs to be generated once pre user session (there is no need to constantly regenerate the value).

For each POST you simply need to make sure that Request.Form["CSRFToken"] == Request.Cookies("CSRFToken").

share|improve this answer
    
Thank you for such detailed answer. Now I understand why it doesn't prevent CSRF. I did not think about all possible variants. –  Curious Feb 10 at 12:41

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.