Subject: [http-auth] CSRF Prevention

From: Tim <[email-masked]>
Date: Fri, 24 Jun 2011 15:13:15 -0700

Hi all.  I wanted to float this one by you all, as we may find it
useful to help squash CSRF along with phishing attacks.

I'm sure many of you are familiar with CSRF attacks, so I'm not going
to give too much background.  I'm also sure these have been discussed
on numerous IETF security lists in the past, but let me just quickly
frame them in the context of how I think of them:

To me, CSRF attacks are symptom of a design flaw in the web, or
perhaps more accurately, a symptom of the fact that we currently use
the web in ways it wasn't designed.  CSRF is possible because:

A. There is no inherent (or strict) distinction between HTTP requests
   initiated by content on the same site vs those initiated by content
   on other sites. 

In addition, CSRF is often made easier because:

B. In practice, there is no distinction between requests that make a
   material change to site content vs those that just retrieve content.
   (Often GET and POST requests are treated identically by
   applications, bluring any meaning we might apply to one or the other
   in this way.)

Because of (B) browsers have no hope in directly preventing CSRF
because they can't tell what request types should be allowed cross
domain (such as fetching images) and which should not be (such as
POSTing forms).

An attempt for fixing (A) is simply to have your web application check
the Referer header that comes with a request and make sure it matches
a trusted domain.  However, Referer headers do give some people the
privacy heebee jeebees and therefore they get turned off at times,
which would cause apps that implement this to break.  Also, old
versions of Adobe Flash allowed one to send arbitrary HTTP headers
cross-domain, so in the early days, this mitigation was thrown out
(though in modern times, it may actually be a reasonable solution).

Because of this history, web applications and frameworks have been
forced to implement cryptographic cookie protocols of their own to
validate that requests really did originate from their sites.  They
embed unpredictable tokens in forms and in URLs and then check those
against server-side data in one of several ways.  Having web
developers and framework developers do crypto has not turned out well
in the past, and I presume it will continue to go poorly.

One simple fix (from a technical perspective, not a standards
perspective), would be to introduce a new HTTP request method (let us
call it "ACTION" for the moment), which behaves more or less like
POST, but is explicitly required never to be used cross-domain.  Then
application implementors could just use ACTION in their forms and
browsers could enforce protections against CSRF instead of making
application developers do it upon receiving the request.  In some of
my past reading of proposals on how PUT is supposed to behave, I did
read something about it having similar restrictions, so perhaps it
could be used for this purpose.

Failing that, as a final possibility (and the reason I am posting this
here) is that we could rely on a better HTTP authentication mechanism
to help us enforce CSRF protections.  Since Referer logic is already
baked in to browsers, and any HTTP authentication mechanism would also
need to be baked in to browsers, why not bake something like Referer
into the HTTP authentication mechansim to help application developers
validate the origin of requests?  Essentially, make Referer
information more reliable and more privacy sensitive.

The most obvious approach would be to require an origin domain
parameter in the HTTP authentication mechanism, have it signed, and
then let application developers check that upon receipt.  

However, this has potential privacy problems, just like Referer does.
So, to help protect privacy, one could instead include a simple salted
hash of the origin domain.  Application developers (or more likely,
development frameworks) can still check a white list of trusted
domains against the hash, or even check for black listed domains if
they really wanted to, but it wouldn't immediately reveal what domain
was the origin.  Referer can continue to be used for non-security
(advertisement tracking, whatever) purposes.

I know this idea is half-baked, but I thought I would try to start a
discussion.  Thoughts?

tim