When building a web server the key features are: serving web pages, databases, user authentication, and cookies. To maintain all of the features of a web server, we must create secure environment, only allowing authorized moderators to edit features and the correct users to access their webpages. There are usually many different layers of security used to ensure the integrity of a web server. This article focuses on securing the access of user accounts, by ensuring passwords are defended against rainbow attacks.
A rainbow attack refers to a malicious individual more or less guessing users account passwords by using common password phrases such as “password,” “abc123,” etc. They do this by gaining access to a username then guessing a few hundred to thousand passwords. One way to achieve this is by accessing the passwords database and comparing the passwords.
The first layer of protection is encryption, or in this case hashing[1], which is used to ensure that each password is unique. Throughout this example SHA-2 will be used as the hashing method, there other methods can take the place of SHA-2 (please do not make it a less secure method). Often passwords will have layers of encryption, on top of hashing and this can improve security, however it will not be covered explicitly in the following example.
SHA-2
SHA-2 is defined as (via wikipedia):
SHA-2 is a set of cryptographic hash functions (SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256) designed by the U.S. National Security Agency (NSA) and published in 2001 by the NIST as a U.S. Federal Information Processing Standard (FIPS). SHA stands for Secure Hash Algorithm. SHA-2 includes a significant number of changes from its predecessor, SHA-1. SHA-2 currently consists of a set of six hash functions with digests that are 224, 256, 384 or 512 bits.
I recommend reading more about it if you are interested. Abridging a large portion of the “how it works,” the SHA-2 algorithm takes in a term and converts it to a string of characters:
Password -> e7cf3ef4f17c3999a94f2c6f612e8a888e5b1026878e4e19398b23bd38ec221a
The reason it works so well is the chances of a collision, meaning two input terms output the same stream of characters is extremely low. Further, Password and password produce entirely different strings:
Password: e7cf3ef4f17c3999a94f2c6f612e8a888e5b1026878e4e19398b23bd38ec221a
password: 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8
This is beautiful! It means each users password can differ by a single character and generate completely different results, ensuring a unique password stays unique.
Defense Against the Dark Arts
Following the “Building a Web Server in Go” theme, imagine we were building a website where users can add, save, download, and remove a list of books. To protect the private user accounts a package called “codify” will be used to encrypt of user passwords as well as usernames. We encrypt the username as well to ensure that a username cannot be easily identified even if an unauthorized individual gains access. Further, we attempt to separate the package from the databases to ensure that the package is as portable as possible, the one exception being the salt database.
The salt database contains a list of salts. A salt is a term, phrase, or (usually) a random set of characters which are added to a string intended to be encrypted. Salts one of the most important aspects of password security. Many users will create a password such as “password,” and if we simply used the SHA-2 algorithm on the term “password” every time a user chose “password” there would be a large number of similar entries. This would allow an unauthorized individual who gained access to the database (or even just make database calls) to quickly identify those users passwords obtaining access to many accounts.
If instead we salted each users password every password would look different. Salting ensures if an individual does gain access to the passwords database it would require orders of magnitude more work to obtain multiple users accounts (because they would have to “guess” each users password). Once more, if the salt is unique to each user a rainbow attack against the database would be ineffective, because common passwords would be made uncommon with the use of a salt.
Coding
The first step in developing the codify package is importing the “crypto/sha256” package for the SHA-2 algorithm and the “encoding/hex” package to encode the SHA-2 output to a string. In order to store/retrieve the data we keep the username and salt in a struct:
As you can see it is fairly straight forward and easy to use the SHA-2 algorithm given the Go packages provided. Once we have a function which can encrypt a given string, we can construct a function that given a password and username can add a salt and generate the SHA-2 output. We need the username because we will use the username to find the proper salt in the salt database. To protect exactly which salt belongs to which user I take a username add their password to it an use the SHA-2 algorithm. This provides us with an exceptionally long username in the salted database, which is itself salted making it unidentifiable (or at least very hard to identify). If a malicious entity made itself into the database the added difficulty of determining users would either thwart the effort entirely or give time to reissue salts.
The following function returns the user password after searching the salt database and applying it appropriately:
Once we have the ability to check a users password, the last step is issuing a unique salt to each user. In this case it is important to create a separate function that generates salts, this way we can update the salt database “at will.” Reissuing salts if there is a security issue or on a daily, weekly, monthly, or yearly basis can be an important security measure to ensure passwords remain secure. We generate a new salt every time the user logs into their account, however that would waste a significant amount of computation time and would not be worth the trouble (in my opinion).
The following function generates a salt for a given user and adds it to the salt database:
That’s it! Generating the salt using: SHA(string(rand(10000000)))[:12] is relatively expensive and pretty unnecessary, however for this example I felt it worked. The point being, you simply want your salt to be as random/diverse as possible in order to ensure the maximum amount of security.
If you wish to view the code associated with this post feel free to visit my github.
You should not salt passwords in this manner. Your salted passwords are now vulnerable to a length extension attack. http://en.wikipedia.org/wiki/Length_extension_attack
Instead, you should be using proper key-derivation functions, PBKDF2 or bcrypt or scrypt.
Thanks for the suggestion, I will update that at some point (when I get around to it)
This is a horribly dated guide. Don’t use SHA family hashes for passwords. Beginners really shouldn’t be teaching beginners, ESPECIALLY when it comes to security.
There are some significant security problems with your implementation.
While better than plain text storage, a single SHA-2 iteration by itself is still a poor choice for password hashing. It’s much too fast, allowing someone with offline hash access to very rapidly make lots of guesses at passwords, even with the salt. You need something with a higher difficulty.
Better hashing options would be scrypt, bcrypt, or PBKDF2 — and probably in that order. The big advantage for scrypt is that it can’t be parallelized over a GPU, making attacks more expensive.
Using string concatenation to combine the password and salt leaves you open to a length extension attack. (I don’t know if I can link here, so just look that up on Wikipedia.) This is especially true because you’re using SHA256, which is specifically vulnerable to this kind of attack. You should be using something like HMAC to combine these values.
Your salt table is a major weakness. You’re storing an unsalted username/password pairs in your database, completely subverting the whole point of using a salt! If an attacker gets this salt database then they don’t need to bother attacking the salted passwords. They already have everything they need. The problem is that you’re treating the salt as a secret value. It’s not. Its purpose is to make rainbow tables infeasible, which it does just fine when it’s unique per user and stored alongside the salted password hash. Your database tuple could safely be (user, hash, salt, iterations).
You didn’t get this far in your article, but it’s important to mention that when it comes time to authenticate the user, use a constant-time comparison function when comparing the hashes. That is, be sure your comparison function doesn’t bail out early at the first byte mismatch. For example, the C function memcmp() is not secure for this purpose because it’s not O(1). A variable comparison time would leak information to an attacker by revealing how much of the hash was matched. This could play right into the previously-mentioned length extension attack.
I notice from the comments that there are some opinions about the accuracy of this information. Do you have a response to that?
If I understand correctly, you are saying that people can type in their too-simple password (like “abc123”) and the program will recognize it as a string of random characters, which are nearly impossible for a hacker’s software to “guess?”
The way virtually all passwords are stored on the web are via the following steps (via a program):
1) User inputs password
2) A “Salt” is added to the password, essentially a string or phrase which is unique and alters the password to be new. Example: Password + Pepper = PasswordPepper
3) You then run it through some encryption algorithm which generates a hash of some nature, or otherwise alters it. Example: PasswordPepper + encryption = jfeiowq8r9304hfeowef4840t-43jg
4) Save that into a database.
5) Every time a user logs in, add the same “Salt,” and check it against the encrypted password in the database. This ensures a malicious party cannot just check for comparisons. I.e. password = r403r34r4940jt3, so we check the database for r403r34r4940jt3 and we suddenly have access to every users data with the password, password.
The goal in security is to make it take a ridiculously long time to steal peoples stuff, but virtually everything is breakable given time.
My implementation has various faults, which I have been meaning to fix, but have not had the time. In either case, they are not secure due to algorithmic issues and the fact I didn’t separate the databases properly.