Over the years I have built up a knowledge base on what to implement and look for when building web applications, these are my thoughts. I have liaised on many occasions with independent security organisations who perform regular audits on web applications. Recently lots of reports circulating about security in web applications and the lack of security being used. I stand firmly behind the notion that their are really two types of organisations those that have been hacked and those that will be hacked (as remarked by Robert S Mueller FBI Director March 2012 http://mcaf.ee/nkq2t ); it is only a matter of time and resources before any site can be hacked. If you are a software developer and you believe this, that is actually good, because you will probably build more secure software as you design. It is always easier to build your security into your software as you design, retro fitting security is never the best approach.
When I began writing Web applications, security was actually the furthest thing from my mind, I was focusing on building functionality and not building secure functionality; this is no longer the case. Sometimes to the annoyance of fellow developers I try to keep security to the forefront. I have heard people say "every one gets hacked" this is true but this is being used as a reason why maybe you don't bother building much security into your web application. My philosophy is yes every one will get hacked as Robert Mueller has noted, but I would much prefer to be able to respond and say we did our up-most to protect our web application and in this case the hackers are just smarter than use. I always look at security as a onion it is many layers someone (the hacker) must go through before compromising your application. As a developer it is your job to ensure the software you are writing is secure don't be relying on someone else to check in (i.e. their is no "Higher Order"), believe in this and you will build more secure applications.
So as a base guide for building secure applications some obvious ones are listed below (of course this is not an exhaustive list, and only represents general starting points):
probably the first place hackers will look at trying to exploit. I think these days most organisations have this sorted out, I rarely read where a web application has had their cookies compromised.
Your cookies need to be secure. What does this mean, well the values used for your cookie need to be non deterministic i.e. if someone manages to grab a million of your cookies it should not be possible to determine the next value. Currently I used PRNG (Pseudo Random Number Generator) which is based on RSA X9.31 PRNG. Whatever you use to create your cookies it needs to be random.
Second your cookies should expire, always expire your cookies on the server side, I believe in having two types of expiry one for user inactivity and a second just expires your cookie after a period of time irrespective of user activity. Consider the second option a lease on your cookie. This lease time depends on the nature of your application if your banking on line you will have a very short lease period, I spend a lot of time in the HR software area and usually set the lease time to a few hours, but I recommend configuring this lease period to be easily adjustable.
Server side cookies should be purged once expired, never leave cookies hanging around on the server side.
Passwords / Usernames / Hash
Recently this is where everyone is getting caught out and I don't know why. Because, it is probably one of the easiest solutions around. A few months back you had linkedIn accounts compromised, more recently Yahoo & Nvidia had an issue with user accounts and passwords. These are only recent examples, has the writing not been on the wall, have these organisations had their head in the sand. Yahoo were just silly and had passwords in plaintext no excuse here, but Nvidia and linkedIn had the passwords hashed with no salt! This should now be obvious your passwords should be hashed with SHA-1 or MD5 or some similar hash algorithm but you must include a salt. In addition why not encrypt the username? What seems obvious is the database table storing the user credentials are being compromised i.e. Maybe a SQL injection attack selects back all columns from a table containing the credentials. What we also know is users will tend to use the same password on many sites, and usernames tend to be email address. What are the chances you use your email (gmail, hotmail etc.) account as your username and then reuse the same password, the chances are extremely high and this is what the hackers are counting on. So Web applications should be encrypting the username as well as hashing the password with a salt. This brings me to a point re: Encryption vs. Hashing, passwords should be cryptographically secure, this does not mean the password should be "encrypted". I read recent reports about linkedIn and Yahoo and reporters talking about passwords not being "encrypted"; guess what they should not be encrypted they should be hashed as I mention above. So you have these reporters throwing mud at linkedIn and Yahoo but they don't fully understand what they are saying. Basically you encrypt something it can be decrypted, you hash something it cant be "de-hashed", hashing algorithms MD5 and Sha-1 are one way hash functions. But if you don’t include the salt it will be easy to crack weak passwords, lets say your password is "password123" and a service you use is compromised, if your password is hashed with MD5 / sha-1 chances are extremely high your password will be compromised. Just Google Reverse MD5 lookup and paste in the hash value for "password123" you will get the plaintext returned.
I have a newer post on secure passwords to be published shortly. Discussing best practices for storing a password.
Passwords & 2FA
A reasonable password policy i.e. user can remember and wont be inclined to write down. 2FA such as OTP via an authenticator app eg Google Authenticator.
Probably one of the easiest ways to hack a site is monitoring the parameters and attempting to tamper with the value, a great tool is burp suite, this is a very powerful tool that I am sure hackers use regularly. This can cause many issues it is a potential to SQL Inject and create some persistent cross site scripting. The recommendation is to centrally validate all your parameters; e.g. a numeric field, your server side application should only be accepting numeric values so < ;script>; should not be accepted. This central validation process is pretty low level and could become a pretty heavy piece of code, this is none the less the recommendation. An alternative I have used is placing a layer on the web server in my case I use Apache. Apache has a module called mod_security, which uses regular expressions; monitoring for such attacks like Cross Site Scripting and SQL Injection. It has proved very effective. If you don't implement a central validation function for parameters you don't get an A, if you implement some central layer on your Web Server you will get a B. You need to way up the pros and cons, I think if I was designing an application from scratch I would try to build a central validation layer ensuring it is performance tuned. Also see primary key protection.
a note on mod_security if you use Oracle, maybe SQL Injection can be turned off, I have seen SQL Injection in mod_security take lots of resources. So in Oracle database SQL Injection is not possible if you are using implicit or explicit cursors. In these cases Oracle DB manages the bind variables. Howvere, ifyou are using dynamic SQL then you might be vulernable to SQL Injection. When using dynamic SQL always use bind variables. All my work tends to be Oracle so I consider Dynamic SQL evil, and I 99% of the time dont use it.
This basically means you have authorized particular server side scripts to execute, if the script is not in the white list it should not execute. I tend to build a white list and each time a new script is created I register this to be white listed as either public or private. Where public means you don't have to be logged in to access the script (e.g. your main front page where users login), and private is where you need to be logged in. This white listing facility should be centrally managed. Don't use the alternative Black Listing, it is too easy to miss something, White-listing requires a little more over head but it is worth it in the end. If you have an application that can have several thousand server side scripts in total but only a few hundred that should be exposed to the internet then white listing is a good approach. When you implement a white listing approach you are effectively reduces the attack surface of your application.
Cookie Checking on Requests
Each time a user makes a request to the server side don't forget to check the cookies, centrally design a function to test if the cookies are valid. I have seen on a number of occasions developers forgetting to check cookies when performing Ajax requests, so the rule is each request check cookies then match the response with the white list i.e. is the request a public script or a private script ? And respond appropriately.
Server Side Tokens - once off
Some requests are so important they should only be performed under strict control, take an example of a HR application where you are allowed to amend your bank account details, so that your next pay check get delivered to this new back account. On submission the server side should request you to re-authenticate, if you successfully re-authenticate the server should respond with a server side token that can only be used once. After it has been used it becomes expired.
Server Side Tokens - locked to account
To further lock down server side tokens, create them and lock to an account. Just check who the current user is, and assign this token to that account. This will then mean the token can only be used by the user who generated it, and can’t be stolen and used under a different account.
Primary Key Protection
In any database system you will need primary keys, allowing the user amend accounts, without a primary key you cant complete an update. So instead of passing the primary key to the client application, you can map the primary key to a random number. I call this key identifier mapping. It is a very simply solution and works very nicely. Take a primary key "123" if a hacker sees this parameter they might store this away for later use and they attack the application at a later time using this parameter. So instead of passing around the parameter value as “123" randomly map this to another value lets say a HEX value of "AED". The client browser sees "AED" and not "123" but in the back end you have mapped "123" to "AED" and then when you need to perform your update you reverse the process. The great thing about this solution is each time you ask for a new identifier you get a randomly different value, so "123" is mapped to "AED" then you request "123" again and it is mapped to "AFF" and so on... This solution requires you to create a central function to create the random map and then to reverse the random map.
For each parameter submitted to server side; ensure you sanitize e.g date fields, number fields, email, dont simply set each field to a string. Assert each parameter and validate against this assertion. This will reduce attack surface for XSS style attacks i.e. its is much more difficult to inject XSS into a email validated field than a string field. Ensure the sanitization process is centralised. Centralising the sanitization allows for easy upgrading maybe to a more powerful sanitizier e.g. OWASP ESAPI.
Content Security Policy
This is more an infrastructural item, but it should be pretty obvious your application needs to run in HTTPS mode. For very large application this can cause performance issues. But for most web applications this is not a concern.
Lots of other areas exist securing and protecting your application at the Network Layer, Operating System and Web Server. However most attacks are targeted at the Web Application layer, last review I completed with auditors was suggesting > 80% attacks are focused on the web application layer. If anyone believes by just implementing these suggestions you are protecting yourself against a hack, you are not getting the point. Above all as a developer you need to ensure you "never trust the client browser" and write defensively.