PHP token security - php

I wrote a PHP application which requires a login. This application is private so no new users can register. First I used sessions to identify the users but it lead to problems on tablets because they lost their sessions. I think this is because of energy saving operations.
Now I changed my application to generate a random security token. So the authentication is as the follows:
Log in
Generate random security token and save it to disk
Redirect the browser to http://myhost/site?id=[securitytoken]
On the server side I check if the file exists - if yes, user is authenticated
Everything is now working perfectly I am just thinking about security concerns. It is no problem if the user sees the security token. Is it somehow possible to find out the token when I use GET? I am using SSL.
I tried to change the expiration times and cookie lifetimes. On a normal computer it is working as it should. On the table it is also working IF it does not go into standby (meaning the screen gets black). If the screen gets black, the session expires very soon.

There is no vulnerability inherent to using GET instead of, for example, POST from a network perspective.
The only caveat you should keep in mind is that a GET request is more likely to be stored on the client (e.g. browser history) in a way you might not intend. For these reasons, I typically use POST requests for authentication.
The problem you are attempting to solve sounds remarkably similar to "remember me" cookies. The linked blog post might be helpful in mitigating the security risks involved in designing token-base authentication systems.
Generally, web apps are confined to using localStorage and cannot silently read/write to files in the background. How are you accomplishing this?
When you say you're using SSL, do you really mean TLS or do you mean SSL version 3? If SSLv3, I would advise updating your stack and webserver configuration to support current best standards. TLSv1.2 with ECDHE and AES-GCM + SHA2 or ChaCha20-Poly1305 are ideal.

GET is more vulnerable than POST as it can be transmitted and stored:
In server logs by default.
In corporate proxy logs.
In the referer header if your page uses external resources or links to external domains.
In your example you have a http URL (this could be a typo though as you said you are using SSL). Make sure you are using https URLs to protect this data in transit.
This approach could also be vulnerable to Session Fixation as an attacker could get the user to visit a URL containing, or redirecting to, the same session ID as the attacker. When the victim logs in, the shared session will be authenticated meaning the attacker is now also logged in. To protect against this, refresh the session ID upon login and logout.
Cookies are often the preferred approach for session handling as they are harder to attack in the above scenarios.

The issue with in URL variables in the get form means that for one : users can easily modify it (by accident or not) and they stay even when the link is copied somewhere.
If you send someone your link/someone gets your link with the id variable in it,is that a security risk to you?

Related

Is it save to use the session cookie PHPSESSID

When I read about something "PHP Session vers Cookie" often I found cookies are not mentioned to be save because they are stored at the client side in the browser. And of course a hacker can get access to the PHPSESSID cookie and get the session_id.
So meanwhile I am a little bit confused about the recommondation to run PHP always with the php.ini statements "session.use_cookies = 1" and "session.use_only_cookies = 1".
What could a hacker do if he get this cookie PHPSESSID whigh includes automatically the session_id?
Would it help to make a statement "session_regenerate_id();" after "session_start()"?
Even then the session cookie will be written to the client side and could be read by a hacker.
Am I right to say this makes the idea of a session cookie - which will identify the user even if the browser will be closed - useless?
This is really confusing.
I am a beginner with the security questions of PHP and Sessions. May be I could find some help here to understand this concept. I read already many post but I did not yet found the answer to my specific question.
The short answer is $_SESSION variables cannot be accessed client side e.g. $_SESSION['variable'] -> NOT stored on client. The $_SESSION id which is used to associate those variables to a client can be accessed as it's stored as a cookie which can be easily manipulated. So for example, if I created a login system which validated a user's credentials, it's common practise to then use this $_SESSION id or a session variable ($_SESSION['loginSuccess']) as the identifier that this login was a success so it can be allowed to access "Locked" pages. A client $_SESSION cookie is only active when the browser is open, if you close the browser down, your $_SESSION cookie will be forced to expire.
The huge security risk is if someone was able to gain access to your session variable using techniques like 'Man in the Middle' attacks (MitM for short). All they would need to do is manipulate there own session id cookie by replacing it with the authenticated cookie and then refresh the page. To get around this, just make your website has an SSL certificate installed from trusted CA (certificate authority e.g. GoDaddy) and enforce your web server to only allow HTTPS connections. This means that all your data transferred from server to client and vice versa is 1-to-1 encrypted.
Even after you have enforced HTTPS, it's worth noting that it's still possible for a MitM attack to be successful and access your encrypted data. This is usually done by the MitM software initiating the SSL acknowledgement on the clients behalf, after that, MitM presents a different SSL certificate (usually self-signed) to the client. By doing this, MitM software can see all encrypted traffic from client and server using 2x SSL certificates. Users would get an error in browser stating the certificate does not match the domain used or is not trusted (because of being self-signed), but as we know, some end users will no doubt accept this.
To overcome this issue, most banks check the validity of the client-side certificate using JS and then confirm server-side if it's valid. I've personally not had to go this length for the security of my sites but I'm sure it wont be long before this becomes best practise.
For MitM Info: https://security.stackexchange.com/questions/65794/it-is-possible-to-decrypt-https-traffic-when-a-man-in-the-middle-proxy-is-alread
For SSL JS: Within a web browser, is it possible for JavaScript to obtain information about the HTTPS Certificate being used for the current page?
For Session Hacking: Can session value be hacked?

How to protect the cookies generated by the PHP after logging in

After logging in, the cookie is set by the PHP. But the text in the cookie is same for the user. So if someone gets the cookie then one can easily login by using the user's cookie he got.
Although I found that it is not possible to set or edit a cookie in the browser. But if someone (probably a hacker) happens to succeed in editing/replacing the cookies, then he can login easily.
I have tried XOR encryption but that doesnot make any difference.
How can I better protect my website?
Exploiting authentication process using cookies is part of session hijacking. You should learn that it is not only cookies which make your scripts vulnerable to this kind of attacks.
The impenetrable solution is HTTPS. The compromise for using cookies to store your login information is using HTTPS along side.
One doesn't have to have access to your PC to sniff your cookies and hijack the session. It can be done in a LAN or even in public wi-fi using simple programs as long as all your data are not fully encrypted end-to-end.
Warning: Header only encryption is not enough. See FiresSheep section of the following article
Session Hijacking

WebSockets + PHP (Ratchet) login system

I know how to make a secure login system with PHP including basics like hashing, salting and more complex security measures.
Recently I've been using Ratchet with WebSockets a lot. And I've been wondering if it is possible to create a secure register/login system using WebSockets.
User enters his data in form.
Data is validated and sanitized.
Password is hashed.
Everything is being sent to the server via WebSocket.
PHP stores it in MySQL database and salts the password's hash.
PHP returns a callback that registration finished via WebSocket.
User is granted access to the website.
I see it might work. My doubts are here: how secure is ws:// protocol? How to make sure that after logging in the user is the user that was logged? Some sort of sessions? Tokens?
Are there any frameworks/libraries/implementations of such a thing?
Questions are more out of plain curiosity over a new (kinda) piece of tech. If it doesn't work I'll just go for AJAX POST request. :)
No, it is not possible to set up a secure authentication using any of the current WebSocket servers written in PHP.
They all lack TLS support. (Even mine, though I do have an active development branch devoted to providing TLS support.)
Here is what is required for a secure authentication system with WebSockets:
Basic PHP security first:
Always transmit via TLS or some other secure transport system.
Use bcrypt or scrypt (or a future more secure system) to hash the password for storage in the database. Even a stretched SHA256 password with a salt generated from a cryptographically random source is now considered insecure.
Authentication tokens (such as the session token created by PHP and stored in the session cookie) must be cryptographically unpredictable.
Authentication tokens must not be available to non-TLS traffic or client scripts. (Strict enforcement of the Secure flag AND strict enforcement of the HttpOnly flag.) This explicitly means that a user can not be securely authenticated unless they are in https: and wss: mode.
Session data must be stored in a secure directory or data storage on the server.
Reset the session token as part of authentication. Completely delete the data associated with the old session ID.
PHP's built in algorithm for generating session IDs uses /dev/urandom if it is available on your system. Windows users do not get cryptographically random session IDs, though because most WebSockets implementations would require a Posix environment, this isn't an issue. If rolling your own session ID generator, use openssl_random_pseudo_bytes(), and remember that when it comes to security, it's a bad idea to roll your own.
Also, by default, the PHP session cookie does not have the Secure flag or the HttpOnly flag set. Change these in your php.ini, and yes, this means that people can not authenticate anyone who is not using a secure connection -- but this is true anyways, since without TLS, you can not ensure that anyone is the same user from request to request, even if they're using the same session ID and same IP.
And, by default, the PHP session save path is your system's temp directory. This is readable and writable by anyone. Thus, any rogue process, regardless of escalated privileges, can access and alter any session data. Least access means that only the web server user and, in the case of those of us using WebSockets, the WS server's user needs to access the session save path.
WebSockets specific authentication:
The session cookie is available to the WebSocket server during the handshake. This includes when the cookie has the HttpOnly flag set. (Tested on latest publicly available Chrome on Windows.) (Secure flag not testable yet. Give me a couple months as I get TLS working on my server. If secure cookies are not available, or are available in a non-secure context, I'll be personally raising a holy stink with the browser vendors on your behalf.)
This means that someone who has an authenticated session can also be pre-authenticated on their WebSocket connection without having to pass data through the web document body (no need to embed the session ID in the HTML or in data in a script tag, which would then be re-transmitted through the open WS connection).
As for securely authenticating someone using WebSockets... There is one huge caveat.
Because WebSocket servers have multiple users connected at the same time, the traditional sense of PHP sessions is broken. Which session do we mean?
Thus, the $_SESSION superglobal MUST be strictly off limits, and the session_...() functions should be considered highly dangerous. The only safe and meaningful session functions are the read-only version of session_save_path(), which tells you where to find the session files, session_encode(), and session_decode().
To get the session data, you will need to read the session file, running its contents through session_decode(), and associating the results with the specific connection for that specific user. You will also need to do this periodically, as the session data changes without warning. To persist any data to the session, session_encode() is your friend, of course. Since PHP doesn't care about race conditions on session data, you shouldn't either. Just read the file, change the data, and write to the file, and it'll be all good.
And this brings us to the first real problem: In order to have secure authentication, you need to reset the session token when the user is authenticated. Since client side Javascript can't write to an HttpOnly cookie, you can't change the session ID on the client side.
The status of whether the user is authenticated can easily be updated within the existing session data, of course. That's fairly trivial. However, because we need a new session ID before we persist the new authentication state, and that new session ID must be valid for all of the client's connections immediately, we can't completely perform secure authentication through a WebSocket connection.
A possible work-around to use as much WebSockets as possible (once a PHP WS server supports TLS, that is):
Client sends login information to the server through the WebSocket connection.
Server responds back with a cryptographically random token.
Client responds back with a salt through the WS connection, and with a hashed and salted version of the token through an AJAX request.
Server verifies the salt matches, and using the AJAX request's script, calls session_regenerate_id(true), and returns any appropriate response (just so long as the set-cookie: header is set).
Server updates its internal mapping to the user's new session ID.
Server discards the one-time token completely, and naturally logs any attempted use of any invalid one-time tokens.
(It might be worth it to implement a true Diffie-Hellman exchange to set up a true secure shared secret. I am not a security expert; the above algorithm may not be as secure as I think it is, though because it would already be in two TLS tunnels, it should be secure. (The https: tunnel is separate and distinct from the wss: tunnel, thus there is a need to confirm information sent through one tunnel matches information sent through the other, but should not require secrecy in addition to that already afforded by TLS.))
Bottom line:
Yes, security is hard to get right. But it's worth it.

User authentication in an SSL iframe

My web application is receiving increased attention and I need to provide additional security to protect my customers.
The biggest problem as I see it is that the user login data is sent as plain text. My goal with this question is to discern if the following approach is an improvement or not.
In extension I will need to get dedicated servers for my service. This proposed solution is temporary until then.
I am currently running my web application on a shared hosting web server which only provides SSL through their own domain.
http://mydomain.com
is equivalent to
https://mydomain-com.secureserver.com
My thought is to have:
http://mydomain.com/login.php
...in which an iframe opens a page from the secure server, something like this:
<iframe src="http://mydomain-com.secureserver.com/ssllogin.php"></iframe>
I authenticate the user in
ssllogin.php with the (hashed+(per
user based-randomly salted))
passwords from the database.
After proper session regeneration set a session verifying the authentication.
This session is then somehow transferred and verified on http://mydomain.com
Is this approach even possible to achieve? Would this be an improvement of my login security or just move the "point of interception of password" for the attacker to another instance?
All feedback is appreciated.
You don't need an iframe. Just make the action of the login form to point to https://yourdomain.com/login.php . In there you may check if user & password are correct, and then redirect again to plain http.
BUT this is not 100% secure. The fact that you are sending the user & password via https may prevent an attacker or sniffer to get that. But if you later revert to plain http, it is possible to this attacker/sniffer to hijack the session of any logged in user sniffing the session cookies of this user.
If you want more security (not 100%, but more than this previous option), stay always in https, for all resources (css, js, images too, not just your php/html files), and even serve the login page via https.
For some reasoning of these points, see firesheep (for the hijacking session problems) or the recent tunisian gov't attack on tunisian facebook/yahoo/gmail users (for serving even the login page via https).
edit: sorry, I misread your question. If the SSL domain is different than the not-ssl domain, you may have problems, as the session cookie only will work against the same domain or subdomains. So, if you do the login and send the session cookie from https://yourdomain.secure-server.com, it will only be sent back by the browser to yourdomain.secure-server.com (or *.secure-server.com if you will), but not to yourdomain.com. I think it's possible to make a wildcard cookie valid for all *.com subdomains, but it's better not to do this (do you want your users' session cookie be sent to evil.com ?)

SSL to log in, regular http after that... how vulnerable is the data transferred from the database?

I roamed the site for this question using the search engine, and I don't think it's out there. If it is, apologies in advance and feel free to point me to it.
Here is my scenario:
I am setting up a web application, Moodle if anyone is familiar with it, with Apache, MySQL, and php on Windows. Moodle supports enabling SSL for login, but then reverts to regular http after login is established. This is running on an internal network with no connection to the outside world, so no Internet access through this network. All users who use the network have logins, however there are some generic guest type logins with certain restricted privilages. Currently the MySQL database is not encrypted.
My question is this:
If my users do an SSL login, and the system then reverts back to http for the remainder of their session, how vulnerable is the data that is transferred back and forth between the browser interface and the database?
I would perhaps prefer to have all the data encrypted, but I am not sure how bad the performance hit would be to do that, so any suggestions concerning that would be appreciated too. Although I will be extending the functionality in Moodle, I don't necessarily want to have to change it to encrypt everything if already does.
I am new to the world of IT security, and my DBA skills are rusty, so if you give me an answer, type slowly so I can understand! ;)
Thanks in advance!
Carvell
A few things.
The fact that the data in the DB server is not encrypted in no way is a factor in the communication between the User and the Web Server. It is a concern obviously for communications between the web server and the database server.
Your risk point between user and web server is in that packets could be sniffed if a person was able to interject in the middle of the communication chain. However, this risk is mitigated by the fact that your on an internal network.
Therefore, unless you are VERY concerned about the other people in your organization, you are more than likely ok. However, if it is really sensitive data, you might do ALL communications via SSL to ensure that it is transmitted securely. IF you are this concerned, then I would also look at the security of the DB and the communications from DB to webserver.
My concern would be how your authenticated sessions are propagated.
Generally a session works by setting a cookie or appending a session id to any URLs presented by the web site. Once a log-in has been established, often the credentials aren't needed any more, as a session is then linked to the user and deemed to be authenticated, and the existence of the session itself is proof of a successful authentication.
However, as previous posters have mentioned, local network traffic can be available for sniffing. If someone sniffed a session id, they could recreate the cookie or urls using the session id, and simply access the site as that session user, even changing the user's password if that option was available.
I would say that your decision here rests on the security of your sessions. If you have some mitigating factors in place to make sessions difficult to replicate even if a session id is compromised (ie. comparison to ip addresses, etc), or your user accounts are relatively secure from a compromised session (eg. require current password to change account settings), then perhaps SSL after login isn't required. However, if you have doubts and can afford the performance hit, then having SSL throughout the site will guarantee that your sessions can't be compromised (as far as you can guarantee SSL, anyway).
With no internet access to this network, the only thing that could potentially happen is someone else (who is already on the internal network) snooping on another user's HTTP traffic. If someone were to actually do that, and you aren't using SSL, they could read all the data that your website is sending/receiving from that user. But is that actually a concern?
Since you are on an internal network turning on SSL for the whole site should not be that bad performance wise, although it is probably unneccesary.
At the very least, you should encrypt the data in your database.
All sensitive data should be encrypted when transferred over an insecure wire. If you just transfer login details over SSL, all your data is still vulnerable to eavesdropping.
Since the data's not encrypted, anybody with sufficient network access (i.e. physical access) can read the data passing back and forth from server to browser and back. As long as everyone who has physical access to the network also has authorization to read the data, you're probably alright. If any of the information is sensitive, and should be restricted to being viewed by a subset of people who have physical access to the network, then you need to encrypt it.
Anyone on your network would be able to see everyone else's traffic with a network packet sniffer like WireShark. The connection between your web server and MySQL is also in cleartext. MySQL may not actually send passwords in cleartext; it may be a hash, for instance.
If you are really trying to be paranoid, you may not need to run your app over HTTPS. There are other lower-level possibilities like IPSec. Since this is an internal network, you can probably get away with implementing this on all workstations.
Not much to add to the above correct responses. But, one think you can do is use a Threat Modeling tool for your application. That will inform you on the types of threats you are exposing your data to by not using transport level encryption (TLS/SSL). Once you understand the threats, you can decide on an appropriate risk mitigation plan.

Categories