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, 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 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:
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.
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.