Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why not use session ID as XSRF token?

Why does Play Framework use [a signed version of the session id] as Cross Site Request Forgery (XSRF/CSRF) prevention token, rather than the session ID itself?

(With XSRF prevention token, I mean a magic value that must be included in a form submission, for the webapp to accept the form.)

If there's an eavesdropper s/he'll find both the XSRF token and the SID cookie anyway (?).

If there's an XSS exploit, then the malicious JavaScript code can read both the XSRF token and the SID cookie (?).

However:

  1. An attacker cannot construct a valid XSRF token, given a SID, since s/he doesn't have the secret key used when signing the SID to obtain the XSRF token. -- But how could it happen that an attacker gets hold of only the SID, not the XSRF token? Is that far-fetched?

  2. If the SID is sent in a HTTP Only cookie, then an attacker wouldn't have the SID even if s/he found the XSRF token, and perhaps the attacker really needs the SID? -- Is this far-fetched?

Code snippets:

Here Play constructs it's XSRF token (getId returns the session ID): (play/framework/src/play/mvc/Scope.java)

    public String getAuthenticityToken() {
        return Crypto.sign(getId());
    }

Here Play checks that a <form> has a valid XSRF token: (play/framework/src/play/mvc/Controller.java)

protected static void checkAuthenticity() {
    if(Scope.Params.current().get("authenticityToken") == null ||
       !Scope.Params.current().get("authenticityToken").equals(
                       Scope.Session.current().getAuthenticityToken())) {
        forbidden("Bad authenticity token");
    }
}

Update:


Play has changed the way it generates XSRF tokens, now the SID is no longer used, instead a random value is signed and used! (I just updated my Play Framework Git repo clone from old Play version 1.1 to new 1.2. Perhaps I should have done this ... yesterday, hmm.)

    public String getAuthenticityToken() {
        if (!data.containsKey(AT_KEY)) {
            data.put(AT_KEY, Crypto.sign(UUID.randomUUID().toString()));
        }
        return data.get(AT_KEY);
    }

Well, then why did they do this change?

I found the commit:
[#669] Fix again and apply for Flash and Errors as well
d6e5dc50ea11fa7ef626cbdf01631595cbdda54c

From issue #669:
create session only when absolute necessary
A session cookie is created on every request of a resource. play should only create a session cookie if there is really data to be stored in the session.

So they're using a random value, not the SID, because the SID might not yet have been created. Well that's a reason not to use a derivative of the SID as XSRF token. But doesn't clarify why they signed/hashed the SID, in the past, when they were using it.

like image 944
KajMagnus Avatar asked Aug 06 '11 16:08

KajMagnus


People also ask

What is anti XSRF token?

Anti-CSRF token as a pair of Cryptographically related tokens given to a user to validate his requests. As an example, when a user issues a request to the webserver for asking a page with a form, the server calculates two Cryptographically related tokens and send to the user with the response.

Is CSRF session based?

In fact, the CSRF vulnerability relies on the authenticated session management. Typically, session management in a web application is based on cookies. With each request to the server, the browser sends the related cookie that identifies the current user's session.

What does XSRF header mean?

Cross-site request forgery (also known as XSRF or CSRF) is an attack against web-hosted apps whereby a malicious web app can influence the interaction between a client browser and a web app that trusts that browser.

Is CSRF token necessary for JWT?

If you put your JWTs in a header, you don't need to worry about CSRF. You do need to worry about XSS, however. If someone can abuse XSS to steal your JWT, this person is able to impersonate you.


3 Answers

The first thing to say is that you can reuse the session ID as the CSRF token, insofar as it will protect you fine against CSRF and does not automatically create any serious security holes. However, for somewhat sound reasons, OWASP used to explicitly recommend against it. (They now don't address the question at all.)

The argument against reusing the session ID as the CSRF token can be summarized as follows (key points in bold, with justification beneath):

  1. The session ID being acquired by an attacker is generally a more serious security breach than the CSRF token being acquired by an attacker.

    All that an attacker gains from having the CSRF token (assuming that some other secure piece of information, like the session ID, hasn't been reused as the CSRF token) is the ability to perform CSRF attacks. This gives them two huge limitations that they wouldn't have if they actually acquired a session ID:

    • They still need to lure the user with the corresponding session token to an attack page (or have them read an attack email, or view an attack ad in an iframe, etc.) to exploit the CSRF token in any way at all. With the session ID, they'd just need to put it in their browser and then use the website as if they were that user.
    • While they can send requests using the user's credentials, the Same Origin Policy still prevents them from viewing the responses to those requests. This may (or may not, depending on the structure of the API you're protecting and the attacker's ingenuity) mean in practice that while the attacker can perform actions on the user's behalf, they cannot acquire sensitive information that the user is authorized to view. (Which of these you care more about depends upon the context - one assumes that an attacker would tend to prefer taking the contents of your bank account to merely knowing how much that is, but that they'd also rather know your medical history than vandalise it.)

  2. The CSRF token is potentially easier for an attacker to acquire than the session ID

    • XSS attacks are likely to permit an attacker to acquire the CSRF token, since it's common practice to bake it into the DOM (e.g. as the value of an <input> element in a <form>. Session cookies, on the other hand, can be kept secret even in the face of a successful XSS attack using the HttpOnly flag, demanding more up-front work from an attacker to usefully exploit an XSS vulnerability.
    • If the CSRF token is being sent back to the server as a request parameter rather than a custom HTTP header (guaranteed to be the case when including it in ordinary HTML <form> submits), then web server access logs will generally log the CSRF token on GET requests (as it's part of the URL). Thus an attacker who manages to view the access log would be able to acquire many CSRF tokens.
    • Pages or scripts that the CSRF token is baked into may be cached in the user's browser, permitting an attacker to retrieve them from the cache (conceivably relevant after the user has, for example, used a public machine in a library or internet cafe, and then either cleared their cookies but not their cache, or used a 'Log Out' button that removes their session cookie from the browser without invalidating it server-side).

  3. But if you're reusing the session ID as the CSRF token, then any attack that permits them to acquire the CSRF token automatically gives them the session ID as well.

  4. Therefore you should not reuse the CSRF token as the session ID, since it makes the session ID more vulnerable.

To be honest, I kind of regard everything above as more of a theoretical concern than a practical one. The weak point in the argument is point 2; the only realistic vulnerabilities I can think of that could be used for acquiring CSRF tokens but not for acquiring session cookies are still really serious vulnerabilities. If you have an XSS hole on your site, or an attacker has access to your freaking server logs, chances are you're totally fucked anyway. And in most libraries and internet cafes I've been to, the staff were not security-savvy and it'd be pretty easy to install a keylogger undetected and just harvest passwords - there'd be no need for an attacker to go to the effort of waiting for people to use the machine and then ripping the contents of their browser cache.

However, unless your circumstances somehow make it difficult to store an additional random token for CSRF alongside the random session ID, why not just do it anyway for whatever modest security benefit it gives you?

like image 191
Mark Amery Avatar answered Oct 22 '22 15:10

Mark Amery


A pure CSRF attack doesn't have access to the browser's cookies so when you say "eavesdropper", that's only going to be achievable if they're sniffing packets (i.e. no SSL, public wifi).

Depending on the configuration of the Play Framework (I'm not familiar with it so take this as general web app advice), the session and authentication cookies will almost certainly be flagged as HttpOnly so they they're unable to be read from the client via XSS.

Ultimately, the idea of using the synchroniser token pattern to protect against XSRF is to use a unique value (preferably cryptographically strong), known only to the server and the client and unique to that session. Based on this goal, Play Framework seems to do just fine.

like image 28
Troy Hunt Avatar answered Oct 22 '22 17:10

Troy Hunt


Perhaps Play Framework doesn't want the SID in the HTML. An end user, Bob, might download a Web page, and if there's a <form> in that Web page, the SID would be included in the downloaded HTML (if the SID itself is used as XSRF token). If Bob then emails his downloaded page to Mallory, then Mallory would find the SID and could impersonate Bob!?

(Another minor reason not to use the SID: As I mentioned in my update, the SID might simply not be available. Perhaps it's generated as late as possible, to save CPU resources.)

like image 29
KajMagnus Avatar answered Oct 22 '22 17:10

KajMagnus