Do I need to encrypt secret access key? - database

I'm creating a mobile REST API.
Currently, when user signs in with email and password, I generate secret session key (64 chars long), store it in database and send it to the user so that user doesn't need to log in again for the future request until they logged out.
For the next requests, I just check if the provided session key is equal to the one in database.
But, there is a big security loophole I see in this scheme. If the attacker got access to the database, they can use the secret key and impersonate anyone without knowing the password at all. What's the point of encrypting the password in this case besides obscuring user's real password - it doesn't prevent anything else.
So, my question is how do you store these access key correctly?
Twitter will send session key on sign in on their API. So, how do they store these keys?
Thanks.

It's even better to hash the session key, just as if it was a password, and store the hashed value in the database.
The only difference from password hashing is that, since your session keys are (I hope, at least) generated by a secure random number generator and long enough to be unguessable by brute force (I'd recommend at least 128 bits of randomness), you:
don't need a separate salt, and
can use a simple cryptographic hash function like SHA-256 instead of a deliberately slow password hashing scheme like PBKDF2.
Not using a salt also allows you to use the (hashed) session key to look up session records in the database, so you don't need a separate session ID for that.
So, to sum it up:
When starting a new session, generate the session key using a secure RNG, store the SHA-256 hash of the session key in your database, and send the (unhashed) session key to the client.
When the client makes a request, hash the session key sent by the client using SHA-256, and look up the corresponding record in the database.
You may also wish to limit the lifetime of session keys, and to provide some mechanism for the client to explicitly invalidate all of the user's sessions, to mitigate the effects of a compromise of individual session keys.

Related

Storing encrypted datas in DB viewable by app in any time, but not by me (admin)

I need to store in my Database some datas that should only be read by the owner (specific user) or by my application (some background batchs).
But, those datas are highly sensitive, and I, the developper, don't even want to be able to retrieve it.
So :
I can't just encrypt datas with a secret key kept in the server, because I would personally have access to it, so if I wanted, I could retrieve the entire datas.
I can't encrypt with user password because my app need to have access to it without the user puting his password each time.
What can I do to solve this?
If you want to let the user encrypt something in such a way that only he can decrypt it, then you need a key to do this.
You could use the users password to do this, or you could use something else (a separate encryption key).
Now as for the password, you should not have access to that anyway; if you need the app to have access, then you should provide it with an access token of some sort, which will let the user get the access he needs without keeping the password in clear text. Entering the password should then only be necessary when the token is no longer valid (either due to timeout, manual cancellation / logout, or due to some kind of irregular event that might trigger a cancellation for security reasons).
Under a regime like this, where you don't need the password, your reason for not using the password as the encryption key falls away.
Note that no matter what you use as a key here, there will always be a question of trust here so long as you are doing the encryption on the server side; if you need your user to provide a key to encrypt / decrypt on your server, then what guarantees do they have that you will not simply steal that key and read their data anyway - or easier yet, simply not really encrypt it at all?
I realize that this solution is an improvement compared to using a single server-side secret key, since you will now have separate keys for each user, and keys that are not stored on the server (great in case someone is able to get unauthorized access to your DB), but an even better solution if possible, would be to let your users encrypt data on the client side. That way your server side logic would only ever see the encrypted data, and never even have to deal with either encryption logic or keys or any of that.

What could be a decent workflow to a user registration application to store password?

I am developing an application (web\mobile). The user have to register the account using a form on the application (it contains some data as username and password).
These data have to be stored in a database table, these data travel on Internet so I think that it is not a good idea that the password is in clear.
I think that the client have to encrypt the password in some ways and that this crypted password have to be stored in the DB.
What could be a decent workflow for this task?
A common way to do this is to send the password as clear text via a HTTPS connection. HTTPS is a must when anything confidential is sent through internet, not only for passwords.
On the server, calculate a hash. There are many algorithms for this, some more secure than others. A hash function works only for one direction: the password cannot be derived from the hash. Store that hash to the database instead of the password. When a User logs in, calculate a hash from that password, and compare it to the hash stored to the database.

Hashing vs Database Lookup Efficiency

I'm intending on using a hash to generate a verification token for verifying email addresses. The hash would be generated like so:
email:username:salt
The hash is generated with the SHA256 algorithm and the same salt is used for each token generated.
The alternative, and more commonly used, method is to generate a one time UID which is stored in the database and acts as the verification for the new email address.
My question is: is this an efficient (taking processor and disk utilisation etc.. into account) way of achieving the generation of a token for email validation.
The whole purpose of email verification tokens is to generate a token from your secure web server, and email that token out to someone so that they can click a link which contains that token, so you can then verify their account.
The important things to keep in mind:
The token must be impossible for the end-user to reproduce, otherwise it can be faked.
The token needs to be cryptographically signed by your web server (ideally), so that the CLIENT knows this is a valid token. This also is important because when the user sends this token BACK to your server, you can verify that YOUR server is the one that created it.
The token needs to be expireable: you should be able to 'expire' this token if it is not used within a certain amount of time: 24 hours, 3 days, etc.
For this reason, I would not recommend the approach you're taking.
Instead, I would use a JSON web token (this is an ideal use case for them). This other SO question has a decent summary.
Using a JWT will let you:
Create the token on your web server.
Set an 'expirey' date on this token so it can't be used after a certain time limit you specify.
Encode any user-specific data in the token you want: usually a user ID or something similar.
When the user sends the token back to your web server, a JWT will:
Guarantee that the token was generated by your server and not someone else maliciously.
Guarantee the token is still valid (in terms of timestamp).
Guarantee the token hasn't been tampered with.
Let you view the previously encoded token data (user ID / etc).
I hope this helps =)
What you're doing is somewhat secure.
I would refer to your salt though as a key - you are generating a keyed hash. Ensure that you generate a key with sufficient entropy. I would recommend a strength of 128 bits generated by a CSPRNG.
Some keyed hashes generated in this manner are vulnerable to a length extension attack. That is, if an attacker has generated a validation token for foo#example.com then they will be able to work out the hash for foo#example.com.example.org. This is because the output of a hash algorithm also betrays its state. To mitigate this, you could use the HMAC algorithm.
Your current approach also has the limitation that an email address always has the same token. If an email address expires (say Bob Smith with email bobs#example.org is fired from his job at Example Organisation, he will know the verification code that the next Bob S. will get when he starts working for Example Organisation). Whether this is any risk to your application is for you to decide. To mitigate this, you could use JWTs instead, which will enable you to put an expiry date into the token that can be validated. JWT's HS256 algorithm also uses an HMAC, solving that problem too.
Using keyed hashes should be efficient, and doesn't have the storage, maintenance and overheads of database lookups.
By UID do you mean UUID?
Remember that:
the purpose of a [UUID] is to be globally unique, not to be unguessable.
and
[UUIDs] are designed for uniqueness, not for security.
You would be better off generating an 128 bit token on the fly using a secure source of entropy (say another CSPRNG). You may want to hash these (without salt) on the server-side using SHA-256 to prevent any data leakage vulnerability from meaning an attacker can validate any email address.

Is it safe store a username inside a cookie?

I working on security and I 'm storing a session key inside a cookie. I will use it to check if the user is actually connected and if he didn't tried to change some info.
at first I think to just check if the session key is inside the database, but I think it would be more secured to check if the current user has the session key instead of just finding a user that have that key and assume that he must be the one connected.
I know I should use session storage, but since I'm using AngularJS, I don't know how to achieve that, so no need to point out that I should use session instead.
-Would it be safe to put the username inside the cookie?
-Would just using the session key and assume that the user that got the key most be the connected one be a good idea (it would simplify some of my request to the database later on)?
It sounds like essentially what you are trying to achieve by storing the username in a cookie is to make the username a 2nd factor in a 2-factor authentication scheme. The problem is, the username always travels in a cookie alongside the session id and so when one is exposed, the other is too. So no security is gained.
Furthermore, there is no valid security argument to storing username in a client cookie and then trusting that this username is the same one associated with a session. The client can trivially change the value of the cookie before submitting a request. And any attacker that has already managed to have sniffed out the session id from a cookie could probably just have easily read the username cookie too, making a session hijack attack practically the same difficulty. At best, you've achieved no higher security and added unnecessary complexity to your code. At worst, you've betrayed usernames which wouldn't have otherwise have been visible to an attacker. eg. in the case of expired sessions.
OWASP Recommendation:
Session ID Content (or Value)
The session ID content (or value) must be meaningless to prevent information disclosure attacks, where an attacker is able to decode the contents of the ID and extract details of the user, the session, or the inner workings of the web application.
The session ID must simply be an identifier on the client side, and its value must never include sensitive information (or PII). The meaning and business or application logic associated to the session ID must be stored on the server side, and specifically, in session objects or in a session management database or repository. The stored information can include the client IP address, User-Agent, e-mail, username, user ID, role, privilege level, access rights, language preferences, account ID, current state, last login, session timeouts, and other internal session details. If the session objects and properties contain sensitive information, such as credit card numbers, it is required to duly encrypt and protect the session management repository.
It is recommended to create cryptographically strong session IDs through the usage of cryptographic hash functions such as SHA1 (160 bits).
-- https://www.owasp.org/index.php/Session_Management_Cheat_Sheet#Session_ID_Content_.28or_Value.29

Where to store password salt and how to get it

I'm in charge of doing the authentication in our .Net MVC 4 Web Application and I have hit a bump concerning password hashing, storing and authenticating.
Plan is to currently use 2 Salts, 1 Dynamic (Per User) and 1 Static (Web App Constant) and a strong Hashing function.
Given a simple User table that contains a username and password:
Do I store the per user salt in a column in the User Table?
My worries is that by doing so, I will have to get the user from the database in the web application memory with its username only. Is there some sort of attack where that could be problematic?
Ideally I'd like to have this be a one step/one SQL Request authentication.
Am I worrying too much? Is there an alternative to a "Per User" salt where I can still do a one step authentication?
The salt can be stored together with the password-hash, so you can create a salt per password instead of per user. It is a common practice for password hash functions (slow key-derivation function like BCrypt or PBKDF2), to return the salt cleartext as part of the password hash, what means that you can store salt and hash together in a single database field.
To verificate an entered password, you first have to search for the password-hash (using the username or email), and then the function can extract the used salt from the stored password-hash and use it to compare the hashes. That should actually answer your question, databases usually don't have appropriate functions to hash passwords, so you cannot do the verification within an SQL-query, the verification will be done in the code.
The second salt is actually called a pepper, the best way to add this server-side secret is, to encrypt the already hashed password with this secret. In contrast to the hash, this will be a two-way encryption, what allows to exchange the key should this once be necessary.
You don't need an external library for doing this. The framework has its own PBKDF2 implementation built in. I prefer storing the salt in a separate field in the database but that's just a matter of taste I guess.
I've written up my thoughts about password hashing here

Resources