Jake Humphrey

March 10, 2021

The gateway to your web app

The web is constantly telling you to never roll your own authentication. Go ahead and do a quick search for "roll your own auth" and you will find the majority of results tell you not to do it. They even go as far to say to never do it. I have an issue with this because authentication is the gateway into your application. I wouldn't leave such an important UI/UX component of my application to a 3rd party, would you?

No, and telling anyone to never do something is never helpful. What is helpful is giving guidelines and examples, and then you can plug your bloated auth library because it covers all those guidelines. Additionally these guidelines apply to other parts of your app, not just authentication, so it's important to understand them.

Here's my checklist for authentication:

  1. Force SSL on every request. It's 2021, come on. If you actually are curious about why this is important, hit me up.
  2. Don't send important information in the URL, this includes GET params (like "/sign_in?email=...&password=..."). Why? Because even with SSL, the URL is never encrypted so attackers at your local coffeeshop can see it. The web needs this to figure out what page and domain to bring you to.
  3. Never store passwords in plain text. It's 2021, come on. This is where many people instantly reach for 3rd party full packages, but that's a bit extreme. A good framework would have a built in way of digesting passwords into a one way hash. Rails has a "has_secure_password" for example, it uses BCrypt behind the scenes.  This is where doing some research into what your framework recommends will pay off.
  4. Use generic error messages for public forms containing identifying information. Don't tell an attacker that they guessed the email address right but the password was invalid. And for that password reset, if the email doesn't exist in your database, just pretend that it does! The bot won't know much better and will think that email is valid and move on from your website.
  5. Emails are forever. Remember that reset password email you sent me 5 years ago? Well I still have that link. Takeaway: Don't recycle tokens. A great solution is to add the user id to the token. That also prevents attackers from randomly guessing a reset password token (remember what happened to Zoom?)
  6. Cookies are forever. Most browsers will expire cookies, but a user can still save those cookies to a file or even transfer them to another computer. Do not rely on cookies to expire. Instead, include an expiration date and sign the cookie to prevent edits to it. This will invalidate really old cookies. I reset that date on every authenticated request.
  7. Reset sessions/cookies on sign in and sign out. This prevents session fixation which you can read about here: https://guides.rubyonrails.org/security.html#session-fixation.  This is one area that 3rd party auth systems fail in. They should and most likely are resetting the credentials in the cookie but often times that is all. This means if you are storing user specific information in a cookie, that information will still be available after they sign out. I find it better to just reset everything and manually add back what I want to persist.
  8. Invalidate cookies after password change. You can accomplish this by including a token in the cookie that represents the current password digest. The most secure would be to use a separate token that is generated any time the user changes their password, but I've also just used a section of the password digest plus a random *different salt. Just don't include the full password hash or use the same salt that was used to generate the password hash.

While it's not the shortest list, it certainly isn't the longest and doesn't instantly warrant a "never do this". This list is not just for rolling your own auth, but also as a learning tool for you to realize where other parts of your app could be insecure. I highly suggest taking a look at the following links while you are building your auth as they will stay up to date and include additional security concerns that may not be covered here but fit in your authentication UI/UX.

Here's some great resources for further reading:

Securing Rails Applications:
https://guides.rubyonrails.org/security.html
4 Ways to Secure Your Authentication System in Rails:
https://www.ducktypelabs.com/4-ways-to-secure-authentication/
Rails Security Checklist:
https://github.com/eliotsykes/rails-security-checklist


Here's one more bonus, sometimes the best security is obscurity. If an attacker is looking to hack your site, they will probably manually navigate to "wp-admin", "admin", or something similar. Having something slightly different can solve a lot of issues.

So with that said, happy coding!