When reading about large-scale hacks like the Ashley Madison attack or the Equifax attack, we assume them to be amazing feats by hackers. The hacked companies were not small-scale businesses—they were enterprises, so the assumption is that they have complex, bulletproof security systems and ethics.
However, the deeper you read about these hacks, the more embarrassing it gets. The Ashley Madison hack was due to a programmer error—encrypting passwords with an easily decipherable algorithm: MD5 over Bcrypt. And they actually stored an encryption key in plain text within the source code.
It’s almost as if the programmers had a blatant disregard for best practices and code ethics—so much so, that it should almost be illegal for developers to not enforce basic application security.
To make it easier on devs, here’s a list of 10 best practices that ensure application security:
1. Hash your passwords, do not encrypt them (or worse, store them in plain text)!
The purpose of a password is to authenticate a user. This requires developers to only “compare” the password stored in the database against the one entered by the user—not access the password itself. This comparison can either happen in the plain text, or when the same transformation is applied to both the texts. Transformation is one way you ensure that the only person who knows the password is the user him/herself.
That transformation is called hashing!
Hashing is a one-way function in which a hashed value cannot be reversed to obtain the original input value (i.e., the password). Symmetric encryption is based on the use of an encryption key and is a reversible operation. Anyone possessing the key can decrypt an encrypted value to obtain the original value.
– via DarkReading
2. Follow REST Principles.
An intern at my startup once set up an unauthorized endpoint to delete articles on his blog. If that wasn’t bad enough, this endpoint was a GET method. So one fine day, when Google came to index his blog, it found this endpoint and decided to index all of the pages—Yes, all of his blog posts were deleted!
Following REST Principles is more along the lines of agreeing to be friendly with every web developer than anything else.
Below is a quote from “RESTful Java with JAX-RS 2.0, 2nd Edition” that explains why:
It is crucial that we do not assign functionality to an HTTP method that supersedes the specification-defined boundaries of that method. For example, an HTTP GET on a particular resource should be read-only. It should not change the state of the resource it is invoking on. Intermediate services like a proxy-cache, a CDN (Akamai), or your browser rely on you to follow the semantics of HTTP strictly so that they can perform built-in tasks like caching effectively. If you do not follow the definition of each HTTP method strictly, clients and administration tools cannot make assumptions about your services, and your system becomes more complex.
Be aware of two important principles:
– Use GET methods ONLY for reading data, not altering state.
– Do not use POST to delete data—Always use DELETE.
3. Sanitize input before querying the database.
The easiest way to prevent SQL injection is to make sure you are not passing in values retrieved from the client directly into the SQL query. Always clean (remove special characters) and validate (IDs can only be of ‘n’ length) input.
Here are a few other tips to follow:
– Use established ORMs (like ActiveRecord).
– Choose a framework that supports sanitization out of the box. (PHP doesn’t!)
– Encrypt data.
– Use a least privileged database account (do not use admin credentials to connect the database to your web app).
4. Client-side validation is not enough!
I’ve reached SQL integer limits trying to count the number of times I’ve seen validation overlooked and limited only to client-side. No matter how complex your client-side validation is, someone can ALWAYS come in between and pass in the wrong input. Always, always validate and clean (again) on the server side.
This also applies for form submissions. Many times, developers overlook things like checkboxes and radio buttons—assuming that only those options can be passed on to the server. However, it is very easy to edit a few HTML files and inject a few JS files to pass in malicious input. Always make sure input is cleaned, validated and exists within an expected range.
5. HTTPS—This has to be obvious!
It’s 2017. A website without HTTPS is like using HTML v1.0. You should always protect your website with it, even if it is just a static page, even if it doesn’t carry sensitive data, and even if you’re just hosting your favorite meme.
HTTPS is no longer a measure of security. It’s also a requirement to integrate cutting-edge web technologies. It’s even a requirement for PWAs!
6. Secure API keys.
A common authentication method for API services is to use auth keys. API servers are traditionally kept stateless and leave the client to worry about state and sending all necessary information with each request. API requests don’t have the luxury of sessions—meaning the traditional approach of saving user data in a session in a normal web interaction needs to be replaced with an auth key that uniquely identifies the user, and needs to be passed with every request.
Here are three quick and easy rules to follow:
- Pass auth keys in the header of each request, not in the URL.
- Refresh and regenerate but never recycle auth keys.
- If you can, whitelist domains that can access your endpoints.
7. Do not process payments on the client side.
Do not process payments with either JS or iFrames. Both are vulnerable to almost the same issues (such as injecting JS or replacing the iFrame itself). Payment values can be altered in these cases, and users end up paying much less than the value of the item they purchase.
8. Do not generate passwords. Send reset password links instead.
When resetting passwords, a lot of applications regenerate the password and send it in plain text via email. This is BAD. Always generate reset password links. This prevents people from resetting other users’ passwords.
9. Do not use real database mapping IDs to display record information.
Instead, encrypt the ID and use that on the client side. This way, in the event that a hacker gets access to your database, there is something preventing them from accessing the data with a simple where query. There are a lot of popular libraries that do this out of the box, like obfuscate_id for Rails or hashids for Python.
10. Have renewal systems in place to update old tech stacks.
Updates for both open source and closed source technology come with major security fixes and better protocols. Even though it’s a pain to bring up existing code to current protocols, the advantages will be worth it!