WebDev: Password Best Practice
Based on my article earlier today about Password Reset Tips for Businesses, this article is about the responsibilities and best practices of web developers. The Security versus Convenience paradigm is well known. There is no specific rule here because each business use case is different. However, it is extremely common for security to be an after-thought or bolt-on instead of designed with a security model in mind.
It is important to first determine what level of security is needed. And while most of us are not designing a bank-level secure application, we often have extremely valuable and sensitive information. Among those is the simple username-password combination. We all know someone who does it, perhaps you still do, but almost certainly you used to — that is share passwords between websites. And your application users are doing that too. Many of them actually are giving you their bank password! So to some degree, you have extreme trust from your end users and need to take that seriously. So with that in mind, let’s talk about several best practices as well as what I’ve seen in the wild:
- Passwords:
- should never be stored in plain text or even in an encrypted form. In virtually NO use cases it there a need for you to know their password.
- any password sent in plain text should be a one-time use password (ie initial email, or password recovery). A password reset that is sent via plaintext email should never be reusable.
- the hashing algorithm should be upgradable because today’s secure hashes are yesterdays insecure. I remember when MD5 was the best hash we had available. Your code should be able to accommodate changes to the hash method.
- passwords should be salted. Some frameworks like PHP password_hash provide unique, one time salt for each hash.
- password length and other criteria should be determined by your specific need for security – obviously the longer the better. In fact, everything supports that length trumps complexity every time. The NIST even removed their recommendation for special characters.
- consider partnering with third parties like LastPass to help users adopt using a password manager.
- consider checking all passwords against the list of 500 million breached passwords via API.
- know that single-use passwords aren’t more secure. That is the practice of simply emailing or texting a user a password at each login.
- while password expiry in the sense of scheduled password resets is considered legacy practices, consider when passwords should be no longer valid. Imagine that inactive accounts (say 1 year) have their password hashes purged. Thereby requiring the user to reset their password via email. How have you improved security? If you were breached, how many fewer passwords would be exposed? Think of Linked in being able to say instead of 167 Million accounts compromised, they could say 30 million active accounts were compromised. (and 137 usernames without passwords). That would be a huge improvement. It helps the security landscape, but still might not save your job!
- Usernames:
- email accounts are okay, but usernames are better. They tend to be even more unique.
- consider providing “display names” and “usernames” as distinct fields. The username then can be hashed for additional security just like passwords. In the event, your database is exposed, both the username and passwords are protected. Ideally using a different salt then the passwords.
- Email Addresses:
- evaluate: do you really need to know the email address for your users? In many cases, the only time you contact them is during a password reset, during which they can provide you the email address and you can compare it to your hashed value.
- some other uses have been that a user preference in another table stores things such as user notification settings (phone, email, etc). So that notifications can still be sent out, while keeping your authentication database table free from unsecured email addresses.
- Two Factor Authentication:
- these are great technologies to employ for either each login or for when accessing highly sensitive areas. My bank, for example, requires my use of the RSA-2FA Fob when I conduct any financial transfers, but just a simple password for most “less sensitive” activities. This is a great balance of security/convenience.
- my own personal perspective is that biometrics-based authentication must always be paired with another factor and never relied upon as a single factor. (ahem, Microsoft) While password management is an issue, the problem with biometrics is that we’re barely keeping ahead of the ability to detect fraudulent use of our biometric data. And the biggest problem is once your biometric identity has been compromised, you cannot change it like you can a password. Once fingerprint tables get into the wild (perhaps they already are), you cannot just change your biometric data. You have to trust that they biometric technology gets better to detect fraud.
- Cookie & Session Security:
- this is huge and cannot be simply stated, but you must not blindly trust your web server to security handle session state. You must ensure that the person you think you’re talking to is the right person – that the session hasn’t been hijacked.
- consider limiting the number of sessions per login (that is that two sessions cannot simultaneously be going on with the same credentials).
- understand how roaming IP addresses impacts sessions (cell phone roaming, etc). When might you need to prompt for authentication?
- clearly understand how your “remember me” can be insecure, and what actions might trigger a re-authentication.
- is there a way for users to manage and understand their active sessions? Can they flush all other sessions? Should you be doing this automatically?
- Rate limits, brute force attacks:
- how is your system designed to detect and prevent brute force attacks? Do you even know if this is happening? I can guarantee that it is happening right now, but can you see it? What are you doing about it?
- Web Application Firewall (WAF):
- are you implementing a WAF in your firewall or software based solution? What is looking for zero-day exploits? Protecting against common threat vectors? Protecting about unexpected crashes or code dumps to the screen?
- Cross-Site Scripting (XSS) & Cross-Site Request Forgery (CSRF):
- what is being done in code to protect against these threats? Are you just accepting form data without any token?
- how are you protecting against reply attacks?
- a major airline made this mistake causing credit cards to be compromised.
- Zero trust user-submitted data
- be sure to apply the correct filters to all user-supplied input
- properly prepare your data before submitting it to your databases to avoid SQL Injection Attacks.
Finally, remember that username/passwords and the issues addressed above are primarily your “front door”. But don’t forget the other security elements that you need to account for. Are the windows, crawlspaces, and inside secure? There is a great YouTube video about physical security for server rooms — you can spend huge amounts on ‘security’ while effectively leaving the physical door unlocked! This includes your physical servers, data-secure-at-rest, data security across sessions, and how data is protected against authorized users. Who can access sensitive or encrypted data? Your server administrators don’t need to be able to see/read/decrypt that data, nor should your web developers.
As you take a look at this, understand that there is a lot more at hand to securely developing applications. If you’re tempted to just hand off this responsibility to 0Auth or another third party, you still need to understand this list. Why? Because you need to know what parts above are handled by them, and thereby know what is on your shoulders. If your database queries aren’t properly prepared, I can still just inject code to “SELECT * from credit_cards WHERE 1=1” and all is lost! That isn’t a authentication issues, but is a security issue. Often we think of security as just been an authentication question, but it goes hand-in-hand with authentication, and it is wholistic, not just something a plug-in, add-on, or module will solve.
Happy coding!