I'm writing Baby's First Web Application. My first task has been to set up an authentication system, which I think I've done okay on. I'm new to the whole thing, though, so:
When the user reports that he's forgotten his password, I e-mail him a temporary replacement password in plain text. It's perhaps not the most secure way to handle the situation, but it's how I do it for now. I do force him to change it at the next login, and the technique I use is to carry a "must-change" field in the database, set to true for users who've been sent the e-mail.
My question: Is a separate database column the best tactic under the circumstances, or is there something better I can do?
A separate column is quite reasonable.
Operating systems typically have a "password expiration timestamp" field which doubles as a "must change at next logon" flag simply by setting the timestamp to 0 (AKA January 1, 1970). Web sites do not usually have password expiration dates, in which case a plain boolean flag suffices.
I presume you are storing passwords hashed and salted. If not, do so. If so, you could store meta-data in the salt. E.g. the salt is [0-9a-z]{8}, but for temp passwords it is ____[0-9a-z]{4}. (before downvoting, people, read on!) The point in this, is that a separate field might get edited separately from the hash field. Of course that should never happen, but it can happen. (failing queries, moronic sysadmins, people who have discovered phpmyadmin and think they understand the system, etc) Keeping the "state" of the password in the salt, prevents such mayhem: on validation of the password, you will always be able to see that you validated against a temp password, and you will always be able to identify the user who needs to get a "enter new password" prompt.
My practice has always been to overload the email validation (where you send an email to the registrant to make sure that the registrant owns the address) to also function as a password reset mechanism. I use certain information about the user (username, id, email, and importantly, the current password hash in DB) to make a hash, which is included in a URL that's emailed to the user, at which point they can set a new password of their choosing.
That being said, the "best practice" vis-a-vis user authentication is 95% of the time to user a library that someone else has written and tested extensively. Just search Google for one that's appropriate for your framework.
Related
So I am encrypting fields in the database, but I don't think i can encrypt the user's username or email because I use those fields to find the user. I could hash them instead, but since I don't think I can use a unique salt per username/email someone could just use a rainbow table to find the hidden username/email.
I guess this it is ok to not encrypt them? I would like to make the website as secure as possible. Would hashing them make sense? I could find a user by their _id instead of username/email, but I wouldn't have their _id until I find the user.
What I am doing currently:
const user = await new db.userModel({
email: email,
username: username,
stuff: cryptr.encrypt(stuff),
});
////
const user = await db.userModel.findOne({
email: email
}).exec();
EDIT: I guess hashing would not make sense, since I cannot un-hash the username/email. Not sure what I was thinking.
This question should really be asked on infosec Stackexchange.
Encryption is usually pointless as a defense against hackers, because you need to access the key to use the encrypted database. That means that you need to save it next to the database. If your server becomes compromised, then the hacker will simply decrypt the database with the key. Of course it's better than doing nothing, because it is possible (maybe improbable) that the hacker will compromise only the database. Horatiu Jeflea hovewer mentions other important reasons to encrypt the database, which you should especially consider if you are not working on the project alone.
Hashing usernames is only possible if you don't need to display them, but usernames are usually public anyway, so it improves security very little.
Hashing emails is an interesting problem. You asked for them for a reason. You presumably need to contact your users. If you hash them, you won't be able to do it and if you don't need to do it, then you don't need to (and shouldn't) save them in the first place. If however they are only part of the authentication process, then it would be possible solution.
Rainbow tables can't really break modern hashing algorithms, although the biggest mitigation is aforementioned salt, which will make it MUCH harder for most attack on the hash. You also have to make sure that you are not using vulnerable ones like md5, but safe one like sha256 or sufficient bcrypt. You should hash the passwords with one of those. Also note that you could use the same salt for all the hashed fields and the salt could even be (this would reduce the security little bit) one of the public fields (username?). There are very little excuses for not using salt.
In summary: you can't hash them and encryption is probably not worth it unless you can sufficiently isolate the key, or need it because of something else than external hackers
I guess this it is ok to not encrypt them?
In most cases, yes. Passwords should be hashed (+ salt..) and sensitive data should be encrypted. But username or email in most cases should not be sensitive.
But let's assume they will be encrypted in DB.
You are storing encrypt(username) in your DB, so in order to search for that, instead of using username, use encrypt(username). Of course sorting may cause some headaches, but finding the user should be efficient.
Think of encrypting (in your case) not about hackers, but about people who are reading those records. For example developers who are investigating a production issue or a DBA, you want some (not all) fields hard for them to read. Storing the key on a different machine, best in a Key Management Tool, will add an extra security layer.
I am new to web development and database and am trying to implement password authentication with reasonable security and speed. I have read about hashing the password and append a salt unique to each user in order to deter people from generating rainbow tables.
My question deals with the time I have to search in order to verify a user. Since I don't know who is trying to connect at any given time, it seems to me that I would need to retrieve every field from the salt column then hash the submitted password + each unique salt and then finally compare each output to the hashed strings in the table?
So I have to submit a separate query for each combination of hash(password+salt)? That seems like it would be awfully slow. Am I missing a trick that would speed up the process? Or is it simply a matter of sucking it up and sacrificing speed for better security? Or am I mistaken and with the speed of today's computers it isn't an issue at all?
You cannot authenticate the user based only on a password. Password is a verification that the user is who they say they are, so you need some sort of user identifier — name or whatever. Table then looks like users(..., name, password, ...), you do SELECT password WHERE name = "foo" and proceed with verification from there. Convenient form is to keep all parameters needed to generate derived key inside the password field, e.g. like this:
algo$salt$password hash
For hashing itself, you don't want it to be fast — see key derivation functions like PBKDF2, bcrypt or scrypt. In general, tuning the parameters so that it takes about a second to derive one key is a nice way to make brute forcing infeasible.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is it possible to decrypt md5 hashes?
In my website, I'm using md5 encryption for the password. So it's saving in the encrypted form in the database. For doing the password recovery, how can I decrypt the encrypted password ??
Please Help :)
As others described quite well, you cannot easily 'decrypt' an MD5 hash.
I guess the best way to do your password recovery is like this:
A user can request password recovery
by providing his email address (it should be unique so users can be identified by email address).
an email is sent to his address with a
link containing a unique hash (which
you have generated when sending the
email and saved it to the db).
when the link is clicked by the user (and
of course the unique hash is checked
to be equal with the one in the db)
you can show a form which lets them
choose a different password.
Another route that some people use is to simply ask for the email address, generate a new password and send it to the user. The problem with this one is that someone who knows only your email address can request a password change. He won't know the new pass, and you will get it by email, but still it is very inconvenient for the user.
MD5 is a hash-based encryption. What that means, is that there is no way to get back the original value. You have created something that is a "checksum" of the original data. You can use the MD5 algorithm to encrypt something else, and then compare that to the MD5'd version of the data, but you can never get back the original.
It would be similar to me saying: 5 + 3 + 2 = 10. The original data is 5, 3, and 2. But the "hash" is 10. There is no way to get the original data from the hash, but if someone supplies the correct input ( 5, 3, 2 ), I can hash it, and confirm that it matches hash that I have on file, 10.
I think MD5 is a one way hashing algorithm. What that means is that once you encrypt it, the data cannot be decrypted. (I'm sure a good hacker will disagree though)
Anyways, for passwords you can save the encrypted version of the password in the database. When a user attempts to log in, encrypt the entered password using the same MD5 algorithm, and compare the encrypted version of the password against the encrypted password stored in the database.
Once you're comfortable with this approach, you can start looking at the concept of adding salt to the hashed password.
Also, there are other hashing algorithms than just MD5. If you're using .NET, there's a bunch in the framework, such as SHA512Managed. Each one has its trade offs, such as speed to hash, security, etc. Pick one that fixes your particular problem.
You can't decrypt a md5 password! The only way would be to brute force it!
If you want to do password recovery make a random string witch will be sent to the user by email (or any other way) and set as a md5'd password... Just an idea
EDIT:
Why would you encrypt a password to keep it safe if you can decrypt it? Makes no sense! -> You could the basically leave the password unencrypted!
It's not easy, but you're best bet would be to use a rainbow table as the MD5 has does have vulnerabilities.
There are several online versions, which you may or may not be able to trust (or work).
You can try to search in a MD5 hash database like:
http://www.md5-hash.com/
http://www.md5decrypter.com/
others....
Chances are small but you can try.
I've just signed up to a site to purchase some goods, and when I tried to enter my (reasonably secure) password I was informed it was too long, and that I should enter a password between 5 & 10 characters! What is the point in that? Who makes decisions like this? Surely the ideal password would be a really long and complicated one? Why do people insist on trying to restrict what types of passwords you can use?
Have you had to implement a login to a website? Was the login for secure purposes (e.g. purchasing goods). What (if any) restrictions did you place on the user's password? What were your reasons for the decision?
Restricting the size of a password is an attempt to save storage space. It pretty much indicates that your password is being stored plainly in their database, so they want to restrict its size. Otherwise it's just a restriction because the implementors don't know any better. Either way it's a bad sign.
You might want to contact the admins of the site and ask them about it. They should be storing hashes, not passwords, which are always the same size no matter how big the password is. There really should be no limit to the size of password you enter, nor the domain of characters you're permitted to input.
The most common reason for this is because the front-end intgrates with some old legacy system that does not handle more than a given number of characters.
Seems especially stupid, given that any half decent website does not store plaintext passwords in their database, they store a one way hash of that password (which will always be a set length depending on the algorithm used, for example sha1 is a 160 bit digest) and then rehash that password on login to make sure that the newly hashed password matches the stored one.
Other than for frontend design asthetics - I agree, it doesn't make any sense to enforce a maximum password length. Minimum length is entirely different though for obvious reasons.
The length restriction is probably due to a storage space concern, but it might be a really bad anti-scripting measure. I'd be a lot more confident if my bank told me my password was too short, rather than too long. Whenever I'm told my password is too short, or "special" characters are not allowed I think, "Oh, they must not have found my password in their dictionary... facepalm."
Any characters should be allowed. Pass phrases should be encouraged, not discouraged. They're much easier to remember than cryptic passwords and much harder to crack since they won't be in a lookup table.
Some (poorly designed) websites have maximum password lengths for a simple reason: that's all the space they have in their database to store your password. There's a good chance they're not hashing it or processing it at all, meaning it's stored in plain text. Websites like that I use one use, throw-away passwords for every time. It's a poor design, and it's unfortunate that people still use it.
It could be that the algorithm they use for encryption doesn't work well with large passwords or that they only have limited storage to store it. Both are very poor reasons, I know, but it's possible.
If I were to make password rules, it would only be things to protect users, like forcing them to use at least one special character and number or mixing lower and upper case.
It could be because they are storing your password as plain text and are trying to save space, but it might also be to try and stop people making their passwords really long and then forgetting them, which means that the company has to send an email with your password, which is a bit of a hassle.
The only possible reason to limit a password in that manner would be to simplify the database table, and that's a bad reason. Long, complicated passwords should be allowed!
Futhermore, the site should not be storing the password at all, but rather storing a crypto hash. Since the hash is a fixed size, that makes the database very simple and storage requirements small.
I have read that using database keys in a URL is a bad thing to do.
For instance,
My table has 3 fields: ID:int, Title:nvarchar(5), Description:Text
I want to create a page that displays a record. Something like ...
http://server/viewitem.aspx?id=1234
First off, could someone elaborate on why this is a bad thing to do?
and secondly, what are some ways to work around using primary keys in a url?
I think it's perfectly reasonable to use primary keys in the URL.
Some considerations, however:
1) Avoid SQL injection attacks. If you just blindly accept the value of the id URL parameter and pass it into the DB, you are at risk. Make sure you sanitise the input so that it matches whatever format of key you have (e.g. strip any non-numeric characters).
2) SEO. It helps if your URL contains some context about the item (e.g. "big fluffy rabbit" rather than 1234). This helps search engines see that your page is relevant. It can also be useful for your users (I can tell from my browser history which record is which without having to remember a number).
It's not inherently a bad thing to do, but it has some caveats.
Caveat one is that someone can type in different keys and maybe pull up data you didn't want / expect them to get at. You can reduce the chance that this is successful by increasing your key space (for example making ids random 64 bit numbers).
Caveat two is that if you're running a public service and you have competitors they may be able to extract business information from your keys if they are monotonic. Example: create a post today, create a post in a week, compare Ids and you have extracted the rate at which posts are being made.
Caveat three is that it's prone to SQL injection attacks. But you'd never make those mistakes, right?
Using IDs in the URL is not necessarily bad. This site uses it, despite being done by professionals.
How can they be dangerous? When users are allowed to update or delete entries belonging to them, developers implement some sort of authentication, but they often forget to check if the entry really belongs to you. A malicious user could form a URL like "/questions/12345/delete" when he notices that "12345" belongs to you, and it would be deleted.
Programmers should ensure that a database entry with an arbitrary ID really belongs to the current logged-in user before performing such operation.
Sometimes there are strong reasons to avoid exposing IDs in the URL. In such cases, developers often generate random hashes that they store for each entry and use those in the URL. A malicious person tampering in the URL bar would have a hard time guessing a hash that would belong to some other user.
Security and privacy are the main reasons to avoid doing this. Any information that gives away your data structure is more information that a hacker can use to access your database. As mopoke says, you also expose yourself to SQL injection attacks which are fairly common and can be extremely harmful to your database and application. From a privacy standpoint, if you are displaying any information that is sensitive or personal, anybody can just substitute a number to retrieve information and if you have no mechanism for authentication, you could be putting your information at risk. Also, if it's that easy to query your database, you open yourself up to Denial of Service attacks with someone just looping through URL's against your server since they know each one will get a response.
Regardless of the nature of the data, I tend to recommend against sharing anything in the URL that could give away anything about your application's architecture, it seems to me you are just inviting trouble (I feel the same way about hidden fields which aren't really hidden).
To get around it, we usaully encrypt the parameters before passing them. In some cases, the encyrpted URL also includes some form of verification/authentication mechanism so the server can decide if it's ok to process.
Of course every application is different and the level of security you want to implement has to be balanced with functionality, budget, performance, etc. But I don't see anything wrong with being paranoid when it comes to data security.
It's a bit pedantic at times, but you want to use a unique business identifier for things rather than the surrogate key.
It can be as simple as ItemNumber instead of Id.
The Id is a db concern, not a business/user concern.
Using integer primary keys in a URL is a security risk. It is quite easy for someone to post using any number. For example, through normal web application use, the user creates a user record with an ID of 45 (viewitem/id/45). This means the user automatically knows there are 44 other users. And unless you have a correct authorization system in place they can see the other user's information by created their own url (viewitem/id/32).
2a. Use proper authorization.
2b. Use GUIDs for primary keys.
showing the key itself isn't inherently bad because it holds no real meaning, but showing the means to obtain access to an item is bad.
for instance say you had an online store that sold stuff from 2 merchants. Merchant A had items (1, 3, 5, 7) and Merchant B has items (2, 4, 5, 8).
If I am shopping on Merchant A's site and see:
http://server/viewitem.aspx?id=1
I could then try to fiddle with it and type:
http://server/viewitem.aspx?id=2
That might let me access an item that I shouldn't be accessing since I am shopping with Merchant A and not B. In general allowing users to fiddle with stuff like that can lead to security problems. Another brief example is employees that can look at their personal information (id=382) but they type in someone else id to go directly to someone else profile.
Now, having said that.. this is not bad as long as security checks are built into the system that check to make sure people are doing what they are supposed to (ex: not shopping with another merchant or not viewing another employee).
One mechanism is to store information in sessions, but some do not like that. I am not a web programmer so I will not go into that :)
The main thing is to make sure the system is secure. Never trust data that came back from the user.
Everybody seems to be posting the "problems" with using this technique, but I haven't seen any solutions. What are the alternatives. There has to be something in the URL that uniquely defines what you want to display to the user. The only other solution I can think of would be to run your entire site off forms, and have the browser post the value to the server. This is a little trickier to code, as all links need to be form submits. Also, it's only minimally harder for users of the site to put in whatever value they wish. Also this wouldn't allow the user to bookmark anything, which is a major disadvantage.
#John Virgolino mentioned encrypting the entire query string, which could help with this process. However it seems like going a little too far for most applications.
I've been reading about this, looking for a solution, but as #Kibbee says there is no real consensus.
I can think of a few possible solutions:
1) If your table uses integer keys (likely), add a check-sum digit to the identifier. That way, (simple) injection attacks will usually fail. On receiving the request, simply remove the check-sum digit and check that it still matches - if they don't then you know the URL has been tampered with. This method also hides your "rate of growth" (somewhat).
2) When storing the DB record initially, save a "secondary key" or value that you are happy to be a public id. This has to be unique and usually not sequential - examples are a UUID/Guid or a hash (MD5) of the integer ID e.g. http://server/item.aspx?id=AbD3sTGgxkjero (but be careful of characters that are not compatible with http). Nb. the secondary field will need to be indexed, and you will lose benefits of clustering that you get in 1).