title: Why not use session ID as XSRF token?
body: <p>Why does <a href="http://www.playframework.org/" rel="noreferrer">Play Framework</a> use [a signed version of the session id] as <a href="http://en.wikipedia.org/wiki/Cross-site_request_forgery" rel="noreferrer">Cross Site Request Forgery</a> (XSRF/CSRF) prevention token, rather than the session ID itself?</p>
  <p>(With XSRF prevention token, I mean a magic value that must be included in a form submission, for the webapp to accept the form.)</p>
  <p>If there's an eavesdropper s/he'll find both the XSRF token and the SID cookie anyway (?).</p>
  <p>If there's an XSS exploit, then the malicious JavaScript code can read both the XSRF token  and the SID cookie (?).</p>
  <p>However:</p>
  <ol>
  <li><p>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?</p>
  </li>
  <li><p>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?</p>
  </li>
  </ol>
  <p><em>Code snippets:</em></p>
  <p>Here Play constructs it's XSRF token (<code>getId</code> returns the session ID):
  (play/framework/src/play/mvc/Scope.java)</p>
  <pre><code>    public String getAuthenticityToken() {
          return Crypto.sign(getId());
      }
  </code></pre>
  <p>Here Play checks that a <code>&lt;form&gt;</code> has a valid XSRF token:
  (play/framework/src/play/mvc/Controller.java)</p>
  <pre><code>protected static void checkAuthenticity() {
      if(Scope.Params.current().get(&quot;authenticityToken&quot;) == null ||
         !Scope.Params.current().get(&quot;authenticityToken&quot;).equals(
                         Scope.Session.current().getAuthenticityToken())) {
          forbidden(&quot;Bad authenticity token&quot;);
      }
  }
  </code></pre>
  <p><strong>Update:</strong></p>
  <hr />
  <p>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.)</p>
  <pre><code>    public String getAuthenticityToken() {
          if (!data.containsKey(AT_KEY)) {
              data.put(AT_KEY, Crypto.sign(UUID.randomUUID().toString()));
          }
          return data.get(AT_KEY);
      }
  </code></pre>
  <p>Well, then why did they do this change?</p>
  <p>I found the commit:<br />
  [#669] Fix again and apply for Flash and Errors as well<br />
  d6e5dc50ea11fa7ef626cbdf01631595cbdda54c</p>
  <p>From issue <a href="http://play.lighthouseapp.com/projects/57987/tickets/669-create-session-only-when-absolute-necessary" rel="noreferrer">#669</a>:<br />
  <em>create session only when absolute necessary</em><br />
  <em>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.</em></p>
  <p>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.</p>