So, I have a form, to make it a little more secure and potentially help prevent CSRF attacks I want to add a random token value in a hidden field that value is also stored server side in my session data.
When should I issue a new token? Per form? Per page load where there is any form? Per session? I can render it invalid as soon as a form is successfully submitted but I'm wondering when to generate one.
I ask as if I issue it per form or per page do I not risk the chance of a duplicate token value overwriting the existing (valid) token if a user opens a separate window but submitting the first form (with the now overwritten value)?
The simplest way to prevent concurrency issues is to generate it only once per login. The chance of an attacker "guessing" your CSRF is about the same chance (or lower) as them stealing your PHPSESSID. You could also regenerate it whenever the user's access level changes, such as after they change their password or something.
If you want to be really thorough, you can generate and store an array of tokens, one for each form on the website. But if they can steal a CSRF token, they might as well have just stolen a session ID and done some real damage.
If you use one Token per session,
then you need a technique to check
duplicate submitted forms (when user
refreshes a page or click back
button).
If use it per form then if user opens
multiple pages then only the last
form will work.
I would prefer using array of
generated tokens per session, and
when a token is submitted it should be
removed. I read that this approach might be a
concern if you have high volume
traffic website.
I am not sure if you read this article before, but I think it is great resource about CSRF security:
http://shiflett.org/articles/cross-site-request-forgeries
Related
I am implementing CSRF token in my website on every post method.
But when i am accessing my webpages in different tabs then token gets change on both pages and token mismatches.
My token is stored in DOM and i am matching token using SESSION.
How to solve this.?
i change the token on every successful request
Yeah this is why we don't invalidate the token on every successful request. That doesn't just break multi-tab browsing, it also means you can't do stuff like hit the back button then submit.
“Invalidate token on every request” is the kind of bogus security recommendation you get from pentest reports where the tester hasn't found much that's really vulnerable. It's a trade-off as always whether you do, but the usability downside almost always outweighs the minimal security benefit.
You only really need to invalidate the CSRF token (along with the session token) on a privilege level change, most notably on login. This mitigates session fixation attacks, by preventing an attacker who knows the session and CSRF tokens prior to login from exploiting those tokens after you've logged in.
You can achieve this easily:
In the server side, store the CSRF tokens in session like this:
$_SESSION['csrf_tokens']['form1'] = //code to generate csrf token
While validating the token on form submit, you can check,
$_SESSION['csrf_tokens']['form1'] === $_POST['csrf_token']
Please post an example code, unless you are using ajax (which I wouldn't recommend for CSRF tokens the code shouldn't change in both tabs if you open a new tab). Also, I disagree with bobince, you are doing the right thing to implement this measure as once you have the logic in place you can easily and effortlessly use it in all your forms. The best way to implement this is to just have each token expire after a certain amount of time.
bobince: CSRF tokes are used to prevent CSRF attacks not session fixation attacks, both are different the former prevents scripts from executing actions on behalf of the user whereas the latter is an attack in which a malicious user impersonates a normal user by guessing or stealing their session id.
Generate two values – one random key (f.e. via uniqid), and a random token.
You generate both every time a form is rendered – and put them both into hidden fields. And you save the token into the session using the random key. Then when the form data is received, you check if the token send is in the session under the key send. (And if so, you delete the entry with this key after processing the form of course.)
Anything else (f.e. expiration time of tokens, binding of tokens to a certain form type out of several) you implement the same as you would before.
is unnecessarily and unsafe like this why you dont create a token based on session with openssl_random_pseudo_bytes() ,which will produce a safe token, and check if is correct or not or you can use also to expire after 2-5 min.also you can check on owasp about tokens on dom,can be easy spoffed !!!
I am learning about how to prevent CSRF using anti-CSRF tokens. Essentially, the idea is to:-
1) generate a token eg Md5 or Sha1 then store this value in a session variable:-
$token = md5(uniqid(rand(), TRUE));
$_SESSION['token'] = $token;
2) All forms include this token value in a POST hidden field
<input type='hidden' name='token' value='$nonce_token' />
Eg what it would look like to user in source code:-
<input type='hidden' name='token' value='9ee66e4e63a06ee4b83a3edde4ecd587' />
3) Once form sent check POST hidden field token value matches token stored in session value
if($_POST['token']==$_SESSION['token']){...ok...}
However, this process seems a little flawed since by including the token value in a hidden POST field an attack can simply just look at the website source code to see the token and then just include this in a malicious generated POST form which my application would thus succeed once received as token value sent would match the token value in my session variable, since I essentially show the token value in my hidden field to the attacker.
Thus, my question is what is the best way around this, as a few ideas I had still seem little flawed:-
1) Using _GET instead but this still has flaws like _POST
2) Changing the token value after x minutes or each request but causes usability issues when going back in browser or fail when user filling in form and token value would become outdated compared to updated session token value as hidden token value would not have updated whilst user filling in a form.
3) Try encrypting hidden POST form token value then decrypting on sending POST but encrypting/decrypting an already hashed value seems complicated especially one way encrypted has values like MD5 etc?
Any ideas would be much appreciated.
What you need to do is make the hidden field the MD5 or SHA1 hash of the session ID with a salt. That way you compare the submitted value with the hash of the session ID plus salt and if they match it is valid. If an attacker can guess the token then they have already stolen the session id and would be pointless to do anymore protecting since login has already been hijacked. It's really as simple as that. Here is some great info per OWASP on how to prevent CSRF https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet
However, this process seems a little flawed since by including the token value in a hidden POST field an attack can simply just look at the website source code
No they can't.
Alice runs a website. Bob visits the website. Mallory is attacking Bob's account.
Bob gets a nonce token when he visits Alice's website.
If Mallory visited the site, Mallory would get a different nonce (because Mallory would have a different session).
If Mallory generated a form with malicious data in it (on her website) and tricked Bob into submitting it, then the nonce Mallory put in the form would not match the nonce in Bob's session and the submission would be rejected.
Let's review the attack scenario:
You have a server at example.com and you use CSRF tokens in your forms.
Each CSRF token is unique, specific to a user and only valid for some time.
A malicious third party, Eve, tricks one of your users, Alice, to come to her site, attempting to mount a CSRF attack.
If Eve simply tricks Alice into submitting a form to your server without CSRF token, your server will reject it.
If Eve also has an account on your server and tries to get any token to submit with the form, this will fail because the token is not valid for Alice.
This leaves this scenario: Using Javascript, Eve fetches a form from your server as Alice, then submits this form back, including a valid token. I.e. Eve completely impersonates Alice for the entire process of a regular form submission using Javascript. This is prevented by the Same Origin Policy. Eve's Javascript won't be able to fetch information from your server, Alice's browser will prevent this as it violates the Same Origin Policy.
That is, assuming there are no security holes in the browser which allow Eve to circumvent that policy. This also means that you need to guard against XSS, i.e. against Eve being able to inject one of her scripts into your website, so regular visitors to your site will run Eve's scripts as part of your site, from the same origin.
As a bit of self-promotion, I've just implemented a signature based CSRF token library, which you may want to look at: Kunststube\CSRFP. I'd also like to solicit peer review and criticism of it, while I'm at it.
At first, you have to keep in mind, that you cannot prevent hackers from attacking your application, only you can make things harder.
The idea is come clearly when you thinking about what is the main goal of CSRF attacks, The CSRF is an attack that tricks the victim into loading a page that contains a malicious request. It is malicious in the sense that it inherits the identity and privileges of the victim to perform an undesired function on the victim's behalf, like change the victim's e-mail address, home address, or password, or purchase something. CSRF attacks generally target functions that cause a state change on the server but can also be used to access sensitive data.
So as above, attackers don't make attack directly to your web page, they need bridge, that's it they need a Victim, so they can use victim identity and privileges to execute actions.
when you said:
However, this process seems a little flawed since by including the token value in a
hidden POST field an attack can simply just look at the website source code
it's doesn't make sense, because attacker will not attack himself.
i hope this was help full.
I am trying to make a like/unlike system, when a user clicks like on a post, his/her user id (which is stored in a session) and the post id will be stored in a database through an ajax call.
Then I thought what if some user make a html form with invisible input field (which has one of his post ids) on another domain and give its link to a user who checked remember me later or is viewing my site.
The user will click the button and The form will POST post id to my site, session contains user id and these will be stored in database.
No good solution comes to my mind. Is there any way more reliable than HTTP referrer to prevent this?
Thanks in advance
One way is to insert a secret variable into the HTML which is specific to a user's session. This can prevent cross site forgery.
In PHP you'd generate a random 'key' and store it in the session:
$_SESSION['myFormVar'] = md5(mt_rand());
Then in a form, you'd add as a hidden variable:
<input type="hidden" name="chkVar" value="<?=$_SESSION['myFormVar']?>"/>
You should submit your form via POST and preferably over HTTPS, making it harder (but not impossible) to intercept the value of chkVar.
In the code that processes your posted form, compare the posted chkVar against your session variable. In an ideal world, you'd have a unique chkVar per request, however using one which is the same for an entire session often works fine and guards against most csrf attacks.
You are talking about CSRF exploit.
This is a good security question.
It's generaly managed with a key that is only known by the server.
This key have to be used in all your forms.
Here is a little tutorial to protect against it
The only thing you should be sending is the post id, the user id should be picked up automatically in the script you are calling through AJAX. Assuming you have validated the user is logged in, you have both pieces of information without any further security risk.
In a attempt to make the current application I'm developing more secure, I've been reading about CSRF tokens and also Nonce.
My question simply is, Are CSRF tokens and Nonce the same thing? from what I could gather so far is that both these methods have different techniques to accomplish the same goal, or am I misunderstanding something?
If they are different, could you be nice enough to provide some example code or point me to some links where i can learn more about how to implementing nonces in PHP apps.
Thanks!
No, they're not the same.
Nonces prevent replay attacks (prevent eavesdropper from storing signed request and re-submitting it later, e.g. if Alice sends "Pay Bob $100", you don't want somebody to re-send that 100 times).
CSRF tokens patch HTML-specific weakness in authentication of users' action, where 3rd party website can submit forms with credentials of user viewing the site (e.g. JavaScript on evil.example.com submitting form to facebook.com using your browser, authenticated as you).
CSRF tokens need to be secret, otherwise attacker would have the missing piece required to forge a request.
Nonces don't have to be secret if they're signed with requester's secret (as long as attacker cannot replace one nonce with another).
You can allow replay of requests with CSRF tokens and still be secured against CSRF (you're interested whether that was intentional action by the user, but may not necessarily want to stop user from performing it many times).
In fact, that's very often useful property, e.g. allows users to use Back button and re-submit forms with corrected values. If you implement CSRF protection with Nonce-like mechanism, you'll get false alarms when users refresh submitted pages.
An easy way to prevent CSRF without Nonces is to put session ID in a hidden from field (not a value stored in the session, but ID of the session itself, the same that you store in the cookie [session_id() in PHP]). When the form is submitted check that form's session ID matches ID in the cookie. That is enough for CSRF, since attacker cannot know value of the cookie (CSRF only allows attackers to blindly send cookies).
Nonce is usually some random string that is added to request just to change in unpredictable way the data, which is used to calculate the signature. So nonce usually is not used by any server-side business logic.
While CSRF-token is stored somewhere on server, passed to the client and need to be returned back to the server to compare. And if matches - then OK.
So in your case the better will be to save csrf token once in a session variable like
$_SESSION['csrf_token'] = bin2hex(random_bytes(16));
and use it unchanged during the session life in all forms you have in your application.
(If you don't have random_bytes(), use random_compat to polyfill it.)
It's sort of the same thing. A "nonce" is just a one-time password itself. It can serve as cryptographic salt, but basically is just a random value. See WP:Nonce
But to sum it up, a nonce is often used as CSRF token. It's an implementation detail. The difference to other use cases is that it later gets asserted.
CSRF having some limitation.
in case if you have requirement where you want to open any page or link in new tab then CSRF won't allow. existing token will allow to open page in new tab for 5 times only.
when you will try to open 6th time it will create the new token which will not match with "server side = client side token". earlier token will expire and new token(NONCE) will create, in that case you will get 404 or 405 error.
when building apps I use a token to prevent attacks on the forms
each time a form is rendered it gets a new ONE TIME security token that i include in the form as a hidden field. this token is also stored in the session.
when the form is sent, the token is verified against the token in the session to make sure the form is legit. This works great for standard pages.
PROBLEM
when using Ajax to send forms, there may be multiple on a page, once you send one of these forms, the token is then invalid for the others as its a one time token.
does anyone have advise for this? or is it secure enough to generate one token per session and just use that instead of invalidating the token each time a form is sent?
If you want to follow your current approach, you can generate a security token each time you do a an AJAX request, return it in the AJAX response, and inject it into the hidden when you get it.
However, I'd go rethinking your current approach for security tokens. Here you have some tips about that in the OSWAP wiki.