I've coded the mobile api using Node.js, Redis & MongoDB. However right now I am looking for a concrete way to provide security in our system. The question I have inspired by the infamous principle of Auguste Kerckhoff;
"It must not be required to be secret, and it must be able to fall into the hands of the enemy without inconvenience"
After inspecting this principle I figure out that there is no safe way to secure data after a sniffer capturing the entire data package. Of course there are alternate ways like using an API key, using encryption algorithms like MD5 & MD6,Triple DES,SHA1 etc. However this also won't work if the entire data package is captured. And there is security precaution standarts like HTTPS, SSL certificates. However again if someone with talent captures the data package it can act just like a verified user in our system.
How would it be possible to apply a security method such that even though the entire data package is captured, the system would be able to distinguish the request coming from an outer source not from our verified user.
PS: I thought that applying a custom encryption algorithm with timestamp in order to prevent this problem could be a bit chaotic.
According to Kerckhoffs's principle "A cryptosystem should be secure even if everything about the system, except the key, is public knowledge." So the way cryptosystem, works is that the key is the only thing that can be used to decipher the system. If the key is fallen to the enemy then its all over.
In practice when you communicate over the internet or try to
authenticate your email account with the password. Your password is
never sent to, nor stored on the server in plain text. If you do then,
its not secure. The best security practice is not to store the
password at all (not even encrypted), but to store the salted hash of
the encrypted password.
That is one hash for one user. It is one way, you cannot get back user info, just test if it is in the database or not. Now even if the enemy takes control of the database, it cannot access your username/passwords.
Now coming to the point, it does not matter what you transmit in the communication channel, because the communication channel is the enemy!!! It is available to other users, anyone can sniff it. It is like enemies scanning each other on the radio.
The hash that has been sent over the channel can be sniffed and be used for authentication. True, but server can differentiate between spoofed attempt and the actual attempt, using HTTPS connection. Server tracks the HTTPS sessions and would ask to revalidate if something like this happens. HTTPS blocks use of sniffed data / MITM attacks. Even if sniffer gets hash (temporary ticket), he cannot do anything malicious, username and password cannot be cracked.
Thanks to Kerckhoff, our passwords are safe.
How to implement it on node.js ?? look for passport.js package. It implements the current standard OpenAuth.
Related
We are building an android application and one of its features is to book a cab service provider's cab (say an Uber).
We have an application specific user ID. Let us call it AUID. To book the cab, the application would Post a request to server and send AUID along with other relevant information (like lat, long etc). How do I make sure at the server end that the request is indeed coming from the correct user and it is safe to book the cab? In the current form, if a third party gets to know the AUID of another person, the third party can book a cab on behalf of that person.
One of the solutions I thought of was using asymmetric encryption. The application would hold the public key and the server would contain the private key. Instead of sending the user ID to the server, we'll instead send an encrypted key where the key would be AUID + timestamp encrypted using the public key. We'll then decrypt the message using private key at server end to obtain the AUID. If the timestamp at server does not lie within a certain interval of the timstamp sent by the client, we reject the request.
Is this a safe enough approach? Is there any other practice widely followed for such scenarios?
What you propose is sensible: encrypt the AUID on the client app and verify on the server. As comments suggest, SSL is vital.
The problem is that if how to encrypt the AUID is in your app, it can be figured out by anyone dedicated enough.
You can drastically reduce the risks of fake requests by issuing a separate encryption key for each user. This means that if someone cracks your code, they can still only spoof from one account. However, once an attacker had decompiled your app, they could theoretically start new accounts, get a valid encryption key and spoof requests.
What you need for 100% reliability is some form of authentication which is not stored in the client app - like a password or TouchID on iOS or fingerprint api on Android M. So when a user orders a cab, they need to enter some piece of information which you also encode with the AUID and check on the server. That secret information is not stored in your app, so no-one can fake requests.
Requiring a password from a user is pretty inconvenient. Fingerprint scanning is much easier and probably acceptable. You could also use a trust system - if the user has ordered cabs before and everything was OK, they can order without special authentication. Using Trust together with individual encryption keys is pretty effective because anyone trying to spoof requests would need to do a successful order before being able to spoof - which is probably too much hassle for them.
I need to make a log-in system and having basically no previous knowledge of how it's done (with security in mind) I studied it on the internet. The way I would do it now is something like this:
Server has login information in a database table - username and a password hash per user (encrypted with SHA224 for example).
When client wants to authenticate, password is encrypted with SHA224 (client-side) and sent with username to the server to verify a match in the database.
If the user ticked "Remember me" option, an authentication key is generated on the server, inserted into a database along with the IP of the client.
The authentication key is sent to the client and stored in cookies.
Now, when the client returns, authentication key from cookies is sent to the server, the server finds it in the database and checks if the IPs match as well. If it does, the user is authenticated and a new authentication key is generated and sent to the user (and stored in cookies) for next visit.
My questions are:
How does encrypting password make this any safer? The hash still can be captured on the way from client to server and misused just as well as if it was plaintext. I know that this is an elementary question but I somehow couldn't find an answer to this one.
Is this security system secure enough? (or better yet - Did I get it right?)
Why does hashing a password make the system more secure
Hashing is not equal to encryption. Encrypted data can be decrypted back into plain text. Hashed data cannot be decrypted.
By hashing your user's passwords, nobody can see what passwords are used. So if your data gets stolen, the hashes cannot be decrypted by the hacker. The same goes for the system administrator, he/she cannot 'lookup' a password. This can be an all to common scenario in shared hosting environments.
Storing passwords
The easiest way to get your password storage scheme secure is by using a standard library.
Because security tends to be a lot more complicated and with more invisible screw up possibilities than most programmers could tackle alone, using a standard library is almost always easiest and most secure (if not the only) available option.
The good thing is that you do not need to worry about the details, those details have been programmed by people with experience and reviewed by many folks on the internet.
For more information on password storage schemes, read Jeff`s blog post: You're Probably Storing Passwords Incorrectly
Whatever you do if you go for the 'I'll do it myself, thank you' approach, do not use MD5 anymore. It is a nice hashing algorithm, but broken for security purposes.
Currently, using crypt, with CRYPT_BLOWFISH is the best practice.
From my answer to: Help me make my password storage safe
As for the infamous remember me option.
Create a random token and give it to the user in the form of a cookie.
If the user presents a cookie with this token, you give them access. Key is to only accept each token once. So after it is used, replace it with a new random token.
This token is, in essence, just another password. So in order to keep it safe, you do not store the token, but a hash of it. (just as you did with the password)
Your suggestion of binding the cookie to an IP-address will unfortunately not work. Many people have dynamic IP-addresses, some even change from request to request during a single session. (this is for example caused by load-balancing proxies).
Sending passwords to the server
The only method currently usable for sending a password from a web browser to server is by using a SSL-secured connection. Anything else will not be safe, as you cannot guarantee the integrity of the solution on the client side.
Some points I want to add:
the hashing of the password is not done on the client. You cannot do it reliably. The necessary technique for computing the hash (JavaScript in your case) might not be available and you cannot trust the result. If somebody can retrieve the hashes of the passwords in your database he could just login without knowing the actual passwords.
make sure to use SSL or another secure transport for transmitting the given passwords from the client to the server. SSL is a good idea for everything after all.
you should not use a single hash algorithm for storing the passwords in the database. Have a look at HMAC. That is far better. Additionally read about salts in cryptography.
Never ever invent your own crypto
mechanisms. Use someone else's.
Crypto is beyond tricky, and unless
you're Bruce Schneier, you have an
extremely slim chance of improving
it, while having a huge chance of
screwing it royaly.
Do not encrypt passwords, hash them.
If you're using hashes, salt them.
If you don't have
to use straight hashes, use HMAC,
they're much more resistant to
precalculated attacks.
If you're
sending stuff across an unsecure
link, add a NONCE to the transmission
to prevent replay attacks. This goes
for both client->server and
server->client.
If you're using salts and nonces, make sure they have high entropy. 'secret' is not a good one. Make it random, make it long, make it use large character sets. The extra computation cost is minimal, but the security you gain from it is enormous. If you're not sure how, use a random password generator, and then use ent to measure entropy.
Do NOT use a
timestamp as a nonce, unless you have
a very specific need and really know
what you're doing.
Use session
protection. SSL isn't perfect but
it's helluva better than nothing.
If you're using SSL, make sure to disable weak protocols. SSL session starts with 'offerings' of lists of ciphers both sides can do. If you let clients use a weak one, an attacker will definitely use that.
I'm implementing authorization in my gwt app, and at the moment it's done in the following fashion:
The user signs up by putting his credentials in a form, and I send them in clear text to the server.
The server code hashes the received password using BCrypt and puts the hash in a database.
When the user logs in, his password is sent in the clear to the server, that checks it against the stored hash.
Now. The thing that's bothering me about this is the fact that I'm sending the password to the server in the clear, I keep thinking that I wouldn't be very pleased if an application I was using did that with my (use-for-everything-kind) password, but encrypting it on the client wouldn't really earn me anything, since the attackers could just use the hashed password as they would the clear one.
I have been googling all day for this, and it seems the Internet is quite unanimous when it comes to this - apparently there is nothing to be gained from client side password encryption. This, this and this are just a few examples of the discussions and pages I've come by, but there are many, many more, all saying the same thing.
This question, in light of all this, might seem a bit unnecessary, but I am hoping that somewhere, someone, will have another answer for me.
What can I do, if ssl isn't an option at this point, to ease my mind about this? Is there anything to be done, or will implementing some sort of client-encrypt-server-decrypt-scheme just be time-consuming feeble dead-horse-kicking?
For login, SSL should be your option, even at this point. If it's just for login, you don't need an expensive SSL farm, but at least you protect the (use-for-everything-kind) password, even though it's clear, that the remaining communication isn't secured [*]. This may mean, that you need to buy a certificate for just one login server, which can again save you a lot of money, depending on the certificate vendor.
For GWT, if you can't afford to encrypt all communication, you'll have to put the login on a separate page due to Same Origin Policy constraints.
If that still isn't an option, you can think about logging in via OpenID, just like stackoverflow does.
There can't be any secure communication over insecure media without some pre-shared secret - usually provided by the root certificates that are installed in a browser (BTW, it's funny/scary that browsers and even entire operating systems are usually downloaded via HTTP). Other systems, e.g. PGP, rely on previously established trust in a "Web Of Trust", but this is just another form of pre-shared secrets. There's no way around it.
[*] Using SSL for everything - unfortunately - comes with additional practical problems: 1) Page loads are a lot slower, especially if you have many elements on the page. This is due to SSL-induced round trips and the resulting latency, which you can't counter with even the fastest SSL farm. The problem is mitigated, but not fully eliminated by keep-alive connections. 2) If your page includes elements from foreign, non-HTTPS sites (e.g. images inserted by users), many browsers will display warnings - which are very vague about the real security problem, and are therefore usually unacceptable for a secure site.
A few additional thoughts (not a recommendation)
Let's assume the worst case for a moment, i.e. that you can't use SSL at all. In that case, maybe surprisingly, hashing the password (with a salt) before transmitting it, may actually be a bit better than doing nothing. Here's the reason: It can't defeat Mallory (in cryptography, a person who can manipulate the communication), but at least it won't let Eve (a person who can only listen) read the plaintext password. This may be worth something, if we assume that Eves are more common than Mallorys (?) But note, that in that case, you should hash the password again (with a different salt), before comparing it with the database value.
If SSL isn't an option then you obviously don't care enough about security ;)
But seriously - like you mentioned, client side encryption of the password is not a good idea. In fact, it's a very bad one. You can't trust the client side for jack - what if an attacker managed to alter the JS code (through XSS or while it was sent through the wire), so that your MD5/whatever hash function just passes the pass in cleartext? Not to mention that you should be using a good, strong, salted encryption method, like bCrypt - something which is just slow on the client and like mentioned before, doesn't quite add to the security of the app.
You could try bypassing some of those problems: by sending the hash library through some secure means (if that was possible in the first place, we wouldn't have to bother with all this now, would we?), by somehow sharing a common secret between the server and client and using that for encryption... but the bottom line is: use HTTPS when possible (in GWT it's hard to mix HTTPS and HTTP) and justified (if the user is stupid enough to use the same password for your not-security-related app and for his banking account, then it's highly likely that he/she used the same password on a number of other sites, any of which could lead to hijacking the password). Other means will just make you think that your application is more secure than it is and make you less vigilant.
Consider using SRP.
But that still won't help if a man in the middle sends you evil javascript than simpy sends a copy of your password to the attackers server.
Despite all the advices to use SSL/https/etc. I decided to implement my own security layer on top of http for my application... The concept works as follows:
User registers -> a new RSA Keypair is generated
the Private Key gets encrypted with AES using the users login Password
(which the server doesnt know - it has only the sha256 for authentication...)
Server stores the hash of the users password
and the Encrypted Private Key and Public Key
User logs in -> authenticates with nickname+password hash
(normal nick/password -> IP-bound sessionid authentication)
Server replies: sessionid, the Encrypted RSA Private Key
and an Encrypted randomly generated Session Communication Password
Client decrypts the RSA Private Key with the users Password
Client decrypts the Session Communication Password with the RSA Private Key
---> From this point on the whole traffic gets AES-encrypted
using that Session Password
I found no hole in that chain - neither the private key nor the login password get ever sent to the server as plaintext (I make no use of cookies, to exclude the possibility of the HTTP Cookie header to contain sensitive information)... but I am biased, so I ask - does my security implementation provide enough... security?
Why does everyone have to come up with their secure transport layer? What makes you think you've got something better than SSL or TLS? I simply do not understand the motivation to re-invent the wheel, which is a particularly dangerous thing to do when it comes to cryptography. HTTPS is a complex beast and it actually does a lot of work.
Remember, HTTPS also involves authentication (eg: being able to know you are actually talking to who you think you are talking to), which is why there exists a PKI and browsers are shipped with Root CA's. This is simply extremely difficult (if not impossible) to re-invent and prone to security holes. To answer you question, how are you defending against MITM attacks?
TLDR: Don't do it. SSL/TLS work just fine.
/endrant.
I'm not a crypto or security expert by any means, but I do see one serious flaw:
There is no way the client can know that it is running the right crypto code. With SSL/TLS there is an agreed upon standard that both your browser vendor and the server software vendor have implemented. You do not need to tell the browser how SSL works, it comes built in, and you can trust that it works correctly and safely. But, in your case, the browser only learns about the correct protocol by receiving plain-text JavaScript from your server.
This means that you can never trust that the client is actually running the correct crypto code. Any man-in-the-middle could deliver JavaScript that behaves identically to the script you normally serve, except that it sends all the decrypted messages to the attacker's servers. And there's no way for the client to protect against this.
That's the biggest flaw, and I suspect it's a fatal flaw for your solution. I don't see a way around this. As long as your system relies on delivering your crypto code to the client, you'll always be susceptible to man-in-the-middle attacks. Unless, of course, you delivered that code over SSL :)
It looks like you've made more complexity than is needed, as far as "home-grown" is concerned. Specifically, I see no need to involve assymetric keys. If the server already knows the user's hashed password, then just have the client generate a session id rolled into a message digest (symmetrically) encrypted via the client's hashed password.
The best an attacker might do is sniff that initial traffic, and attempt a reply attack...but the attacker would not understand the server's response.
Keep in mind, if you don't use TLS/SSL, then you won't get hardware-accelerated encryption (it will be slower, probably noticeably so).
You should also consider using HMAC, with the twist of simply using the user's password as the crypto key.
SSL/TLS provide transport layer security and what you've done does nothing but do that all over again for only the authorization process. You'd be better served to focus on authorization techniques like client certificates than to add an additional layer of line-level encryption. There's a number of things you could also introduce that you haven't mentioned such as encrypted columns in SQL Server 2008, IPSec, layer 4 & 7 hardware solutions and even setting up trusts between the server and client firewalls. My biggest concern is how you've created such a deep dependency on the username and password, both which can change over time in any system.
I would highly recommend that you reconsider using this approach and look to rely on more standard techniques for ensuring that credentials are never stored unencrypted on the server or passed in the clear from the client.
While I would also advocate the use of SSL/TLS for this sort of thing, there is nothing wrong with going re-inventing the wheel; it leads to innovation, such as the stack exchange series of websites.
I think your security model is quite sufficient and rather intelligent, although what are you using on the client-side? I'm assuming javascript since you tagged this post with 'web-development'? Or are you using this to communicate with a plug-in of sorts? How much overhead does your implementation produce?
Some areas of concern:
-How are you handling initial communication, such as: user login, registration?
-What about man-in-the-middle attacks (assuring the client that it is talking to the authorized server)?
The major problem you have is that your client crypto code is delivered as Javascript over unauthenticated HTTP.
This gives the Man-In-The-Middle plenty of options. He can modify the code so that it still authenticates with your server, but also sends the password / private key / plaintext of the conversation to him.
Javascript encryption can be enough when your adversary is an eavesdropper that can see your traffic but not modify it.
Please note that I am not referring to your specific idea (which I did not take the time to fully understand) but to the general concept of Javascript encryption.
Many users – myself included – would like the security of having everything they do on a web service encrypted. That is, they don't won't any one at the web service to be able to look at their: posts, info, tasks, etc...
This is also major complaint in this discussion of an otherwise cool service: http://news.ycombinator.com/item?id=1549115
Since this data needs to be recoverable, some sort of two-way encryption is required. But unless you're prompting the user for the encryption key on every request, this key will need to be stored on the server, and the point of encrypting the data is basically lost.
What is a way to securely encrypt user data without degrading the user experience (asking for some key on every request)?
-- UPDATE --
From #Borealid's answer, I've focused on two possibilities: challenge-response protocols, where no data (password included) is sent in the "clear", and non-challenge-response protocols, where data (password included) is sent in the "clear" (although over HTTPS).
Challenge-response protocols (specifically SRP: http://srp.stanford.edu/)
It seems that its implementation would need to rely on either a fully AJAX site or using web storage. This is so the browser can persist the challenge-response data during encryption and also the encryption key between different "pages". (I'm assuming after authentication is completed I would send them back the encrypted encryption key, which they would decrypt client-side to obtain the real encryption key.)
The problem is that I'm either:
fully AJAX, which I don't like because I love urls and don't won't a user to live exclusively on a single url, or
I have to store data encryption keys in web storage, which based on http://dev.w3.org/html5/webstorage/ will persist even after the browser is closed and could be a security vulnerability
In addition, as SRP takes more than one request ( http://srp.stanford.edu/design.html ), there needs to be some persistence on the server-side. This is just another difficulty.
Traditionally
If I'm ok transmitting passwords and data in the clear (although over HTTPS), then the client-side issues above are not present.
On registration, I'll generate a random unique encryption key for the user, and encrypt it using their password and a random salt.
In the database, I'll store the user's password hash and salt (through bcrypt), encrypted encryption key, encryption key salt, and encryption iv.
After an authentication, I'll also need to use their password to decrypt the encryption key so that they may view and enter new data. I store this encryption key only temporarily and delete it when they explicitly "log out".
The problems with this approach is that (like #Borealid points out) evil sysadmins can still look at your data when you are logged in.
I'm also not sure how to store the encryption keys when users are logged in. If they are in the same data store, a stolen database would reveal all data of those who were logged in at the time of theft.
Is there a better in-memory data store for storing these encryption keys (and challenge data during an SRP authentication)? Is this something Redis would be good for?
If the data need to be recoverable in the event of user error, you can't use something like a cookie (which could get deleted). And as you point out, server-side keys don't actually secure the user against malicious sysadmins; they only help with things like databases stolen offline.
However, if you're running a normal web service, you've already gotten pretty lucky - the user, in order to be unique and non-ephemeral, must be logged in. This means they go through some authentication step which proves their identity. In order to prove their identity, most web sites use a passed credential (a password).
So long as you don't use a challenge-response authentication protocol, which most web sites don't, you can use an encryption key derived from a combination of a server-side secret and the user's password. Store the encryption key only while the user is authenticated.
If you do this, the users are still vulnerable to sysadmins peeking while they're using the service (or stealing their passwords). You might want to go a step further. To go one up, don't send the password to the server at all. Instead, use a challenge-response protocol for authentication to your website, and encrypt the data with a derivative of the user's password via JavaScript before uploading anything.
This is foolproof security: if you try to steal the user's password, the user can see what you're doing because the code for the theft is right there in the page you sent them. Your web service never touches their data unencrypted. This is also no hindrance to the normal user experience. The user just enters their password to log in, as per normal.
This method is what is used by Lacie's storage cloud service. It's very well done.
Note: when I say "use foo to encrypt", I really mean "use foo to encrypt a secure symmetric key which is then used with a random salt to encrypt". Know your cryptography. I'm only talking about the secret, not the methodology.
None of those other solutions are going to maintain the feature set requested -- which specifically wants to preserve the user experience. If you look at the site referenced in the link, they email you a nightly past journal entry. You're not going to get that with JavaScript trickery per above because you don't have the browser to depend on. So basically this is all leading you down a path to a degraded user experience.
What you would want, or more precisely the best solution you're going to find in this space, is not so much what wuala does per above, but rather something like hush.com. The handling of user data needs to be done on the client side at all times -- this is generally accomplished via full client-side Java (like the Facebook photo uploader, etc), but HTML/JavaScript might get you there these days. JavaScript encryption is pretty poor, so you may be better off ignoring it.
OK, so now you've got client-side Java running a Journal entry encryption service. The next feature was to email past journal entries to users every night. Well, you're not going to get that in an unencrypted email obviously. This is where you're going to need to change the user experience one way or the other. The simplest solution is not to email the entry and instead to provide for instance a journal entry browser in the Java app that reminds them of some old entry once they get to the website based on a link in the daily email. A much more complex solution would be to use JavaScript encryption to decrypt the entry as an attachment inline in the email. This isn't rocket science but there is a fairly huge amount of trickery involved. This is the general path used by several web email encryption services such as IronPort. You can get a demo email by going to http://www.ironport.com/securedemo/.
As much as I'd love to see a properly encrypted version of all this, my final comment would be that journal entries are not state secrets. Given a solid privacy policy and good site security semantics, I'm sure 99% of your users will feel just fine about things. Doing all this right with true security will take an enormous amount of effort per above and at least some design/UE changes.
You should look into the MIT project CryptDB which supports querying an encrypted database using a subset of SQL. (see the forbes article, mefi thread, or Homomorphic encryption on wikipedia)
There is the Tahoe-LAFS project for cloud storage too, which conceivably could be leveraged into a fully anonymous social networking application, one day in the distant future.
If you want to perform computations on a server without even the server being able to see the data, you may be interested in knowing about fully homomorphic encryption. A fully homomorphic encryption scheme lets you perform arbitrary computations on encrypted data, even if you can't decrypt it. However, this is still a topic of research.
For now, I guess your best bet would be to encrypt all posts and assign meaningless (e.g. sequential) IDs to each one. For a more in-depth discussion of how to encrypt server-side data with today's technology, look up.