Why can CookieCsrfTokenRepository.withHttpOnlyFalse() in spring security handle CSRF attack? - spring

CookieCsrfTokenRepository.withHttpOnlyFalse() stores the XSRF Token in cookies, and allows front-end to extract cookie contents using JS code. The front-end then appends XSRF Token to http header.
But what if a hacker injects some malicious JS code to read the XSRF Token in the cookie, and add the XSRF Token to http header of the forged http request, and send it? I think backend will think the request is legal. Is not that dangerous?

"If a hacker injects some malicious JS code", that's a cross-site scripting vulnerability. Given most protections against CSRF, an XSS will beat it in the sense that any token can be read and used by the attacker. If there is XSS, there likely also is CSRF, it's just not that big of a deal compared to XSS.
Having said that, there are some mitigations to CSRF that don't actually break in case of XSS, one is checking referer / origin headers, the other is SameSite auth (session) cookies. These might bring different problems, but help separate CSRF from XSS impact, which can be a useful consideration in some special cases. However, if you have XSS, the attacker can pretty much do anything a user can do anyway, and they don't usually need CSRF.

Related

Is a CSRF token needed for "AJAX"-only "application/json"-only POSTs?

If I understand correctly, there's no need for a CSRF token if you're only allowing JSON as application/json from an "AJAX" (really AJAJ for JSON) form, right?
If someone tries to post to the form from another page using some nifty POST-to-iFrame hack it will be application/x-www-form-urlencoded, you can throw it out immediately.
If someone tries to post to the form using AJAJ, it will only succeed if OPTIONS has the CORS headers that allow it.
Conclusion: unless you're using CORS you're safe from CSRF as when you're using application/json instead of application/x-www-form-urlencoded.
Any contradictions I'm not considering?
Have a look at this Sec.SE question and answer. In short: you are correct (presently), but it's probably not a good idea to rely on this behavior, so use tokens anyway.
2022 Update
So much has changed - such as fetch giving more control to requests.
Yes, it's still dangerous
It is possible to do a cross-site JSON POST that includes cookies.
(the attacker can't see the response, but they can POST successfully)
CSRF is necessary by default.
Yes, it's easy to mitigate
Same-Site Cookies
There's now a same-site cookie option. Using this correctly makes it completely unnecessary to use CSRF tokens at all.
API Tokens
Completely abandoning Cookies in favor of per-request API tokens, such as the well-standardized JWT, will make CSRF attacks impossible.
This is best done by separating token routes from cookie routes, such as:
/api/account/xxxx for authenticated JSON API
/api/assets/xxxx for <img src="xxxx" /> and other assets that should not have a token in the URL and must therefore rely on cookies

What is the motivation behind the introduction of preflight CORS requests?

Cross-origin resource sharing is a mechanism that allows a web page to make XMLHttpRequests to another domain (from Wikipedia).
I've been fiddling with CORS for the last couple of days and I think I have a pretty good understanding of how everything works.
So my question is not about how CORS / preflight work, it's about the reason behind coming up with preflights as a new request type. I fail to see any reason why server A needs to send a preflight (PR) to server B just to find out if the real request (RR) will be accepted or not - it would certainly be possible for B to accept/reject RR without any prior PR.
After searching quite a bit I found this piece of information at www.w3.org (7.1.5):
To protect resources against cross-origin requests that could not originate from certain user agents before this specification existed a
preflight request is made to ensure that the resource is aware of this
specification.
I find this is the hardest to understand sentence ever. My interpretation (should better call it 'best guess') is that it's about protecting server B against requests from server C that is not aware of the spec.
Can someone please explain a scenario / show a problem that PR + RR solves better than RR alone?
I spent some time being confused as to the purpose of the preflight request but I think I've got it now.
The key insight is that preflight requests are not a security thing. Rather, they're a not-changing-the-rules thing.
Preflight requests have nothing to do with security, and they have no bearing on applications that are being developed now, with an awareness of CORS. Rather, the preflight mechanism benefits servers that were developed without an awareness of CORS, and it functions as a sanity check between the client and the server that they are both CORS-aware. The developers of CORS felt that there were enough servers out there that were relying on the assumption that they would never receive, e.g. a cross-domain DELETE request that they invented the preflight mechanism to allow both sides to opt-in. They felt that the alternative, which would have been to simply enable the cross-domain calls, would have broken too many existing applications.
There are three scenarios here:
Old servers, no longer under development, and developed before CORS. These servers may make assumptions that they'll never receive e.g. a cross-domain DELETE request. This scenario is the primary beneficiary of the preflight mechanism. Yes these services could already be abused by a malicious or non-conforming user agent (and CORS does nothing to change this), but in a world with CORS the preflight mechanism provides an extra 'sanity check' so that clients and servers don't break because the underlying rules of the web have changed.
Servers that are still under development, but which contain a lot of old code and for which it's not feasible/desirable to audit all the old code to make sure it works properly in a cross-domain world. This scenario allows servers to progressively opt-in to CORS, e.g. by saying "Now I'll allow this particular header", "Now I'll allow this particular HTTP verb", "Now I'll allow cookies/auth information to be sent", etc. This scenario benefits from the preflight mechanism.
New servers that are written with an awareness of CORS. According to standard security practices, the server has to protect its resources in the face of any incoming request -- servers can't trust clients to not do malicious things. This scenario doesn't benefit from the preflight mechanism: the preflight mechanism brings no additional security to a server that has properly protected its resources.
What was the motivation behind introducing preflight requests?
Preflight requests were introduced so that a browser could be sure it was dealing with a CORS-aware server before sending certain requests. Those requests were defined to be those that were both potentially dangerous (state-changing) and new (not possible before CORS due to the Same Origin Policy). Using preflight requests means that servers must opt-in (by responding properly to the preflight) to the new, potentially dangerous types of request that CORS makes possible.
That's the meaning of this part of the original specification: "To protect resources against cross-origin requests that could not originate from certain user agents before this specification existed a preflight request is made to ensure that the resource is aware of this specification."
Can you give me an example?
Let's imagine that a browser user is logged into their banking site at A.com. When they navigate to the malicious B.com, that page includes some Javascript that tries to send a DELETE request to A.com/account. Since the user is logged into A.com, that request, if sent, would include cookies that identify the user.
Before CORS, the browser's Same Origin Policy would have blocked it from sending this request. But since the purpose of CORS is to make just this kind of cross-origin communication possible, that's no longer appropriate.
The browser could simply send the DELETE and let the server decide how to handle it. But what if A.com isn't aware of the CORS protocol? It might go ahead and execute the dangerous DELETE. It might have assumed that—due to the browser's Same Origin Policy—it could never receive such a request, and thus it might have never been hardened against such an attack.
To protect such non-CORS-aware servers, then, the protocol requires the browser to first send a preflight request. This new kind of request is something that only CORS-aware servers can respond to properly, allowing the browser to know whether or not it's safe to send the actual DELETE.
Why all this fuss about the browser, can't the attacker just send a DELETE request from their own computer?
Sure, but such a request won't include the user's cookies. The attack that this is designed to prevent relies on the fact that the browser will send cookies (in particular, authentication information for the user) for the other domain along with the request.
That sounds like Cross-Site Request Forgery, where a form on site B.com can be submitted to A.com with the user's cookies and do damage.
That's right. Another way of putting this is that preflight requests were created so as to not increase the CSRF attack surface for non-CORS-aware servers.
But POST is listed as a method that doesn't require preflights. That can change state and delete data just like a DELETE!
That's true! CORS does not protect your site from CSRF attacks. Then again, without CORS you are also not protected from CSRF attacks. The purpose of preflight requests is just to limit your CSRF exposure to what already existed in the pre-CORS world.
Sigh. OK, I grudgingly accept the need for preflight requests. But why do we have to do it for every resource (URL) on the server? The server either handles CORS or it doesn't.
Are you sure about that? It's not uncommon for multiple servers to handle requests for a single domain. For example, it may be the case that requests to A.com/url1 are handled by one kind of server and requests to A.com/url2 are handled by a different kind of server. It's not generally the case that the server handling a single resource can make security guarantees about all resources on that domain.
Fine. Let's compromise. Let's create a new CORS header that allows the server to state exactly which resources it can speak for, so that additional preflight requests to those URLs can be avoided.
Good idea! In fact, the header Access-Control-Policy-Path was proposed for just this purpose. Ultimately, though, it was left out of the specification, apparently because some servers incorrectly implemented the URI specification in such a way that requests to paths that seemed safe to the browser would not in fact be safe on the broken servers.
Was this a prudent decision that prioritized security over performance, allowing browsers to immediately implement the CORS specification without putting existing servers at risk? Or was it shortsighted to doom the internet to wasted bandwidth and doubled latency just to accommodate bugs in a particular server at a particular time?
Opinions differ.
Well, at the very least browsers will cache the preflight for a single URL?
Yes. Though probably not for very long. In WebKit browsers the maximum preflight cache time is currently 10 minutes.
Sigh. Well, if I know that my servers are CORS-aware, and therefore don't need the protection offered by preflight requests, is there any way for me to avoid them?
Your only real option is to make sure that your requests use CORS-safe methods and headers. That might mean leaving out custom headers that you would otherwise include (like X-Requested-With), changing the Content-Type, or more.
Whatever you do, you must make sure that you have proper CSRF protections in place, since CORS will not block all unsafe requests. As the original specification puts it: "resources for which simple requests have significance other than retrieval must protect themselves from Cross-Site Request Forgery".
Consider the world of cross-domain requests before CORS. You could do a standard form POST, or use a script or an image tag to issue a GET request. You couldn't make any other request type other than GET/POST, and you couldn't issue any custom headers on these requests.
With the advent of CORS, the spec authors were faced with the challenge of introducing a new cross-domain mechanism without breaking the existing semantics of the web. They chose to do this by giving servers a way to opt-in to any new request type. This opt-in is the preflight request.
So GET/POST requests without any custom headers don't need a preflight, since these requests were already possible before CORS. But any request with custom headers, or PUT/DELETE requests, do need a preflight, since these are new to the CORS spec. If the server knows nothing about CORS, it will reply without any CORS-specific headers, and the actual request will not be made.
Without the preflight request, servers could begin seeing unexpected requests from browsers. This could lead to a security issue if the servers weren't prepared for these types of requests. The CORS preflight allows cross-domain requests to be introduced to the web in a safe manner.
CORS allows you to specify more headers and method types than was previously possible with cross-origin <img src> or <form action>.
Some servers could have been (poorly) protected with the assumption that a browser cannot make, e.g. cross-origin DELETE request or cross-origin request with X-Requested-With header, so such requests are "trusted".
To make sure that server really-really supports CORS and not just happens to respond to random requests, the preflight is executed.
I feel that the other answers aren't focusing on the reason pre-fight enhances security.
Scenarios:
1) With pre-flight. An attacker forges a request from site dummy-forums.com while the user is authenticated to safe-bank.com
If the Server does not check for the origin, and somehow has a flaw, the browser will issue a pre-flight request, OPTION method. The server knows none of that CORS that the browser is expecting as a response so the browser will not proceed (no harm whatsoever)
2) Without pre-flight. An attacker forges the request under the same scenario as above, the browser will issue the POST or PUT request right away, the server accepts it and might process it, this will potentially cause some harm.
If the attacker sends a request directly, cross origin, from some random host it's most likely one is thinking about a request with no authentication. That's a forged request, but not a xsrf one. so the server has will check credentials and fail.
CORS doesn't attempt to prevent an attacker who has the credentials to issue requests, although a whitelist could help reduce this vector of attack.
The pre-flight mechanism adds safety and consistency between clients and servers.
I don't know if this is worth the extra handshake for every request since caching is hardy use-able there, but that's how it works.
Here's another way of looking at it, using code:
<!-- hypothetical exploit on evil.com -->
<!-- Targeting banking-website.example.com, which authenticates with a cookie -->
<script>
jQuery.ajax({
method: "POST",
url: "https://banking-website.example.com",
data: JSON.stringify({
sendMoneyTo: "Dr Evil",
amount: 1000000
}),
contentType: "application/json",
dataType: "json"
});
</script>
Pre-CORS, the exploit attempt above would fail because it violates the same-origin policy. An API designed this way did not need XSRF protection, because it was protected by the browser's native security model. It was impossible for a pre-CORS browser to generate a cross-origin JSON POST.
Now CORS comes on the scene – if opting-in to CORS via pre-flight was not required, suddenly this site would have a huge vulnerability, through no fault of their own.
To explain why some requests are allowed to skip the pre-flight, this is answered by the spec:
A simple cross-origin request has been defined as congruent with those
which may be generated by currently deployed user agents that do not
conform to this specification.
To untangle that, GET is not pre-flighted because it is a "simple method" as defined by 7.1.5. (The headers must also be "simple" in order to avoid the pre-flight).
The justification for this is that "simple" cross-origin GET request could already be performed by e.g. <script src=""> (this is how JSONP works). Since any element with a src attribute can trigger a cross-origin GET, with no pre-flight, there would be no security benefit to requiring pre-fight on "simple" XHRs.
Additionally, for HTTP request methods that can cause side-effects on
user data (in particular, for HTTP methods other than GET, or for POST
usage with certain MIME types), the specification mandates that
browsers "preflight" the request
Source
In a browser supporting CORS, reading requests (like GET) are already protected by the same-origin policy: A malicious website trying to make an authenticated cross-domain request (for example to the victim's internet banking website or router's configuration interface) will not be able to read the returned data because the bank or the router doesn't set the Access-Control-Allow-Origin header.
However, with writing requests (like POST) the damage is done when the request arrives at the webserver.* A webserver could check the Origin header to determine if the request is legit, but this check is often not implemented because either the webserver has no need for CORS or the webserver is older than CORS and is therefore assuming that cross-domain POSTs are completely forbidden by the same-origin policy.
That is why webservers are given the chance to opt-in into receiving cross-domain write requests.
* Essentially the AJAX version of CSRF.
Aren't the preflighted requests about Performance? With the preflighted requests a client can quickly know if the operation is allowed before send a large amount of data, e.g., in JSON with PUT method. Or before travel sensitive data in authentication headers over the wire.
The fact of PUT, DELETE, and other methods, besides custom headers, aren't allowed by default(They need explicit permission with "Access-Control-Request-Methods" and "Access-Control-Request-Headers"), that sounds just like a double-check, because these operations could have more implications to the user data, instead GET requests.
So, it sounds like:
"I saw that you allow cross-site requests from http://foo.example, BUT are you SURE that you'll allow DELETE requests? Did you consider the impacts that these requests might cause in the user data?"
I didn't understand the cited correlation between the preflighted requests and the old servers benefits. A Web Service that was implemented before CORS, or without a CORS awareness, will never receive ANY cross-site request, because first their response won't have the "Access-Control-Allow-Origin" header.

Same origin Policy and CORS (Cross-origin resource sharing)

I was trying to understand CORS. As per my understanding, it is a security mechanism implemented in browsers to avoid any AJAX request to domain other than the one open by the user (specified in the URL).
Now, due to this limitation many CORS was implemented to enable websites to do cross origin request. but as per my understanding implementing CORS defy the security purpose of the "Same Origin Policy" (SOP).
CORS is just to provide extra control over which request server wants to serve. Maybe it can avoid spammers.
From Wikipedia:
To initiate a cross-origin request, a browser sends the request with
an Origin HTTP header. The value of this header is the site that
served the page. For example, suppose a page on
http://www.social-network.example attempts to access a user's data
in online-personal-calendar.example. If the user's browser implements
CORS, the following request header would be sent:
Origin: http://www.social-network.example
If online-personal-calendar.example allows the request, it sends an
Access-Control-Allow-Origin header in its response. The value of the
header indicates what origin sites are allowed. For example, a
response to the previous request would contain the following:
Access-Control-Allow-Origin: http://www.social-network.example
If the server does not allow the cross-origin request, the browser
will deliver an error to social-network.example page instead of
the online-personal-calendar.example response.
To allow access to all pages, a server can send the following response
header:
Access-Control-Allow-Origin: *
However, this might not be appropriate for situations in which
security is a concern.
What am I missing here? what is the the intend of CORS to secure the server vs secure the client.
Same-origin policy
What is it?
The same-origin policy is a security measure standardized among browsers. The "origin" mostly refers to a "domain". It prevents different origins from interacting with each other, to prevent attacks such as Cross Site Request Forgery.
How does a CSRF attack work?
Browsers allow websites to store information on a client's computer, in the form of cookies. These cookies have some information attached to them, like the name of the cookie, when it was created, when it will expire, who set the cookie etc. A cookie looks something like this:
Cookie: cookiename=chocolate; Domain=.bakery.example; Path=/ [// ;otherDdata]
So this is a chocolate cookie, which should be accessible from http://bakery.example and all of its subdomains.
This cookie might contain some sensitive data. In this case, that data is... chocolate. Highly sensitive, as you can see.
So the browser stores this cookie. And whenever the user makes a request to a domain on which this cookie is accessible, the cookie would be sent to the server for that domain. Happy server.
This is a good thing. Super cool way for the server to store and retrieve information on and from the client-side.
But the problem is that this allows http://malicious-site.example to send those cookies to http://bakery.example, without the user knowing! For example, consider the following scenario:
# malicious-site.example/attackpage
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://bakery.example/order/new?deliveryAddress="address of malicious user"');
xhr.send();
If you visit the malicious site, and the above code executes, and same-origin policy was not there, the malicious user would place an order on behalf of you, and get the order at his place... and you might not like this.
This happened because your browser sent your chocolate cookie to http://bakery.example, which made http://bakery.example think that you are making the request for the new order, knowingly. But you aren't.
This is, in plain words, a CSRF attack. A forged request was made across sites. "Cross Site Request Forgery". And it would not work, thanks to the same-origin policy.
How does Same-origin policy solve this?
It stops the malicious-site.example from making requests to other domains. Simple.
In other words, the browser would not allow any site to make a request to any other site. It would prevent different origins from interacting with each other through such requests, like AJAX.
However, resource loading from other hosts like images, scripts, stylesheets, iframes, form submissions etc. are not subject to this limitation. We need another wall to protect our bakery from malicious site, by using CSRF Tokens.
CSRF Tokens
As stated, malicious site can still do something like this without violating the same-origin policy:
<img src='http://bakery.example/order/new?deliveryAddress="address of malicious user"'/>
And the browser will try to load an image from that URL, resulting in a GET request to that URL sending all the cookies. To stop this from happening, we need some server side protection.
Basically, we attach a random, unique token of suitable entropy to the user's session, store it on the server, and also send it to the client with the form. When the form is submitted, client sends that token along with the request, and server verifies if that token is valid or not.
Now that we have done this, and malicious website sends the request again, it will always fail since there is no feasible way for the malicious website to know the token for user's session.
CORS
When required, the policy can be circumvented, when cross site requests are required. This is known as CORS. Cross Origin Resource Sharing.
This works by having the "domains" tell the browser to chill, and allow such requests. This "telling" thing can be done by passing a header. Something like:
Access-Control-Allow-Origin: //comma separated allowed origins list, or just *
So if http://bakery.example passes this header to the browser, and the page creating the request to http://bakery.example is present in the origin list, then the browser will let the request go, along with the cookies.
There are rules according to which the origin is defined1. For example, different ports for the same domain are not the same origin. So the browser might decline this request if the ports are different. As always, our dear Internet Explorer is the exception to this. IE treats all ports the same way. This is non-standard and no other browser behaves this way. Do not rely on this.
JSONP
JSON with Padding is just a way to circumvent same-origin policy, when CORS is not an option. This is risky and a bad practice. Avoid using this.
What this technique involves is making a request to the other server like following:
<script src="http://badbakery.example/jsonpurl?callback=cake"></script>
Since same-origin policy does not prevent this2 request, the response of this request will be loaded into the page.
This URL would most probably respond with JSON content. But just including that JSON content on the page is not gonna help. It would result in an error, ofcourse. So http://badbakery.example accepts a callback parameter, and modifies the JSON data, sending it wrapped in whatever is passed to the callback parameter.
So instead of returning,
{ user: "vuln", acc: "B4D455" }
which is invalid JavaScript throwing an error, it would return,
cake({user: "vuln", acc:"B4D455"});
which is valid JavaScript, it would get executed, and probably get stored somewhere according to the cake function, so that the rest of the JavaScript on the page can use the data.
This is mostly used by APIs to send data to other domains. Again, this is a bad practice, can be risky, and should be strictly avoided.
Why is JSONP bad?
First of all, it is very much limited. You can't handle any errors if the request fails (at-least not in a sane way). You can't retry the request, etc.
It also requires you to have a cake function in the global scope which is not very good. May the cooks save you if you need to execute multiple JSONP requests with different callbacks. This is solved by temporary functions by various libraries but is still a hackish way of doing something hackish.
Finally, you are inserting random JavaScript code in the DOM. If you aren't 100% sure that the remote service will return safe cakes, you can't rely on this.
References
1. https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Definition_of_an_origin
2. https://www.w3.org/Security/wiki/Same_Origin_Policy#Details
Other worthy reads
http://scarybeastsecurity.blogspot.dk/2009/12/generic-cross-browser-cross-domain.html
https://www.rfc-editor.org/rfc/rfc3986 (sorry :p)
https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
The Same Origin Policy (SOP) is the policy browsers implement to prevent vulnerabilities via Cross Site Scripting (XSS). This is mainly for protecting the server, as there are many occasions when a server can be dealing with authentication, cookies, sessions, etc.
The Cross Origin Resource Sharing (CORS) is one of the few techniques for relaxing the SOP. Because SOP is "on" by default, setting CORS at the server-side will allow a request to be sent to the server via an XMLHttpRequest even if the request was sent from a different domain. This becomes useful if your server was intended to serve requests from other domains (e.g. if you are providing an API).
I hope this clears up the distinction between SOP and CORS and the purposes of each.

Preventing session fixation in ruby sinatra

Most of the session fixation topics in ruby are mostly related to rails. Are there any session fixation vulnerabilities in sinatra? In rails we are mostly recommended to do reset_session before assigning sessions. How can we prevent session fixation in sinatra?
Sinatra by default uses the Rack::Protection gem which protects against a lot of common vulnerabilities. You might be particularly interested in its session hijacking protection. These are some of the things the Rack::Protection gem protects against:
Cross Site Request Forgery
Authenticity token: Only accepts unsafe HTTP requests if a given access token matches the token included in the session. Form token: Only accepts submitted forms if a given access token matches the token included in the session. Does not expect such a token from Ajax request. Remote token: Only accepts unsafe HTTP requests if a given access token matches the token included in the session or the request comes from the same origin. JSON CSRF: JSON GET APIs are vulnerable to being embedded as JavaScript while the Array prototype has been patched to track data. Checks the referrer even on GET requests if the content type is JSON. Remote Referrer: Does not accept unsafe HTTP requests if the Referer [sic] header is set to a different host.
Cross Site Scripting
XSS Header: Sets X-XSS-Protection header to tell the browser to block attacks. Clickjacking. Escaped Params: Automatically escapes Rack::Request#params so they can be embedded in HTML or JavaScript without any further issues. Calls html_safe on the escaped strings if defined, to avoid double-escaping in Rails.
Clickjacking
Frame options: Sets X-Frame-Options header to tell the browser avoid embedding the page in a frame.
Directory Traversal
Unescapes '/' and '.', expands path_info. Thus GET /foo/%2e%2e%2fbar becomes GET /bar.
Session Hijacking
Tracks request properties like the user agent in the session and empties the session if those properties change. This essentially prevents attacks from Firesheep. Since all headers taken into consideration might be spoofed, too, this will not prevent all hijacking attempts.
IP Spoofing
Detect (some) IP spoofing attacks.
As is the case with most security related questions, it's a good idea to have a general knowledge of web security. Unfortunately there are not a lot of good tutorials that address Sinatra security specifically.

Is exposing a session's CSRF-protection token safe?

Django comes with CSRF protection middleware, which generates a unique per-session token for use in forms. It scans all incoming POST requests for the correct token, and rejects the request if the token is missing or invalid.
I'd like to use AJAX for some POST requests, but said requests don't have the CSRF token availabnle. The pages have no <form> elements to hook into and I'd rather not muddy up the markup inserting the token as a hidden value. I figure a good way to do this is to expose a vew like /get-csrf-token/ to return the user's token, relying on browser's cross-site scripting rules to prevent hostile sites from requesting it.
Is this a good idea? Are there better ways to protect against CSRF attacks while still allowing AJAX requests?
UPDATE: The below was true, and should be true if all browsers and plugins were properly implemented. Unfortunately, we now know that they aren't, and that certain combinations of browser plugins and redirects can allow an attacker to provide arbitrary headers on a cross-domain request. Unfortunately, this means that even AJAX requests with the "X-Requested-With: XMLHttpRequest" header must now be CSRF-protected. As a result, Django no longer exempts Ajax requests from CSRF protection.
Original Answer
It's worth mentioning that protecting AJAX requests from CSRF is unnecessary, since browsers do not allow cross-site AJAX requests. In fact, the Django CSRF middleware now automatically exempts AJAX requests from CSRF token scanning.
This is only valid if you are actually checking the X-Requested-With header server-side for the "XMLHttpRequest" value (which Django does), and only exempting real AJAX requests from CSRF scanning.
If you know you're going to need the CSRF token for AJAX requests, you can always embed it in the HTML somewhere; then you can find it through Javascript by traversing the DOM. This way, you'll still have access to the token, but you're not exposing it via an API.
To put it another way: do it through Django's templates -- not through the URL dispatcher. It's much more secure this way.
Cancel that, I was wrong. (See comments.) You can prevent the exploit by ensuring your JSON follows the spec: Always make sure you return an object literal as the top-level object. (I can't guarantee there won't be further exploits. Imagine a browser providing access to the failed code in its window.onerror events!)
You can't rely on cross-site-scripting rules to keep AJAX responses private. For example, if you return the CSRF token as JSON, a malicious site could redefine the String or Array constructor and request the resource.
bigmattyh is correct: You need to embed the token somewhere in the markup. Alternatively, you could reject any POSTs that do have a referer that doesn't match. That way, only people with overzealous software firewalls will be vulnerable to CSRF.

Resources