This is the first post in a series on handling auth in CI4. Authentication was requested by several of you so I had to make it one of the first big series we do. This first part is going to be an overview where we take a look at several places to find best practices to use from the people who know what they’re talking about more than I. And we’ll get everything set so we can dig into next time.
What are we building?
Authentication systems can be as complex or as simple as you want them to be. There are a myriad of options, but to keep things relatively short, we are going to make this as simple and streamlined as it can be, while still following best practices. This will only cover authentication, not authorization. Basically – it will be the simple email/password/remember-me form we all know and hate. But hopefully we’ll end up with something you can easily drop in that takes advantage of all that CI4 has to offer.
I will make the code for this available at the end of the series, or you can build it as we go, sharing your discoveries and thoughts in the comments on each article. As a matter of fact – I’d love to see you guys provide sources for other best practices we should be aware of.
There are three primary sources that I’ve found over the years as I’ve built out auth systems in Bonfire, Sprint, and now the in-progress Myth:Auth. Let’s look at them here, and I recommend reading through a lot of their material
This group is part of the U.S.A. Government’s Department of Commerce and periodically release their recommendations for security and “Digital Identity Management”, or authentication. Their most recent guidelines may be surprising to some, as it does away with a lot of the more complex cases users have had to deal with in the name of security, but makes a lot of sense.
This is a security-focused group that is highly regarded. They have numerous guides and cheatsheets to help you improve your app’s security in many ways, not just authentication. Their Top 10 list is especially good to be familiar with.
This is a software/web development company that publishes lots of information about security in their blog. Highly recommended reading.
First things first – we need to plan out what we’re building, right? Here’s a quick list:
- register a simple user with email/password
- accept/validate email/password combos to determine the current user
- implement secure remember-me functionality
- throttle login attempts to discourage brute-force attacks
- use filters to restrict access to logged in users
- provide simple way to get current user
- password recovery system
I think that is about as minimal of a setup as I can think of that still keeps people pretty safe, and is usable. Still a big project that will cover several blog posts to cover it well. Let’s look at these features and see what our sources above tell us we should proceed.
According to NIST, the only real things we need to require for a password is a minimum length of 8 characters or more. That should be checked against a database of known weak passwords, typically something gathered through a data breach or other real-word source. But that’s it. Their reasoning can be found here and I think it makes total sense. I had been seeing many of those reasons around long before NIST jumped on board with it in 2017.
Here’s how we should treat passwords:
- minimum length of 8 characters
- maximum length of 255 characters (just so we can use the full amount of a VARCHAR field in the database)
- replace any multiple spaces with a single space
- compare against a database of known weak or breached passwords
ensure it’s not their email address, or a portion thereof. If we were handling usernames, real names, etc, I’d ensure it didn’t match those either.
Storing the password:
– use PHP’s built-in password commands (password_hash, password_verify) since it salts and hashes the value for us.
– rehash if necessary (we can check with PHP’s password_needs_rehash function)
There’s not much to do here but there are a couple things:
– log every attempt, successful or failed, and keep it forever. Should have enough information to attempt to trace actions
– regenerate the session id to help avoid session fixation attacks
– destroy the current session and all it’s contents
– regenerate the session id
– destroy any remember me tokens
Remember me features are a compromise in security and convenience and should be able to be turned off on a per-site basis. Ideally, you’d ask the user if they want the option (people using password managers might not). It can be complex to get it right, but Paragon Initiative is here to help. I’ll just link to their article and not repeat steps here.
Forgot Password Feature
Once again, Paragon comes to our rescue.
While that’s only 5 main things to handle here it’s still a lot of code to write. In the future articles I likely won’t provide all HTML for the forms as they would just make each post that much longer. Don’t worry, they’ll be in the repo, though.