In our web development post last week, we talked about the risks involved with running a web application, and how to reduce risk with change management techniques and technologies. We focused mostly on preparing and planning in advance to not only accept, but embrace change, creating an environment where your marketing team can feel safe to make updates to the site and test new features to improve ROI. Hopefully you analyzed your current web update process and talked with your IT team about their testing and deployment strategy. Now, we turn our focus to risks of a different type: security risks.
In the news earlier this week, LinkedIn was reportedly hacked, and according to reports, as many as 6.5 million passwords may have been compromised. Millions of passwords sounds like a lot, and it may have tarnished your image of LinkedIn’s brand, but to put a positive spin on this news, the number of passwords leaked represents less than 5% of LinkedIn accounts.
If you haven’t already done so, get over to update your LinkedIn account ASAP and change your password. While you’re at it, change your Google account password and turn on 2-step verification. I’m proud to say I use Google’s excellent 2-step verification process, which sends a 6-digit code to your cellphone periodically to re-validate your identity. If your company is running on Google Apps, you can enable 2-step verification for your entire organization. There are really no good reasons for having a lax security policy.
The news loves hackers
Password leaks and security breaches make great headlines. We all know that changing our passwords often is a very wise behavior to adopt, but be honest—how often do you change yours? Hopefully these type of reports remind us to choose complex passwords and change our passwords often.
Even though a hacker gained access to LinkedIn’s database, consider this: in all likelihood, your password wasn’t stored in LinkedIn’s database in clear text, it almost certainly was stored encrypted with some type of hashing. This extra layer of protection is often used nowadays to make it difficult, expensive and/or time consuming to decrypt—even if the raw data was compromised. We’ll discuss how this is done in code a little farther down.
But First, A Story
When I first learned to do web development back in the 90s, one of the first tutorials I followed was how to create a login box with a username and password field. In the example, I learned how to create an HTML form, add a text input field and a password field, a submit button, analyze the $_POST values, then run an SQL query to find a record that matched, and if 1 record was found, set a cookie with the user’s ID and username that I found in the database. Of course, no mention was made about security, it was just a simple exercise to get me started. I went on my merry way, finishing my first website with a simple login feature.
Not much has changed in 20 years in this respect. Almost every website that exists has an email and password login box that queries a data store containing usernames and passwords. Unfortunately, many websites online are still running on five or ten year old code, made by a novice coder like my younger self, who followed a similar tutorial, stored the passwords in clear text, and never went back to add security features or encryption.
Over the years I’ve audited dozens, if not hundreds, of web applications, and at least a handful of them not programmed by me stored the passwords in clear text. Seeing these brought me down memory lane, back to my early days of development, simultaneously making me reminisce and cringe at what I now realize is absurdly insecure code.
Plenty of other code I’ve run into has implemented password storage using a single-key, two-way encryption function. In this type of a setup, give me one glance at your database data, a single encrypt/decrypt key from a configuration file, and I could probably decrypt the entire database of passwords in seconds, because they all use the same key and a simple, one-line encryption-decryption method. Let’s hope you’re not storing credit card data online using such an approach.
A word of warning
Key-based encryption can give the illusion of application security when, in fact, it’s not much better than storing passwords in clear text. That is because, in its raw state, insecurely encrypted cipher text bears a very strong resemblance to securely hashed cipher text. Only an analysis of the code responsible for moving data to and from the database, or before and after the encryption, can reveal how secure or insecure your data actually is.
When a bunch of passwords are all encrypted with the same key, your data may be open to a dictionary attack or brute force attack. In both cases, if a villain obtains the encrypted dataset, he can try billions or trillions of combinations of words and characters against the encrypted data and eventually discover the key you used to encrypt it. Once he has the key, he can decrypt all your data in seconds.
Unlike single-key encryption, secure one-way hashing is most commonly recommended to store passwords. A hashing algorithm differs from an encryption algorithm in that it can only go in one direction. In other words, you can decrypt encrypted text, but you can’t undo a hash. Algorithms such as MD5 (128-bit) and SHA-1 (160-bit, 256-bit, 512-bit) were once considered quite secure, and they’re very fast. I say, “once considered secure,” because, as CPU processing speed has continued to double every 1.5 to 2 years with Moore’s law, it becomes cheaper and easier to try zillions of combinations to crack passwords on a commodity PC. As computers have increased in speed, so, too, have our hashing algorithms. For example, some SSL providers now offer 2048-bit certificates. If you’ve ever developed an ecommerce website and successfully achieved PCI compliance, you know of the complexities involving password and credit card storage.
Any security expert responsible for managing a database the size of LinkedIn’s knows that having so many passwords in a single place is an attractive target for hackers. This is because the more cipher text a hacker has obtained, the more likely he can find the key that encrypted it.
Predicting this risk in advance, the security and IT teams at LinkedIn almost certainly applied yet another layer of safety for its users’ passwords, and that is to use a random salt when calculating the hash, for each password separately.
Please pass the salt
The idea behind a salt value is similar to a randomized timestamp that changes every time it is called. By passing a salt value in addition to the password to your hashing algorithm, we eliminate the risk of a dictionary or brute-force attack from succeeding for all the passwords, even if it succeeds once.
To summarize why this is important: if we’re using a random salt and a strong one-way hash function, even if an attacker obtains your complete password database, and even if they manage to crack one password, they’ll have to run another billion comparisons to crack the password in row 2, and another billion for row 3, and so on. Assuming LinkedIn uses this approach to protect their users’ passwords, the hacker’s great grandchildren will be dead long before they can crack all 6.5 million passwords.
Now, can you see how rewarding it can be, just knowing your users’ passwords are uniquely salted and hashed? Wow, all this talk about salty hash is making me hungry, but we’ve got more to cover.
What, me worry?
So, as you can probably tell, I’m not very concerned about my password being compromised from LinkedIn because I think it’s safe to assume that LinkedIn uses a random-salt, one-way hashing algorithm. Even if an attacker gained access to a part of LinkedIn’s database of millions of account passwords, and even if your or my password was among those stolen, that doesn’t necessarily mean that our passwords are, in fact, cracked. I’ve changed mine already, and you should too, but more importantly, I use a different password on every account I have online, so there’s literally nothing said hacker can do with my password, even if he manages to also decrypt it.
Given the math and theory behind a truly in-depth understanding of cryptology, it’s fair to say that it is rather complicated to do a fantastic job with security, but on the other hand, it’s relatively simple to do a decent job, and so many great libraries, plugins and examples are out there, you have no excuse for not protecting the passwords in your database. You should at least know what you’re currently doing, what you’re using, how it works and have a plan for improving security incrementally.
Hashing made simple
The vast majority of popular web application frameworks support some type of security features built-in, out of the box. You really have no excuse to store you web application passwords in clear text, or even encrypted with a single key. Encrypting passwords properly is not difficult to do. In doing so, you can be at least somewhat confident that even if your accounts are leaked, it would be very, very difficult, time consuming and expensive to actually crack all the passwords.
But wait, there’s more
Passwords are just one of the most common places to look to improve security of your web application, but now let’s start from the top. You can harden your firewall. You can harden your linux server or secure your Windows IIS server. You can harden your PHP. All The popular CMS systems, including WordPress, Drupal, Joomla, Magento, and phpBB, each publish their own variation on the best practices for securing your site and preventing hacking attempts and attacks. There are even WordPress plugins to boost security beyond the basic installation. Magento, Joomla and Drupal have plugins and extensions dedicated to improved security as well.
Every top PHP framework there is has a security or encryption class, including CakePHP, CodeIgniter, Kohana, Laravel, Symfony, Yii, and Zend. In one of my favorite frameworks, the Kohana Auth module, for example, calculates a random salt and a hash password for you automatically. If you build your application’s authentication around this module, you automatically inherit it’s incredibly secure algorithm. It’s battle-tested and just works. Same goes for the PHPass class that WordPress uses under the hood. Same goes for the PassLib Python library.
Put your code down and step away from the IDE
Please don’t try to write your own secure password hashing algorithm—this is the kind of code about which a hundred nerd geniuses have flame wars on forums and IRC channels tirelessly for weeks and months. Use an existing library. No matter what language you’re using, there’s almost certainly a library, an API, a blog post and a discussion forum addressing these issues.
Given the plethora of available information on this topic, we urge you to ask your web developer or IT manager to prepare a report for you covering two basic topics:
- How well our current website withstand a hacking attempt?
- And, how secure is our password storage algorithm?
If they can’t answer these two questions quickly and easily, please contact us for a decent security audit.
Following is a list of questions you should be asking about your web security.
- Do we have SSL installed? Are we enforcing it with redirect rules?
- What ports do we have open on our firewall and server?
- Why are these non-standard ports open?
- Have we applied the latest security fixes?
- Have we removed any unused accounts?
- Have we changed our login credentials recently?
- Is our Apache, PHP and MySQL version up to date?
- Is our framework version up to date?
- Are there any security updates for our framework or plugins?
- How are we keeping users logged in? With a cookie?
- What’s in the cookies we’re writing? Incidentally, the EU just adopted more strict cookie policies. There are some specifics about how to comply.
- What encryption library and cipher type are we using to hash our passwords? Can we easily improve it?
- Is the encryption library we’re using updated?
- Are we using encryption or hashing?
- Are we generating a random salt when storing passwords?
- Could we upgrade to Oauth2?
Obviously, a list of questions is not intended to be a complete guide on security, nor a comprehensive list of all the concepts involved. Anyone using the built-in features of the current versions of WordPress, Magento, Joomla or Drupal can rest easy—all the top frameworks we’ve mentioned either support proper password hashing with very little work, or implement it automatically by default.
To perform a true security audit requires a thorough review of multiple technologies, including your LAN and WAN network topology, server logs, access logs, and the algorithms, software and plugins you’re using to encrypt sensitive information. Even things like your internal processes and vendor relations are important factors, because, let’s face it, leaks in security often start with a disgruntled employee and a broken process.
Hopefully our article last week prompted you to look more closely at your risk management strategy in defense of your brand image and ROI. This week, we encourage you to really take a good look at your own website security policy, and do your best to protect your server, database and user accounts against security risks.
More Topics in Web Application Security
- How to prevent XSS or Cross-Site Scripting attacks
- How to prevent CSRF or Cross-site Request Forgery attacks
- How to prevent SQL Injection attacks
- List of dozens more web application attacks
- Background and history of Cryptography
Security Topics for E-Commerce users
- Learn about Transport Layer Security
- Review PCI Security Standards
- Do a Google search of Top SSL Certificate Providers
- You can also step through a SSL Certificate Wizard to help figure out what type of certificate you need
- Look into obtaining the new Google Trusted Store badge
Security Topics for PHP users
- How to do Secure Password Hashing
- How to install mcrypt
- Using PHPass with Zend Framework
- User login & authentication with Zend_Auth & Zend_Acl
- How to do password hashing in CakePHP