3 ms·
In general, if you have an XSS vulnerability in your app, you can't have proper protection against CSRF, either. Every single line of JS that executes on your p
by kijin 13y ago
In general, if you have an XSS vulnerability in your app, you can't have proper protection against CSRF, either. Every single line of JS that executes on your page should be your own, otherwise it'll be impossible to distinguish CSRF requests from genuine requests. So there's no point worrying about JS on your own page having access to the CSRF token. Likewise, if your pages are unencrypted, you don't have control over anything that appears or executes on your page.
Provided that there are no XSS vulnerabilities (e.g. you use a framework that automatically escapes everything you put in a template) and you use SSL on all your pages, an easy way to do "stateless" CSRF protection is to insert a token into each form that contains encrypted information about the form and the client. For example, create an array containing a unique identifier of the form, the client's IP address, the client's user agent string, and any other piece of information that is available with every request (so that you don't have to remember them). Serialize the array and encrypt it with AES using a key that you keep in the server. When you receive a POST, decrypt the token and check if the information it contains matches the client's details. If it matches, you know that it was you who generated that token. Of course this is vulnerable to replay attacks, but if your app is XSS-proof and your pages are delivered over SSL, it should be very difficult for an attacker to obtain the token in the first place.
But realistically, if you're already using cookies, there's no point insisting on a stateless solution to anything. If your site has a login functionality at all, you're probably already restricting dangerous actions to logged-in users only. In that case, spare a few bytes in your session storage. Generate a random token, put it in your form, and also store it in the session. Remove it from the session after use. Problem solved, and no replay attacks either. Why the obsession with stateless stuff? Maintaining state is easier than ever before. Gone are the days when sessions were incompatible with load balancing. Nowadays you can just throw all your sessions in a Redis node and access them in a fraction of a millisecond from a thousand different servers.
Edit: There are also in-between solutions if you really want to avoid using sessions. For example, you could keep a database of all the tokens you ever generated, from which tokens are deleted when used. This can help you prevent replays while minimizing (but not eliminating) state. If you don't want the database to grow indefinitely, you can just say "all tokens expire after X hours" and periodically purge old entries from your database.
- papsosouid 13y ago>Nowadays you can just throw all your sessions in a Redis node and access them in a fraction of a millisecond from a thousand different servers. You seriously believe that? Adding tons of extra complexity, latency, and potential failure modes to gain absolutely nothing is not a trivial thing.
- kijin 13y agoIf you have enough application servers for session sharing to be a problem, you probably already have enough complexity to worry about. Adding sessions to the mix won't change much. If you don't want to add another daemon to your stack, just reuse whatever you were using before, whether it's Memcached, MongoDB, or plain old MySQL. Gain nothing? Why? Easily preventing CSRF replay attacks count as something, doesn't it?
- josephscott 13y agoYou don't need to have very many application servers for this to become an issue. For instance, what if you host your site in multiple data centers? Each data center might only have a few servers, but any additional data layers that have to be kept in sync between the two is a non-trivial amount of additional complexity.
- papsosouid 13y ago>If you have enough application servers for session sharing to be a problem, you probably already have enough complexity to worry about You definitely have lots of complexity. Which is why adding more is bad. There is no point where things are so complex that making it more complex is cool. > If you don't want to add another daemon to your stack, just reuse whatever you were using before, whether it's Memcached, MongoDB, or plain old MySQL. Sure, just make things slower and more likely to fail for no reason. >Gain nothing? Why? Because you can just store the session in an encrypted cookie. There is no need for it to be on any server at all.
- AnIrishDuck 13y ago> Serialize the array and encrypt it with AES using a key that you keep in the server. When you receive a POST, decrypt the token and check if the information it contains matches the client's details. If it matches, you know that it was you who generated that token. No. You want to use a MAC for this, not encryption. Encryption does not guarantee authenticity, MACs do. It is very possible to predictably alter the contents of encrypted text; many of the early Matasano cryptopals challenges revolve around doing precisely this.