I'm using a local storage value to check whether a user is logged into my Chrome extension.
Can users edit their own local storage values? If I were to use their user ID in my database, I wouldn't want them to be able to log in as something else just by editing that ID, e.g. incrementing by 1.
Should it be something that the user shouldn't be able to see? I also considered using their salt, but I might not want to reveal that to the user.
You are right to be concerned. Generally, client-side code and data can't be trusted because it's in the hands of the attacker. The question is identical to the problem faced with web cookies: a browser can report anything at all as cookie data, so the server can't trust it. You have two general options to get around this problem. One is an HMAC, and the other is public-key signatures. Both require a server, but only the latter can verify without a server.
An HMAC requires that the secret remain inaccessible to the attacker at all times, but it's required for both generation and authentication (that is, that it stay on the server and be verified on the server). You haven't given us enough information to tell whether your extension is appropriate for this use case. Most industrial-strength cookies these days use some variant of an HMAC.
Public-key signatures require that the signing be done in secret (that is, on the server), but after that point the client can verify it without talking to the server.
The big problem that you'll face with any of these schemes is that two people can collude to copy one person's credentials to another machine, or one person can steal another person's credentials. Again, with client-side code you can't really trust anything. But either of these schemes prove that an attacker didn't make up login credentials entirely on his or her own.
Think of this problem as a web cookie problem. However you solve that problem, you can also apply it to chrome.storage.
Related
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.
I have a simple site with a sign-up form. Currently the user can complement their registration with (non-critical, "low security") information not available at the time of the sign-up, through a personal (secret) URL.
I.e., once they click submit, they get a message like:
Thanks for signing up. You can complement your registration by adding information through this personal URL:
http://www.example.com/extra_info/cwm8iue2gi
Now, my client asks me to extend the application to allow users to change their registration completely, including more sensitive information such as billing address etc.
My question: Are there any security issues with having a secret URL instead of a full username / password system?
The only concern I can come up with is that URLs are stored in the browser history. This doesn't worry me much though. Am I missing something?
It's not the end of the world if someone changes some other users registration info. (It would just involve some extra manual labor.) I will not go through the extent of setting up https for this application.
This approach is not appropriate for sensitive information because it's part of the HTTP request URL, which is not encrypted and shows up in many places such as proxy and other server logs. Even using HTTPS, you can't encrypt this part of the payload, so it's not an appropriate way to pass the token.
BTW, another problem with this scheme is if you send the URL to the user via email. That opens up several more avenues for attack.
A better scheme would require some small secret that is not in the email. But it can be challenging to decide what that secret should be. Usually the answer is: password.
Another potential problem lies with the users themselves. Most folks realize that a password is something they should try to protect. However, how many users are likely to recognize that they ought to be making some sort of effort to protect your secret URL?
The problem here is that although it is hard to guess the URL for any specific user, given enough users it becomes relatively easy to guess a correct url for SOME user.
This would be a classic example of a birthday attack.
ETA: Missed the part about the size of the secret, so this doesn't really apply in your case, but will leave the answer here since it might apply in the more general case.
can complement their registration with (non-critical, "low security") information
It's hard to imagine what user-supplied information really is "low-security"; even if you are asking for a password and a username from your customers you are potenitally violating a duty of care to your customers; a large propertion of users will use the same username/password on multiple sites. Any information about your users and potentially a lot of information about transactions can be used by a third party to compromise the identity of that user.
Any information about the user should be supplied in an enctypted format (e.g. via https). And you should take appropriate measures to protect the data you store (e.g. hashing passwords).
Your idea of using a secret URL, means that only you, the user, anyone on the same network as the user, in the vicinity of a user on wifi, connected to any network between you and the user, or whom has access to the users hardware will know the URL. Of course that's not considering the possibility of someone trying a brute force attack against the URLs.
C.
The secret URL means nothing if you're not using SSL. If you're still having the end-user transmit their identifying information across the Internet in the clear, then it doesn't matter how you're letting them in: They are still exposed.
The "secret URL" is often referred to as security by obscurity. The issue is that it is super simple to write a script that will attempt various combinations of letters, symbols, and numbers to brute force hack this scheme.
So if any sensitive information is stored you should definitely use at least a username and password to secure it.
So lets say i have a member base website and when the user signs in i put put a cookie (or a session) with a key value pair remembering who the user is. But its just come to my attention which information i should use to remember the user so that its secure. I cant use username=username or user_id = user_id (because my user_id will be 1), because people then can just simply guess what the cookie values are and logged in as that user. So what key/value pair should i use to be able to identify users and still connect their information to the database securely? Thanks.
Ben, there are a few different types of attacks you need to be concerned with. For example simply encrypting the identifier with a private key doesn't prevent someone who can intercept the encrypted value from simply replaying it to your server (and appear to be the user). Some common security risks are detailed here (and in associated links at bottom of this page):
https://www.owasp.org/index.php/Session_hijacking_attack
Session management can be quite complex and depending on the level of security you require, it is not something you want to tackle yourself, because likely your development environment / framework already has a solution that has been vetted moreso than a homebrew solution. Here is a link detailing some things to consider, unfortunately this topic has more to it than a simple Stack Overflow post:
https://www.owasp.org/index.php/Session_Management
If you dont prefer encryption for whatever reason, then a simpler solution could be to use a GUID to identify the user. This way, a hacker would have to launch a denial of service kind-of attack on your application to be able to run through even a very small fraction of the GUIDs.
If you want to do this properly, then you should have a look at http://jaspan.com/improved_persistent_login_cookie_best_practice also.
I'm definitely not an expert in security, but I have recently implemented user management tool and I have done the following.
Don't use encryption, its slow and most of the time for simple implementation its just a waste of time.
Here is what you do need to store on the server - in order to authenticate each request.
UserId (obvious)
CookieHash (made out of userId, some secret private key and crypto randomly generated number)
LastLogin
SessionRenewed (useful for when to cancel someone's session eg. renew cookieHash every 10 min, otherwise log out user)
LastIP
What I store in cookie is following
UserId
CookieHash
How to use this basic security
Simply when user logs in you check username/password etc. (just the usual) If everything is fine then log in user and generate new cookiehash and fill those values given above.
Every request check UserId against its hash. If someone gave UserId = 4 but hash didnt match then automatically drop a session and forward user to login screen. Possible log is good to see how often people try to play around with your hard work.
I hope this helps.
You can just encrypt the user id with a private encryption key that you keep on the server. There are a few things to watch out for with this approach:
Every call to the server will require you to decrypt the cookie to get the id of the user. This will add overhead to each request.
If the key is ever compromised, you will be forced to abandon the current name for the cookie you use and use another encryption key when assigning to the new cookie name; this will cause the user to have to re-login, of course.
While I don't think that these are major hurdles, they might be to you, and you would have to evaluate the impact on your site for yourself.
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.
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.