1

I'm very new to things when it comes to website security. I currently have my website set up like this:

  • User inserts username and password
  • User gets redirected to a login.php page to proceed with authentication. Username and password are sent over POST to login.php and is NOT ENCRYPTED in any way. (Potential security flaw, but I'm not sure if it is or how to fix it..)
  • Username and Password is matched with username in database and hashed password in database
  • Login.php generates a 100 character code (May be excessive). This code is stored in the user's cookies and in a MySQL database along with the current time.

Authentication:

  • Checks for the authentication code in the database and checks if it's still valid (was made less than 6 hours ago). If not, redirects user to login page and denies access.

Again, I'm very unsure if this is secure at all. It should be noted that this website will not be getting very much traffic (as it's not meant to be public) however I still do wish to have a certain amount of security on there, just in case.

Also, is it secure for a MySQL server to be storing these codes?

  • So you are trying to rebuild some session based authentication. You could also store this session code in hashed way in your database to avoid "session hijacking" in the database. But I am sure, that there is a great framework around for your application, which already has a decent authentication implementation? – cornelinux Oct 23 '16 at 21:17
  • Many of the other authentication implementations are simply too complex for this application. My use for doing this is to simply deny access to a web page. Each user does not have specific information which will be shown, but instead, a verified user will ONLY have access to the information which is built into the web page. I have in fact looked at authentication methods such as Auth0, but everything seems too "heavy" and many features are unused for my application for it to be considered worth it in my own opinion. I will look into hashing the session code also. – Twijn Oct 23 '16 at 21:24
  • At least you can be sure that probably your session code has more entropy than the users password. – cornelinux Oct 23 '16 at 21:26
3

Storing the session id in the database is ok as long as access to the database is restricted and you regenerate the id each time the authentication is successful, but you didn't say much about the cookie. A 6 hour TTL is excessive. Typically a session id should expire after around 20 minutes of inactivity, although this can vary greatly depending on what the service being authenticated actually does. It should be a session cookie and therefore expire when the browser is closed. Also, it should probably have the httponly flag set to protect against javascript attacks and you should provide an explicit logout capability which removes the session id from the database. But the absence of HTTPS is a major security hole.

Also, I hope you are generating and storing sufficientlty random salts for the hash and using a decent hash algorithm.

You might also spend some time thinking about how you prevent brute force attempts on your site.

  • The cookie is set to expire in 1 month. There is a reason to this, even though it's not a very good reason. At this point the session does not get deleted from the database automatically. Instead it will be deleted when there is a failed login due to expiry of the code. Having at 1 month means it will more likely get deleted however I'm still working on it and plan to delete automatically. Also, how do you enable https? Is it an option? It is also hashed using password_hash in PHP – Twijn Oct 24 '16 at 17:21
  • You said you don't need to carry around much state for the user. If you just store that state directly in the cookie (basically just a user name, login timestamp, and nonce) and encrypt it, you can follow cymcbeans advice and use short-lived session cookies, and session cleanup will be done automatically by the browser when it is closed. – Pascal Oct 24 '16 at 18:07
1

You don't have to worry about the security of storing the session ID in the database backend. That's not where it is usually at risk. Your server is, hopefully, secure. If it isn't and an adverary can somehow access the database you're running on it, you've already lost because then all the information you want to protect using a website login is probably known to the attacker whether he has access to the session id or not - chances are he won't just be able to access the database, but all the files on your server that the webserver has access to. Unfortunately, this includes the data you actually want to protect with your login.

Usually it's the client and the transport medium that poses much bigger security risks to the session.

Others have mentioned how important it is to use an encrypted connection. I agree. Making your authentication secure without https / TLS is very difficult.

Not encrypting your connection leads to the browser cookie being sent over the wire in the clear. So it doesn't make sense for you to worry about the 100-character code being stored securely in the database; it's much easier to get at this code by simply reading it out of the cookie while the cookie is in transit.

If you don't want to use https (lets encrypt is a very good suggestion imo), you should first secure the cookie. This is arguably even more important than taking care of sending the password in encrypted form, because while the password is only transfered a single time - at login - the cookie is transfered with every single request the client makes to the server, and thus the chance that it is stolen is greater (though the consequences of the password being stolen are probably worse).

You could make your cookie more secure, for example, by sending back a new cookie with every response and have the cookie consist not only of your secret 100-character session id, but instead add to that a nonce and build an hmac over both the session id and the nonce using a secret only the server knows. Then if someone steals the cookie from the request, that won't do him any good because it won't be valid for a second request. And if he steals a fresh cookie from a response and uses it before the legitimate client does, the server will notice something is wrong when the legitimate client tries to send a request using the now-used-up cookie.

If you don't encrypt your connection and don't add a nonce to your cookie, you'll always be susceptible to replay attacks for the lifetime of the session.

By the way, since you're saying that the only reason you need the authentication is to authenticate a user, not to give him access to personal information stored in the database, you could get away by simply storing the username of the logged in user, the date he logged in and a nonce in the cookie. Encrypt the cookie on the server using a secure symmetric encryption algorithm. If you do this, you don't even need to store any session ids in a database; you can see whether a client is authenticated by simply looking at the decrypted cookie. This isn't any less safe than session ids if you keep the cookie encryption key secure on the server, and if you can't do that, well then you probably can't keep the database on the server secure, either.

As for the plaintext password: Note that encrypting the password using Javascript in the Browser doesn't actually help very much, it just looks more secure. The problem with that idea is that what you should be protecting yourself from is a man in the middle attack, e.g. someone listening to all your traffic, usually by sitting somewhere on the route from the client to the server. Someone who has this capability can probably also make arbritrary changes to your traffic; e.g. he can always change the javascript encryption routine to his liking. Javascript is not a secure platform: What if he changes your state-of-the-art encryption function to this:

function encrypt(password) { return password; }

You mention that you've looked at Auth0 as an alternative to rolling your own authentication method. If you don't use https to secure the transmission of your passowrd, then I don't think you can do it in a secure way at all, and looking at third-party solutions would be the right thing to do. You could use digest authentication, which is provided by Apache servers and which is a bit more secure than sending your password in plaintext. But I'd suggest you look at OpenID Connect, which is a lightweight authentication solution built on top of OAuth. It basically consists of redirecting your user to a login url provided by one of the OpenID providers (Google, Microsoft, Twitter, Yahoo, ...), then receiving an answer on an endpoint you provide as a callback. It's much simpler than you'd think and both Google and Microsoft have step-by-step instructions on how to set it up, plus code libraries if you want to use them. I think this is secure even if your oauth callback endpoint uses http instead of https (but I may be wrong, check before blindly trusting my memory). OpenID may be overkill if the login system is just for yourself, but it's also not much more work than implementing your own login/logout functionality and probably much more secure than rolling your own solution.

Finally, if you don't use https, you make all the not-for-the-public-eye stuff on your website visible to a man-in-the-middle who watches your clients access it. After all, all this secret data is transfered in the plain. There's no way around that.

Best solution to that: Go with shackledtodesk's suggestion and get a let's encrypt SSL certificate.

  • +1 for openid, but changing the sessionid on each request creates a lot of complexity which will break in unexpected ways (arguably an interesting approach for a surrogate authentication token for use in Ajax requests though). – symcbean Oct 24 '16 at 15:54
  • Still seems more simple to just do it yourself. May be slightly less secure but again, security is not 100% needed. It's a private website, the security sits there only "just in case" I'll look into Let's Encrypt but I'm not sure if the host supports it. – Twijn Oct 24 '16 at 17:25
  • I think your gut feeling tricks you. It takes time to understand how OAuth flows work and which one to use, but you only have to invest that time once, and writing the actual code to do authentication using Open ID really isn't much more complicated than doing an http redirect, sending one or two server-side https requests and verifying that some values you get sent are what you expect them to be. It's much simpler than you'd think. – Pascal Oct 24 '16 at 17:35
0

So you are trying to rebuild some session based authentication. You could also store this session code in hashed way in your database to avoid "session hijacking" in the database.

But I am sure, that there is a great framework around for your application, which already has a decent authentication implementation?

0

User gets redirected to a login.php page to proceed with authentication. Username and password are sent over POST to login.php and is NOT ENCRYPTED in any way. (Potential security flaw, but I'm not sure if it is or how to fix it..)

Even before we talk about MySQL, we need to address the above. This is the first thing you need to fix if you are not enciphering the password via JS in the browser, or otherwise encrypting the traffic between the browser and your server. The simplest thing here is to require access to your web application be over SSL/TLS. Considering this is low volume, a free, secure option is to get a certificate from https://letsencrypt.org/.

Back to MySQL. You haven't mentioned what your HASH method is. Not all hashes are created equal. The Unix crypt function is worthless. MD5 is considered insecure partially because of its simplicity, but also because there is a collision issue (multiple passwords could result in the same hash). Similarly, SHA1 has been found to have mathematical flaws. SHA256 is a reasonably secure hash method.

Without knowing how your sessions key is generated, character length does not provide enough information as to the security (or lack thereof) of your cookies.

  • Encrypting or hashing the password in the browser before sending the cyphertext in the clear has limited value since the mechanism for encrypting/hashing is also delivered in the clear and hence vulnerable to MITM (although, in the case of hashing not to sniffing). – symcbean Oct 24 '16 at 15:42
0

Note: "Authentication code" = "session token"

The design is mostly OK and pretty common

Your overall design is OK and it is common to do it this way. If your site is not a high value target it is perfectly acceptable. I've provided a couple things to think about below if you want to get the extra step.

You have to use SSL

All of this stuff is worthless unless you are using SSL/TLS (HTTPS). If you're not, you should look into this as your highest priority, if you are at all worried about security.

Encrypting the password (e.g. with Javascript) without using SSL, by the way, is pointless and does not alleviate the problem in any way.

Couple cases where encrypting the session token is a good idea

There are a couple decent but weakish reasons to encrypt your session tokens in the database or to use a hash.

Real time DB compromise. The usual attack vector for DB compromise is not real time-- hacker gets a copy of it, takes it back to his lab, and tries to brute force stuff. This attack vector isn't very important for the session keys because they only live for six hours anyway; by the time they get around to using the keys, they will probably be expired.

However, if there is any risk of a real time DB compromise (e.g. if your site is vulnerable to SQL injection) then you will want those session IDs in the DB to be different from the session IDs that are presented by the browser. You can encrypt them or hash them. If you don't, anyone with real time DB access can impersonate any user.

Analytics. If you are using site analytics, you may want to be able to include a session identifier in the information that is sent to the analytics engine. if this is the case, you don't want to send the real session ID. So an encrypted or hashed session ID would be very handy for this situation. Rr you could substitute an index or pointer to the session key (e.g. the identity column from your session table).

Logs. Logs have a tendency to end up being somewhat more vulnerable to compromise than the database. And session identifiers tend to get logged (they are really handy for debugging and necessary for non-repudiation). It is safer to log an avatar for the session identifier, such as an encrypted or hashed value, or a session index that is only meaningful internally and cannot be used in the public interface to your site.

Double submit cookie

Storing the session key (authentication code) as a cookie is OK, but you may also want to include it in any form/post that updates state (e.g. saving any information, posting a transaction, or updating a password). This is called double submit cookie pattern and helps mitigate risk of CSRF, a.k.a. session riding.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.