CSRF tokens vs Nonce confusion - are they the same? - php

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.

Related

Secure CSRF protection without sessions or database?

i'm trying to implement secure CSRF protection to HTML login form,
i know the best way to implement CSRF protection is storing random csrf_key in a session,
but i want to add CSRF to my login & register forms... and i do not want to store many sessions for any anonymous unregistered users...
so i want to create the best secure posibble without using sessions or database, with only form hidden field /& a cookie, and after the login i will use sessions csrf protection.
my idea of secured user_storage only csrf:
csrf_token= AES(ip+useragent+timestamp+random_data, csrf_aes_site_key)
when csrf_aes_site_key is hard-coded in config file.
and after every login/register i will decrypt the AES string + velidate that the ip&ua is matching the request ip&ua, and timestamp is not too match ahead, let say 5 min (if csrf_timestamp + 18000>=current_ts), and random_data is just randomness (and make sure that the same user will not get the same csrf_token if requested multiple times in the same ts)...
so ... is it secure enough, is it good solution?
if not, any other suggestions to solve this dilemma?
thank!
EDIT:
the implementation i just created, and it's working fine, but is it good enough?
full example:
https://github.com/itaiarbel/aes_based_csrf_protection
issue 1:
user may take the csrf_token and submit to the form successfuly using the same token for the next 5min
bug? what do i care if the user submit many times? as long as it not csrf attack...
issue 2:
if the page is left open for 5min, the user will faild login,
(refrash login page automaticaly every 5 min? maby change it to 1h?)
can you spot any specific security risk with this implementation? or can i assume this is a secure way of doing CSRF protection?
The method with storing the CSRF token in cookie is quite widely used (AngularJS, Django) but it works a bit differently. The server sends the token in cookie, the client uses JavaScript to read the cookie and reflect the token in a HTTP header. The server should only verify the value from the HTTP header, even though the cookie will be sent automatically as well.
The actual cookie and header names are not important as soon as both JavaScript frontend and backend are aware of them.
This prevents CSRF because only JavaScript running from the authentic origin will be able to read the cookie (see detailed discussion on Wikipedia). The token can be a HMAC of the session cookie, which avoids the need to remember token state on the server side.
The main advantage is that this approach (unlike the one with token in form fields) works with single-page, JavaScript based applications where you don't generate the HTML on the server and can't really embed the CSRF token in their code.
It will work for most clients - but will fail horribly where the client is accessing your site via load balanced proxies (the client IP you see with change). A more correct solution would use the organization data from the whois record or the ASN number, but there's an expense in looking these up - depending on the volume of traffic simply using the forst 16 bits of the (IPV4) address is probably sufficient.
You may also run into problems depending on how much of the user agent you store (Google Chrome can update itself on the fly).
Looks highly insecure to me. Do not use this. Login forms and registration forms need full CSRF protection; using any kind of reduced protection is not acceptable.
Your setup seems easily attackable by anyone behind the same NAT (and thus sharing the IP address), which is very common in people's homes and even many workplaces. Here's an example scenario:
Malicious coworker (MC) registers a new account on the website
MC figures out victim's user-agent, which is quite easy to do
MC fetches a CSRF token from the website while sending the victim's user-agent
MC crafts a malicious website, containing:
A hidden login form that auto-submits on load
The CSRF token from above
A funny cat meme
MC sends link to victim saying "lol, look at this"
Victim enjoys the meme, but is now logged into the website without their knowledge
MC convinces victim to start using the website, generating data or metadata on the logged in account
MC can view all this data, since they have access to the same account
Steps 3 to 6 can easily happen within 5 minutes.

is putting token in URL secure to prevent CSRF attacks in PHP applications?

I want to use a token to prevent CSRF attacks on my website (written with PHP). I've used it in forms and it works well. But logout link is not a form; It is only a hyperlink.
Is it secure if I put the token in the query string like this:
Logout
If it has any problem, what is your suggestions and solutions ?
Yes, if the CSRF token is 'unguessable' and validated: the approach is the same in both cases.
From Wikipedia's Cross-site Request Forgery - Prevention:
Web sites have various CSRF countermeasures available .. Requiring a secret, user-specific token in all form submissions and side-effect URLs prevents CSRF; the attacker's site cannot put the right token in its submissions.
It doesn't matter if the token is from a form value or a query string parameter1. An approach that prevents CSRF by including a token in forms is adaptable to (and valid for) hyperlinks2.
1 A MitM / proxy which can intercept a URL can just as easily intercept an HTML form. This is outside the scope of a standard CSRF attack or mitigiation of such. In such cases the CSRF token value is 'knowable' and system is not secure.
2 This assumes the token is a per-user (and time-sensitive) value. A simple HMAC hash of the Session ID should be sufficient in most cases.
I think one of main disadvantages of using CSRF-token in GET requests is possibility of incompetent user to easily disclose his token by copying a link with the token and paste it in some public content like a comment/post/etc... Also GET query parameters including CSRF-tokens usually logged by HTTP servers/proxies and it introduces another risk.
So I suggest you to implement CSRF-secure links using something like this:
<form name="logout" action="logout.php" method="post">
<input type="hidden" name="token" value="9ae328eea8a72172a2426131a6a41adb"/>
</form>
...
Logout
Others made some good points. I add this answer to augment theirs.
Always filter and validate your query string name/value pairs.
Given: You have a database and you want to create a link to help dynamically get (but not change) content that a user can link to. Example: news articles, case studies, public user profiles.
Requirement: Use a query string and deter CSRF by using a token.
One of the purposes of a CSRF token is to help verify that an incoming HTTP request was generated from a page served from your domain (regardless if sessions are in play. The session token is a separate beast). A CSRF token works best when you use more than one defense vector.
Comparison: Check that a submitted token matches one in session.
Time: You can specify a token is only good for a certain period into the future.
public function setFormToken()
{
$token = $this->cipher->getFormToken(); //Some hashing algorithm.
$this->formToken = $token; //In this example, used to insert the token into HTML.
$_SESSION['token'] = $token; //Save the token for comparison upon form submission / HTTP query string processing.
$_SESSION['tokenExpireTime'] = time() + (60 * FORM_TOKEN_EXPIRE_MINUTES); //This is just an abstract example.
return;
}
Then, in addition to comparing the submitted token to the one in session, verify that the submission period is still valid.
private function hasTokenTimeLeft()
{
if(isset($_SESSION['tokenExpireTime']) && (time() < $_SESSION['tokenExpireTime']))
{
return true;
}
throw new SecurityException("Token time has expired for this POST request.", 911);
}
Sessions: If a session has expired, or is non-existent, the a false HTTP request for your content should fail.
Request Info: With HTTP POST request, some attempt to check that the token, user agent, and IP match the one from the original HTTP GET request (which means storing it in session before responding to the GET request).
Query strings, as previously mentioned, can get cached. There is no problem with that if the data is supposed to be publicly available, anyway. Think about someone bookmarking a product on an e-commerce website.
What you have to ask yourself is "Should I be able to get to this content from anywhere, anytime, through this link with a query string?" If yes, do not use a true, backend, randomly generated, CSRF token. Imagine you are running for elected office by word of mouth and people sending links to their friends and family in email (ok, bad practice). In this case, you never want to set off a "trip wire" and cause a fail condition. If a fresh token always needs to be generated on the backend first, emailing your link around will not work.
If you should not be able to get to content from outside of your security context (i.e., before logging in), then you are free to take whatever measures are necessary to fortify your CSRF token strategy using query strings.
Your log out snippet is a perfect example.
Logout
No one from outside your security context should be able to use the logout feature. You want the "trip wire" if someone emails this link around! Obviously, sessions are integrated into this solution (the token has to be stored somewhere while the user uses the page). Session duration and logging out should be managed carefully, and I say you are doing a good job.
Encryption: The only thing you could do better is encrypt the hash/token for the query string, then decrypt it and verify it upon submission. Additionally, you can break the token up into pieces, mix the pieces up, and basically use some security by obscurity string techniques to make your CSRF token more resilient.

CSRF Token Multiple tab issue

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 !!!

Protecting login and comment forms against CSRF

I have read many articles about CSRF protection (this is a good one) and various questions here on SO, but none of them seem to be informative enough to answer my question.
I am developing my own CMS and I want to secure my login and comment forms. I am going to allow anonymous users to comment on my website.
All of the forms on my website are secured using tokens. I already know about that approach, but the problem is that it needs an active session (that is, after the user logs in). The problem with the login and comment forms is that they are accessible to just about anyone and do not require you to log in - what would be the best protection against CSRF in this case?
On the link above, I read that it could be possible to create a "pre-session" when the user tries to log in and then proceed to the usual anti-CSRF methods (like assigning a token to the user's session), but I have no insight on how to achieve this.
The referrer header is a weak solution, so I guess I shouldn't bother. The Origin header, is, as far as I have tested, only supported in Google Chrome. What about custom headers? XMLHTTPRequest seems like a possibility, however, I have spent literally more than three hours on Google looking up some information about how should one implement such a security measure on their website. But even if I could use a custom header, doesn't it make it useless since the HTTP headers can be faked completely?
So, the question: how should I protect my login and comment forms against CSRF?
Edit: here's some additional information from the link that I provided above:
We recommend strict Referer validation to protect against login CSRF
because login forms typically submit over HTTPS, where the Referer
header is reliably present for legitimate requests. If a login request
lacks a Referer header, the site should reject the request to defend
against malicious suppression.
and
Secret validation tokens can defend against login CSRF, but developers
often forget to implement the defense because, before login, there is
no session to which to bind the CSRF token. To use secret validation
tokens to protect against login CSRF, the site must first create a
“presession,” implement token-based CSRF protection, and then
transition to a real session after successful authentication.
I just cannot put an end to this argument after reading the above quotes. One of them mentions using the referrer header, but I'm not quite sure whether it really adds much to the security of the webapp.
Edit 2: What about using CAPTCHAs?
The CSRF problem relates to someone using logged in user credentials to submit something. This is highly problematic as a malicious site can do stuff as anyone who's just browsed into your site. If you're talking about forms that can be used as anonymous, without logging in, there is lot less CSRF risk as there is considerably less to gain from posting to the form from another site - as anyone can do it directly also with same permissions.
So I don't get why protecting against CSRF for non-logged-in forms is needed.
If you do want this, a pre-session token could be technically similar to real session, but just a more light-weight one. It wouldn't really contain anything else than a generated token.
EDIT: about using the $_SESSION provided by PHP for the pre-session token, that's PHPs standard session mechanism. If you want to use that, then yes, that's about it.
However you're not forced to do it that way, and I personally wouldn't do it like that as it consumes server memory for all visitors, and that's not really needed. For a more efficient mechanism, basically you need a) a cookie identifying the user and b) something stored on the server side telling that the cookie is valid (and if needed, who is it valid for, meaning the ip). For a more light-weighted approach you can just create a token, store it in a cookie, and generate something matching that token in the form as hidden field, and match those on submit (like explained by Devesh). The latter would prevent submit of forms from another site, the former would prevent even the case where a malicious site does a lookup on your site and tries to set any cookies to the end user, too. So three approaches that I can think of:
just prevent image requests from other sites - using POSTs prevents this
prevent form submits from another site - form hidden field matching a cookie prevents this
prevent form submits from another site that do pre-lookup on your site - this would need IP verification, something stored on the server side, like ip in the database matched to the cookie
EDIT2: On captchas, their main use case is to prevent automated (brute force) login attempts. They would fix the issue with CSRF requests on login forms, too, but are an overkill for that. For preventing brute force login attacks they might be needed in some cases, although something more user friendly might be in order to not degrade usability too much. Maybe something like KittenAuth :)
You cannot realy protect an anonymous form against CSRF. Simply because the other site can act as a regular user. I can just create a site that does a curl request to the anonymous form and store the cookies and tokens in variables. And then make a second request to post the form.
The script isnt realy forging a request, but is just posting automatically.
The point of CSRF is to prevent a script/person to perform actions on behalf of another user. So that would be me trying to post as you. To prevent that the session/cookie with token approach is a good a solution. Because I have no way to get your session and token, unless your site is flawed in other areas. I would suggest to read the OWASP guidelines to get some idea on what you should be on the lookout for.
Another thing you should always do is make sure "actions" are always with POST request so I cannot simple put on image on your forum that links to 'http://www.yoursite.com/delete.php?id=10'. If you allow GET request and you open the page that contains this image, I would have forged a request. If you only allow POST it would have no result.
I think you can tackle the CSRF kind of problem by combining the hidden field added to your form and at the same time add the same value in the cookies and attach with the user response. When user post back the form try to match the hidden field value and the cookie value coming from the request , if both are matching you are good to go...
he CSRF problem relates to someone using logged in user credentials to submit something. This is highly problematic as a malicious site can do stuff as anyone who's just browsed into your site. If you're talking about forms that can be used as anonymous, without logging in, there is lot less CSRF risk as there is considerably less to gain from posting to the form from another site - as anyone can do it directly also with same permissions.
So I don't get why protecting against CSRF for non-logged-in forms is needed.
If you do want this, a pre-session token could be technically similar to real session, but just a more light-weight one. It wouldn't really contain anything else than a generated token.

PHP further security on anti-CSRF token

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.

Categories