Authentication and Secure Password Storage
How to build an authentication system. Users register and login using their username and password. How we securely store passwords
Authentication
User Accounts
- Registration
- Users create an account on your app
- Choose a username and password
- Authentication
- User claims to be a specific registered account holder
- Supplies their username and password
- They are claiming the be username and their proof is the password
- Verify their identity using the password
- If the password matches, log them into your app
- Serve private content specific to them
Password Storage
- You have a need to store each username and password in a database
- This data must persist so users can log in even after a server restart
- What if this database is compromised?
- Perhaps by a SQL injection attack
Never Store Passwords as Plain Text
NEVER store passwords as plain text
We need to securely store passwords
Our goal: Store them in a way that even the admins of the app can know the passwords of their users
Solution: Hash the passwords and only store the hashes
Hash Function
- A function that converts one value into another with certain properties
- Typically a fixed length value
- Used to build hash tables
- Among other applications
- Hash functions might not add any security!
Cryptographic Hash Function
- A hash function that is meant for secure purposes
- Goal of being a one-way function
- Easy to compute a hash value from plain text
- Very difficult to compute the plain text of a given hash
- Hashes can be shared without compromising the plain text [With care]
Your password: "password"
Hashed password: 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8
Cryptographic Hash Function
- Only a cryptographic hash of your password is stored in the database
- By only storing the hash of a password:
- Even the admins of a site can't read your password!
- SHA256 is a commonly used cryptographic hash function
SHA256
- Runs input through multiple rounds of bit-level manipulation
- Designed to be VERY fast!
- Very difficult to invert
- We could just store a SHA256 hash of our passwords
Brute Force Attack
- Storing SHA256 hashes is not always secure!
- Surprisingly common misconception
- Hashes are easy to compute, but hard to reverse
- To attack a hash:
- Hash every possible password
- If the hashes match, you know the password
- SHA256 is designed to be FAST!
- This feature makes the attack more effective
Entropy
- Entropy is a measure of uncertainty
- Number of guesses required to guarantee a hash is matched
- Examples:
- If you know the plain text is a single lowercase letter the entropy is 26
- If it's two lowercase letters, the entropy is 26^2 = 676
- If it's two letters that can be upper or lower case, 52^2 = 2704
- Tend to measure the "bits of entropy"
- The log base 2 of these values
- Typically consider >=80 bits of entropy to be secure
Dictionary Attack
- More advanced version of the brute force attack
- Use common words with common replacements
- a -> @
- O -> 0
- i -> !
- Real words are easier to remember
- Attackers take advantage of this
- Lists of common passwords are freely available
- Start with these
Rainbow Table
- A table containing the start and end of "chains" of hashes
- Repeatedly rehash the start to reach the end
- To attack a hash:
- Rehash until you reach the end of a chain
- Rehash the beginning of the chain to find the value before the hash
- Takes a long time to compute a large table
- Effectively trades space for time once the table is computed
Salting
- Salt hashes to prevent attacks like rainbow tables
- A salt is a randomly generated string that is stored in plain text with the hash
- The salt is appended to the plain text before hashing
- Nearly all hashes in the rainbow table will not use this salt
- The salt does not add entropy since it is stored in the clear
Authentication
- Registration
- User provides username/password
- Generate a random salt
- Append the salt to the password and compute a secure hash of this value
- Store the username/salt/hash in your database
Authentication
- Authentication
- User provides username/password
- Lookup the salt/hash for the given username
- Append the salt to the provided password and compute the SHA256 hash
- If this hash matches the stored hash, the user is verified
- If this hash does not match the stored hash, the user is not logged in
bcrypt
- bcrypt is a hashing algorithm designed specifically for passwords
- Much more secure for low-entropy inputs like human generated passwords
- Designed to be SLOW!
- Roughly 100ms per hash with default settings and a typical laptop
- Build salting into the algorithm and output
- Use a bcrypt library to compute and check hashes
- Limited to 72 bytes of input (Truncates after 72)
Redirects
Redirects
- To redirect the user to a different page:
- Respond with a 300-level status code
- Ex. Redirect HTTP requests to HTTPS requests
- Ex. Respond with 301 Moved Permanently when the server is updated with new paths, redirect the old paths to the new paths instead of maintaining both
- Ex. Response with 302 Found to redirect temporarily (Avoids browsers caching the new path)
HTTP/1.1 301 Moved Permanently
Content-Length: 0
Location: /new-path
Redirects
- A redirect response must contain a Location header
- This is the path of the redirect
- The client will make a second HTTP request for the Location path and load the page with the new response
HTTP/1.1 301 Moved Permanently
Content-Length: 0
Location: /new-path
Redirects
- If the Location is not a full url, it will be treated as a relative path
- New request is made with the same protocol/host/port as the original request
- Example:
- First request was for "http://cse312.com:8080/old-path"
- Second request is "http://cse312.com:8080/new-path"
HTTP/1.1 301 Moved Permanently
Content-Length: 0
Location: /new-path
Redirects
- If the location is a full url, the user can be redirected to a different server
- Example:
- First request was for "http://cse312.com:8080/old-path"
- Second request is "https://google.com/"
HTTP/1.1 301 Moved Permanently
Content-Length: 0
Location: https://google.com/
Redirects
- Add a Content-Length of 0 since there are no bytes to read from the body
- This is technically optional. The lack of a Content-Length header should imply a length of 0
- However, this confuses Firefox.. so we'll add the header
HTTP/1.1 301 Moved Permanently
Content-Length: 0
Location: /new-path