Web Security… It’s almost an oxymoron. Security for the web has always been a long and difficult battle, often a losing one. With this segment on web security, I am focusing specifically on development techniques that you can apply to your web applications to make them more secure. I really want to concentrate on making security easy, for both the end-user and the developer alike. Who said security has to be hard?
This is a multipart segment that will cover:
- XSS (Cross Site Scripting) Attacks
- CSRF (Cross Site Request Forgery) Attacks
- SQL Injection Attacks
- JSON Hijacking
My Security Background
Firstly, a little on my background: I consider myself fairly knowledgeable on security related issues but I am by no means an expert. I worked for Lockheed Martin (albeit breifly) in the System Security Engineering group. I have taken courses from the NSA and did coursework for CISSP. I gave several presentations on secure programming best practices and I have dabbled in a little hacking (ethical of course *wink*). With that said though, its not my main area of expertise, so take my advice with a grain of salt.
General Rules to Follow
There are some general rules to always follow during the development phase. These rules apply regardless of what type of application you are building. I believe every developer should be aware of these.
Nearly all of you are web developers so there is only 1 symmetric algorithm you need… use AES 128 as your encryption method. AES is also known as Rijendael (though the key block sizes can differ between the 2… its technically the same algorithm). Don’t use any other encryption algorithms! AES 128 is approved by the NSA for the encryption of classified Secret documents. Want something stronger? AES 192 (or 256) is approved for classified Top Secret. There is no other algorithm that is more secure. You may think that “Blowfish” sounds like a cool algorithm, but it has not been fully vetted. It lost the race to be the Advanced Encryption Standard against Rijendael.
The only time you should use a different encrpytion algorithm is if your application’s performance is dependant on the speed of your encryption. Other algorithms are also easier and faster to implement in hardware.
Also, encrypting something more than once does not make it more secure. In fact, the opposite can be true. You can actually weaken the encryption by doing this or at the least, not increase it by much. Encrypt once, with AES 128 and you will be fine.
Password requirements should encourage users to create strong passwords, but not burden them with such complex rules that they take extreme measures to remember their new “secure” password. If your password strength requirements are too extreme users are going to write all their passwords down on a sticky note and tack it to their monitor.
At one of my previous jobs, everyone in the company had to remember at least 4 different passwords. I had about 7 to remember. All of them were different, had different, and conflicting password strength rules and were all on different expiration periods. It was no suprise that most people carried a crib sheet with them with all their passwords written down. The company’s attempt at password security failed miserably because no one could remember all their passwords.
Make your password requirements sensible.
We always like to let the user know when something went wrong so they can fix their mistake, or let us know something went wrong. However, we need to be cautious in the error messages we return as they can give hackers insight into vulnerable areas.
For instance on a login page you don’t want to tell the user: “Your password is incorect” indicating that the username was correct. Instead, just say “The username and password combination was incorrect.” This prevents hackers from guessing user accounts and hinders their ability to perform brute force attacks.
Another example is how you handle unexpected error conditions and exceptions. You should avoid printing a stack trace, or even what kind of exception occured. Some exceptions can leave you open to reflective xss attacks which I will cover in the first part of this series, Web Security Part 1 – XSS (Cross Site Scripting) Attacks.
Every application should contain some sort of logging mechanism. It is important to log certain things like failed login attempts, even who logged in when from which ip address. These log messages leave an audit trail allowing you to see possible attacks. Additionally, you should log all errors and exceptions instead of showing them to the user.
Use a database abstraction layer that you can extend
The database abstraction layer is required to implement my solution to protecting against XSS attacks. See Part 1 in this segment, Web Security Part 1 – XSS (Cross Site Scripting) Attacks. Additionally you can put in checks to make sure you are using prepared statements, which help prevent SQL injection attacks. More on that in Part 3 – SQL Injection.
Always use prepared statements
This should really be a no-brainer. This is the only way to effectively prevent SQL injection attacks. There is a caveat to this which needs to be taken into consideration. The ORDER BY clause cannot be parameterized using most database connection libraries. Many developers concatenate a parameter to the end to sort by. I will admit, I was guilty of this one. I illustrate some simple methods to address this in my post: Web Security Part 3 – SQL Injection.
If you have cookies, ensure they are secure (if you run on https) and bound to a specific subdomain
This may effect only a few readers but should still be thought of. Most people don’t pay too much attention to how their session cookies are set in their web application so they just bind the cookie to the * subdomain. This can have dangerous security repercussions in community based sites with user generated content. For example, a community website that hosts blogs for members.