How can I safely get user passwords to the back end without HTTPS? - security

I'm trying to get a hobby/educational project off the ground that involves user accounts. Naturally, it will be critical for users to be able to log in securely. The information I will be storing and transporting for users is not intended to be personal or personally identifiable, but just on principle I'd like password transport to be as secure as possible.
I understand that the best way to get the user's password safely to the back end from the front is by using HTTPS. However, I don't want to pay for a CA for this learning/experiment project, and I also don't want to get browser warnings for self-signed certs, because though this is a hobby project, I would ultimately like to share it with the world (like a portfolio piece, something to share with friends, for people to actually find useful and fun).
Granted, you'd be right to say that if I want it to be a "portfolio piece," I should use best practices such as HTTPS, but I still don't want to pay an annual CA fee for what ultimately is a hobby/learning project.
I'm considering the asymmetric cryptography solution found here: https://github.com/travist/jsencrypt It's quite like the one suggested by ArthuruhtrA, and seems promising. It uses public/private key, so I could encrypt using public key on the front end, and transport encrypted to be decrypted on the back end with a secret/private key (where proper salting/hashing practices would occur before storage to a database). Does this seem reasonably safe, if untraditional?
Is there any other, better way to get user information (e.g. password) safely to the back end without browser warnings and without spending money needlessly?

If you use encrypted password from JavaScript it cannot be well secure since it is only client side customisation, i.e. it is not à service provided by the browser.
I would advise you to use TLS with a free certificate. You should have à look at letsencrypt.org.

I don't know what the best answer to this is. Obviously you've considered using a self-signed cert. I may be wrong, but depending on the OS and browser, you may be able to tell it to trust certs you have signed.
Another solution might be to use the asymmetric cryptography principle behind HTTPS, but without actually using SSL: Include your server's public key in your webpage. Use javascript to encrypt the data with it. Your server would then be able to decrypt it using its private key, without a middleman being able to do so.
Hope that helps! If I come up with something else I'll add it here.
Edit:
On second thought, this solution would be super vulnerable to a man-in-the-middle attack. Sorry.

Related

Mobile API Security Paradigm

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.

Ciphertext on server

Are there any protocols which would allow 2 visitors to communicate securely through my website, without the possibility of me reading their messages?
Ask Google for End-to-End encryption like PGP/GPG. For a client-side browser-based implementation you might want to check out GPG encryption in JavaScript.
I just googled it and cannot tell if its really secure (not sending your private key to anyone). I just want to give you a point to start with.
EDIT: Looks like it does send the clients private key to your server to perform a server-based encryption. This is not what you want. But I am sure that a JavaScript implementation of GPG is possible even though I don't know if somebody has done it yet.
Yes; for example, this is what would happen if your server was a link in a communication protected by SSL/TLS.
The participants use a public-key encryption scheme to agree upon a secret, symmetric key; that is then used to encrypt their communication.
It's also possible for the participants to simply encrypt their messages with the public key of the intended receiver. That way, only the intended receiver can decrypt the message. This is not a very advanced scheme and probably vulnerable. (Among others, if an eavesdropper can guess exactly what is sent, he can encrypt that message with the intended recipient's public key and see if the result matches with what is being sent).
There is a lot of literature available on cryptographic protocols; for starters, here's a Wikipedia article on Key Agreement Protocols.
If we're talking about not possible then the second part to S.L. Barth's answer will achieve this with the exception that the key exchange must be done by some other means. This can be the phone or email or even another website but if it's done via your website then it's open to a man-in-the-middle attack. You can tell your users to do this, you just can't actually help them do it.
There is probably a javascript library somewhere that will implement GPG encryption so that all you have to do is make sure that every message is encrypted in the browser before it's sent to your web server. You can store the messages as long as you like, they're encrypted. Only the user with the correct private key will be able to decrypt it.
SSL and TLS as they are used by websites everywhere are vulnerable to man-in-the-middle attacks. The reason we don't hear much about these sorts of attacks is that most of the people in the middle are trustworthy so the attacks simply don't happen. The recent revoking of the CA certificates of DigiNotar and others was precisely because the Iranian Government were caught acting as a man-in-the-middle and decrypting their own citizen's SSL traffic.
If you're happy with preventing casual snooping by curious sysadmins, the key exchange can be done through your website as well.
One more thing: Security is hard.
Even if you do this with well-known encryption techniques, the chances of there being a flaw in the implementation will be very close to 1. This doesn't mean that those curious sysadmins will be able to accidentally read messages but it does mean that a determined and skilled adversary will be able to find a way in. As soon as you can afford it you should hire an expert to redesign or at the very least examine your protocol and implementation.
In general, such a secure link between your users without you being able to read and/or modify their messages is only possible if they have some way of identifying each other (or at least in one direction).
This might be a shared secret (like a passphrase) or a public key known to one (or certified by a CA known to one), where the other one has the corresponding private key.
On this one can build a secure protocol (using a key exchange and then symmetric encryption with MACs in both directions), like TLS does. (Another way, used often for instant messaging, is OTR, the Off-the-Record messaging protocol.)
Without a way to identify the other end point, you end up with a way of allowing man-in-the-middle attacks. SSL/TLS without certificates, or with certificates where the man-in-the-middle knows the corresponding private key, is insecure, as is every other similar encryption scheme.
Another issue is that you said visitors of my website. This looks like you would implement client-side cryptography in JavaScript, delivered from your website. Don't do this ... if the visitors do not trust you not to read their data, they also should not trust you to feed them non-malicious JavaScript, which might implement something else than you are claiming it does, again allowing a MITM, or even directly sending a copy of the data to you.
More details about this are discussed in Javascript Cryptography Considered Harmful (from a slightly different perspective).

GWT/Javascript client side password encryption

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.

Backwards HTTPS; User communicates with previously generated private key

I am looking for something like https, but backwards. The user generates their own private key (in advance) and then (only later) provides the web application with the associated public key. This part of the exchange should (if necessary) occur out-of-band. Communication is then encrypted/decrypted with these keys.
I've thought of some strange JavaScript approaches to implement this (From the client perspective: form submissions are encrypted on their way out while (on ajax response) web content is decrypted. I recognize this is horrible, but you can't deny that it would be a fun hack. However, I wondered if there was already something out there... something commonly implemented in browsers and web/application servers.
Primarily this is to address compromised security when (unknowingly) communicating through a rogue access point that may be intercepting https connections and issuing its own certificates. Recently (in my own network) I recreated this and (with due horror) soon saw my gmail password in plain text! I have a web application going that only I and a few others use, but where security (from a learning stand point) needs to be top notch.
I should add, the solution does not need to be practical
Also, if there is something intrinsically wrong with my thought process, I would greatly appreciate it if someone set me on the right track or directed me to the proper literature. Science is not about finding better answers; science is about forming better questions.
Thank you for your time,
O∴D
This is already done. They're called TLS client certificates. SSL doesn't have to be one-way; it can be two-party mutual authentication.
What you do is have the client generate a private key. The client then sends a CSR (Certificate Signing Request) to the server, who signs the public key therein and returns it to the client. The private key is never sent over the network. If the AP intercepts and modifies the key, the client will know.
However, this does not stop a rogue AP from requesting a certificate on behalf of a client. You need an out-of-band channel to verify identity. There is no way to stop a man in the middle from impersonating a client without some way to get around that MITM.
If a rogue access point can sniff packets, it can also change packets (an ‘active’ man-in-the-middle attack). So any security measure a client-side script could possibly provide would be easily circumvented by nobbling the script itself on the way to the client.
HTTPS—and the unauthorised-certificate warning you get when a MitM is trying to fool you—is as good as it gets.
SSL and there for HTTPS allows for client certificates. on the server side you can use these environment variables to verify a certificate. If you only have 1 server and a bunch of clients then a full PKI isn't necessary. Instead you can have a list of valid client certificates in the database. Here is more info on the topic.
Implementing anything like this in JavaScript is a bad idea.
I don't see, why you are using assymetric encryption here. For one, it is slow, and secondly, it is vulnerable to man in the middle anyhow.
Usually, you use an asymmetric encryption to have a relatively secure session negotiation, including an exchange of keys for a symmetric encryption, valid for the session.
Since you use a secure channel for the negociation, I don't really understand why you even send around public keys, which themselves are only valid for one session.
Asymmetric encryption makes sense, if you have shared secret, that allows verifying a public key. Having this shared secret is signifficantly easier, if you don't change the key for every session, and if the key is generated in a central place (i.e. the server and not for all clients).
Also, as the rook already pointed out, JavaScript is a bad idea. You have to write everything from scratch, starting with basic arithmetic operations, since Number won't get you very far, if you want to work with keys in an order of magnitude, that provides reasonable security.
greetz
back2dos

Which attacks are possible concerning my security layer concept?

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.

Resources