Persistent CSRF token is safe/secure? - php

my previous algorithm for my CSRF token is using password_hash(), and this is multi-tab and cross-tab friendly. My only problem is that, when I start profiling my codes using kCacheGrind, this function is eating most of the time which is Incl. = 87.1 & Self = 87.11, I am not an expert in profiling but KCacheGrind said that I should focus with a high Self time. So I searched here, I saw ThiefMaster's answer and said that;
You could simply use a token which is persistent for the current
session or even the user (e.g. a hash of the hash of the user's
password) and cannot be determined by a third party (using a hash of
the user's IP is bad for example).
Then you don't have to store possibly tons of generated tokens and
unless the session expires (which would probably require the user to
login again anyway) the user can use as many tabs as he wants.
Is using a persistent CSRF token safe/secure?
what do I need to do to make a persistent CSRF token safe/secure?

Related

Auto login security with PHP, how and why [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I know this question has been asked many times, but I have a little different spin to it. It's a two part question.
First, I am implementing an auto login and I'd like to know where any holes are in my workflow.
Second, I'm unclear as to how a hacker would use the information they stole to compromise a system.
The first part, here is my workflow, what parts are vulnerable. Here are a few things that may, or may not, be helpful to know, I'm using PHP 5.6.21. I will be using their new hash API that uses the latest hashing technology and automatically salts it. I'm using the MVC architecture, so pretty much everything, other than my front controller and personal assets, are outside the root of the web server.
A member logs in and selects the auto login checkbox
A cookie with a hash value, that matches a hash value in the members table, is written to their browser. The cookie is only accessible from the members directory on the server, which is outside the root directory. Also, the httpOnly attribute is set.
The next time the member logs in, there is a check to see if that cookie exists, if so use the hash value as a key to lookup the member in the member table.
If they are found, log them in. If the cookie was set, but no matching record was found, then it's possible the cookie was tampered with. In that case, create a new auto login hash in the database and delete the cookie in the members browser. Then, force them to log in manually. If they choose auto login again, it goes back to step 1, this time using the new hash.
So, its pretty straight forward and no user data is stored in the cookie, just a meaningless hash.
The second part of my question is more general. Let's say a hacker somehow compromises the auto login cookie and gets the has code. What can they do with it? How can they use that to compromise my system?
In the case of SQL Injection, I understand that a data dump may be possible and a hacker could get a read only view of your database. In which case having hashed and salted passwords is a must! They can run those hashes through their evil machines and possible get your login credentials.
I was reading some security paper on why it is important to take all these measures. It kept saying that if a hacker get access to your database... But, if a hacker gets access to your database (with write privileges), none of this matters because you're screwed no matter how strong your hashes are.
Thanks for your time!
There are two parts to this:
Making sure your sessions are secure. Read this for a primer on session security, with configuration examples. Spoiler: HTTPS is mandatory, make sure you're using a CSPRNG for session identifiers, and you're regenerating session IDs during privilege escalation (and/or regularly).
Safely implementing a cookie-based authentication token that will transparently re-authenticate the user when they access your website with a valid cookie but without an active session. I've previously written extensively abut side-channel-resistant persistent user authentication.
The second part is more interesting, because many people stop at the "generate a random token, store in a cookie, and then look it up in the database" step.
You're safe to assume that your heavily-optimized database query isn't comparing strings in constant-time, like you need to be in order to prevent timing attacks.
The solution is to break your token into two pieces: One for the database lookup (timing-leaky), and the other for comparing in constant-time.
The first piece (called the selector) is stored/indexed in your database table.
The second (called the verifier) piece is stored in plaintext in your user's cookie, but is hashed (e.g. SHA256) in the database.
After retrieving the token based on the selector, you compare the hash of the verifier provided by the user with the stored hash, using hash_equals().
Each long-term authentication token should only be used once. Afterwards, a replacement should be issued to the end user. Logging out should clear the cookie, while the session should expire when the browser is closed.
This is only secure if you're using HTTPS with HSTS, and your cookies are set to HTTPS-only! (This means secure and httpOnly are both set to true.)
You can see an example of this system in action here and here.
When a user is required to enter a username and password every time he wishes to login, the only information stored client side is a cookie containing the session id. Now this is prone to session hijacking, which works on the principle that being client side, a user has full control of the session id sent to the server and in a non-secure environment, this is transmitted via HTTP (w/o any encryption). If a malicious user managed to get a hold of another user's session id, he could "hijack" that user's session.
There are ways to prevent or discourage session hijacking. One method is to whitelist the IP Address and/or browser information in the session. If the session conflicts with the "whitelisted" information, the session has been compromised.
Using your "auto-login" logic, your server only requires a single hashed string to gain access to a user's account. Since this hash is stored client-side, a user can "submit" any string they want in place of the hash. If the connection is not secured (HTTPS), and the network the user on is not necessarily trusted, a malicious user can intercept the hash string. They could theoretically use that single hash string to login as the user.
At this point, your hash string, no matter how strong the algorithm was to generate it, is simply the new "username/password".
Most of the holes in the security depend on an insecure connection. If the connection is well-secured with a modern cypher-suite, I don't believe you'd be prone to the same issues.
Assuming that all transport is secure (via HTTPS), the only reliable vector for an attacker would be stealing the cookie from a user's browser either physically or through some kind of browser exploit.
Some extra steps in regards to the auto login cookie could be taken such as:
Storing an IP and locking that auto login token to a particular IP or a range around that IP, anything else could be deemed as suspicious activity and you could terminate the auto login key
Storing the user agent and again, if it differs significantly (such as different browser) then it also could be unauthorised access and the auto login token should be revoked
In those cases it would be a good idea to notify the user that this has happened via email or another reliable option you have at your disposal.
Here's a idea to protect against the situation in the second question: store the hash in a location other than the database. We have an app that stores authentication tokens in Memcached - a server-side key-value store in RAM.
https://memcached.org/
We use a similar algorithm that you use here, except that we do a Memcached lookup instead of a database lookup.
Memcached has the additional advantage that you can set a timeout on how long a token is valid - allowing you to easily implement something where you log off after 30 minutes.

Protect APIs against CSRF?

I have a PHP API that is being used by my website using Ajax requests!
An example of the operations I may perform using that API is (log user in, change password, retrieve sensitive data)
So simply, how can I prevent CSRF when using this API? It looks like it's a bit complicated for me to understand how!
I use HTTPS connection to perform these operation.. but I do not think that's enough to secure the operations!
You will want to use a Synchronizer Token. I don't think I can put it any better than OWASP does:
In order to facilitate a "transparent but visible" CSRF solution, developers are encouraged to adopt the Synchronizer Token Pattern (http://www.corej2eepatterns.com/Design/PresoDesign.htm). The synchronizer token pattern requires the generating of random "challenge" tokens that are associated with the user's current session. These challenge tokens are then inserted within the HTML forms and links associated with sensitive server-side operations. When the user wishes to invoke these sensitive operations, the HTTP request should include this challenge token. It is then the responsibility of the server application to verify the existence and correctness of this token. By including a challenge token with each request, the developer has a strong control to verify that the user actually intended to submit the desired requests. Inclusion of a required security token in HTTP requests associated with sensitive business functions helps mitigate CSRF attacks as successful exploitation assumes the attacker knows the randomly generated token for the target victim's session. This is analogous to the attacker being able to guess the target victim's session identifier. The following synopsis describes a general approach to incorporate challenge tokens within the request.
When a Web application formulates a request (by generating a link or form that causes a request when submitted or clicked by the user), the application should include a hidden input parameter with a common name such as "CSRFToken". The value of this token must be randomly generated such that it cannot be guessed by an attacker. Consider leveraging the java.security.SecureRandom class for Java applications to generate a sufficiently long random token. Alternative generation algorithms include the use of 256-bit BASE64 encoded hashes. Developers that choose this generation algorithm must make sure that there is randomness and uniqueness utilized in the data that is hashed to generate the random token.
<form action="/transfer.do" method="post">
<input type="hidden" name="CSRFToken" value="OWY4NmQwODE4ODRjN2Q2NTlhMmZlYWEwYzU1YWQwMTVhM2JmNGYxYjJiMGI4MjJjZDE1ZDZMGYwMGEwOA==">
…
</form>
In general, developers need only generate this token once for the current session. After initial generation of this token, the value is stored in the session and is utilized for each subsequent request until the session expires. When a request is issued by the end-user, the server-side component must verify the existence and validity of the token in the request as compared to the token found in the session. If the token was not found within the request or the value provided does not match the value within the session, then the request should be aborted, token should be reset and the event logged as a potential CSRF attack in progress.
To further enhance the security of this proposed design, consider randomizing the CSRF token parameter name and or value for each request. Implementing this approach results in the generation of per-request tokens as opposed to per-session tokens. Note, however, that this may result in usability concerns. For example, the "Back" button browser capability is often hindered as the previous page may contain a token that is no longer valid. Interaction with this previous page will result in a CSRF false positive security event at the server. Regardless of the approach taken, developers are encouraged to protect the CSRF token the same way they protect authenticated session identifiers, such as the use of SSLv3/TLS.

Effective way to protect session hijacking in php

I read on how to protect a session in php, there are a few, but they are not so effective like adding to a session the useragent,ip and port and encrypting them both.
What is a good way to prevent session hijacking?
I thought to take the following steps:
Change the PHPSESSID key altogether to something generic like id
Generate token per page and put it on the page and then validate it as well as teh session. That would reduce my reliance on session alone for validation.
I would add a short session expiration.
Add more variables to the session id and encrypt it, so it would be longer and harder to crack. Perhaps I would use RSA encryption.
Put a logout button, so that the user will be able to terminate his session.
Use javascript to count the time, over 5 mins will alert the user to continue his session.
Save session in cookies only.
The difficulties that I heard are: When you use token per page, you need to disable the back button? why is that?
A few other things are also unclear? Is saving session in the database more secure? why?
How more secure is to use SSL? How about regenerating session id very quickly, would it help?
What system would prevent brute-forcing the encryption key (would identifying the ip of the user who tries to flood the server with massive attempts to guess the session id would help?)?
How does session regeneration works, is the old session key destroyed automatically, what if the hacker obtains an old session key would it still work? Please, it is important for me to understand session security, because I am learning how to be a penetration tester?
UPDATE
I thought to do this:
Symmetric encryption on the session id with key A
Symmetric encryption on a randomly generated token that will be in the post field with key
The randomly generated token will be appended to the session id too and then encrypted.
On Request, I should get those variables:
$_SESSION['PHPSESSID'] (has the randomly generated token encrypted in it)
$_POST['RandomlyGeneratedToken']
Decrypt session id with key A and decrypt randomly token with key B.
Do 2 checks:
-Check the token if it is the same as the token on the first request sent.
-Check if the token exists in the sessionid.
Possibility for the hacker:
-Bruteforce the session id.
My session id is long enough it would take him time. I could employ a system that detects massive flow of requests from the same ip with different session id and slow him down with the sleep function.
-Eavesdrop the traffic and get the session id from the user and also the token and try to submit those.
hmm... I will have to regenerate the session id with every request and expire the session quickly on certain pages..may be 1 minute..
But how fast can he eavesdrop?
"Change the PHPSESSID key altogether to something generic like id"
This is security through obfuscation and a weak on at that. The user only needs to view their cookies and put together which is being used for the session id to bypass this
"Generate token per page and put it on the page and then validate it as well as teh session."
this is an interesting idea. but what if the user has multiple pages open? can you support multiple tokens? when do the tokens expire?
"I would add a short session expiration."
Good idea but this might effect users who stay on a page for a long time and then hit refresh only to find that they are logged out too soon
"Add more variables to the session id and encrypt it, so it would be longer and harder to crack. Perhaps I would use RSA encryption."
why use RSA encryption? why not hash it with something one-way like SHA? don't forget to add salts or intialization vectors
"Put a logout button, so that the user will be able to terminate his session."
who ever hits the logout button? ;-)
"Use javascript to count the time, over 5 mins will alert the user to continue his session."
YES
"Save session in cookies only."
dont do this, save the data server side always. cookies can be manipulated as they are stored client side
as for your other comments: you can store your session variables in a database and this allows you to check for other things like ip address and the like (though you can check ip etc with custom session handling functions: http://php.net/manual/en/session.customhandler.php). However, if you use a database and you regenerate your session ID too frequently (e.g. with every page load) you'll find that if your user hits the refresh button rapidly the id will regenerate more quickly than your server can update it in the database and the session will be lost.
"How does session regeneration works, is the old session key destroyed automatically"
yes unless you write custom code then it depends on your custom code
I hope my answers were somewhat useful, but i recommend following the guidelines for OWASP for session management so that you follow best practices:
https://www.owasp.org/index.php/Session_Management_Cheat_Sheet
EDIT
im not sure what do you mean by token? do you mean token as in session id? What value would that provide?
Is your token a session variable? that doesn't make sense as it's value is stored server side the key to which is the phpsessid whose abuse you are trying to prevent.
Also- never count on a hacker's ability not to understand your logic. If they want to understand it they will.
lastly, why do you need so much security? there is such a thing as good-enough security (if you follow certain standards). you likely don't need to protect against foreign government hackers else you'd probably outsource this project. follow best practices outlined in easily googled tutorials or guidelines such as the OWASP one i provided above. It'll be sufficient :-)
edit
"Also, you say the optimal storage is database? what about the last method that I described against brute forcing"
database session storage isn't necessarily optimal. you use it when you need to such as when you load balance multiple web servers that need to share session data.
two ways to hinder brute force attacks are to 1) have a really long session id, and 2) regenerate it frequently

CSRF protection and usability

Between most strong CSRF protection, there is the form token protection. The question I have about this method, is about usability: if a user opens multiple page containing a form, which use the token, are generated multiple token, but only the last opened page can successful send the form, all the other will give error.
I thought 2 solutions:
Keep a unique token for all the duration of session.
Store all generated tokens in session.
But:
This is the more realistic solution, but is less safe.
This generate a large resource overhead, because a user could open many pages, and I must store all the generated token.
Therefore, how have you solved this question?
PS The website I'm developing, is practically a ecommerce in PHP and although the money transfer will be managed through an external provider (like paypal), I think right give a good safety to my service.
You don't need to store tokens in the database.
Instead, you should include the same token in a cookie; a cross-site attacker cannot read or set cookies.
As long as the you get the same token in the cookie as the POSTed form, you're safe.
For additional security, you can hash them with a keyed HMAC hash, and verify that hash to make sure that the token came from your server.
You can also make the tokens per-user.

$_session security

Currently I autheticatic user sessions by matching a key in the session to the same key in a MySQl database. I regenerate the session with a random number that is MD5 protected on every page load. I am aware that sessions are not inherently secure and I'm looking for further security options that can be attached to this method in a speedy manner.
Any Ideas?
Since the session data is stored on the server side and the session ID is used to associate a client’s request with a certain session, it’s the session ID that needs to be protected. And the only viable measure to protect that session ID is to encrypt the connection between the client and server using TLS/SSL.
So you can use sessions as long as the data transfer between client and use is secured. Additionally, you can fix the PHP session to the TLS/SSL session so that the PHP session is only usable within that specific TLS/SSL session.
You're already jumping through hoops which do nothing to enhance the security, and potentially compromise the functionality of your site.
I autheticatic [sic] user sessions by matching a key in the session to the same key in a MySQl database
Even leaving aside the spelling mistakes, this is nonsense. Do you mean you authenticate requests by this method? If so, it's still not helping your security. You've already authenticated the request by de-referencing the session. Whether the request is authorized is completely different - if you need to authenticate the user then you should flag this in the session data.
It sounds like you're trying to prevent a CSRF, but getting this all mixed up with whether you're authenticating a user, a session or a request.
I regenerate the session...on every page load
Again, this is semantic nonsense. You can't "regenerate the session". Do you mean you create a new sessionId? If so then all you are achieving is creating errors when users try to open a second window or use the back button. It provides very little CSRF protection.
is MD5 protected
Just using random cryptographic functions doesn't make your application secure. It doesn't matter what the mapping between the real data and a surrogate identifier is, on its own it provides no protection against MITM.
Either you've done a very bad job describing your current security measures, or you've written lots of code which serves no useful purpose.
Go and read a lot of Stefan Esser's and/or Chriss Schiflet's stuff.

Categories