More on secure code
I will try and visit some points on securing web applications in this weblog entry. To the security experts, my notes here will seem amateurish and so I'd recommend you amuse youself by clicking on one of the links on the sidebar or Google your name. To the rest of the uninitiated or partially initiated, this log will hopefully provide some value.
A common mistake that web application developers and vendors alike make is that they trust their users to provide valid, non-malicious data. This is more often than not at the root of most problems compromising web applications. Howard and LeBlanc in "Writing Secure Code" suggest remembering the two golden rules of user input:
- All input is bad until proven otherwise
- Data must be validated as it crosses the boundary between untrusted and trusted environments
It is best to structure validation logic such that it determines only what is valid data and discards all other input. This is the key in structuring you if-else clause. One mistake would be to leave room for unbounded and unchecked data from form submissions. I have seen a lot of this on my projects, where for instance, developers forget to provide
maxlengthattribute values to Struts HTML input tags. Remembering the rules above can steer you away from the mistake of allowing direct user input data in your SQL statements. An attacker can provide form input like
xyz' or '1' = '1. If your code allows untrusted input without validity checks, and moreoever propogates it all the way into your data access objects, then you may be in for trouble. Here's a sample authentication query in a fictitious DAO that would typically get you in:
SELECT COUNT(*) FROM USER_TABLE
WHERE USER_NAME = 'admin' AND PASSWORD = 'q$N-0'
Say, your logic here is structured to permit access only if the returned value is non-zero. Now, if the malicious input values were substituted, the query looks like this:
SELECT COUNT(*) FROM USER_TABLE
WHERE USER_NAME = 'xyz' or '1' = '1' AND PASSWORD = 'xyz' or '1' = '1'
The attacker is authenticated without knowing either the username or their password. There are variants to this as one can no doubt deduce. The vulnerability shown above is partly due to the fact that we have SQL statements in our code. Use prepared statements or parameterized queries. Java [that wonderful language!] provides you with all the means to achieve this. Does your code have safeguards against this sort of thing? Maybe so. Do you trust that the code on your favorite online store has similar safeguards? You'd sure hope so!
Yet another vulnerability stems from allowing HTML constructs as valid form inputs. Attackers can enter a wide expanse of inputs to detect systems secrets.
If you really do want to allow a small subset of HTML tags as part of form input data, then use regular expression -based input checks.
There are some other tips to remember:
- Don't use security logic that in some way relies on hidden form fields, data in cookies, weak session ids and the HTTP
- Don't use hidden fields to store sensitive or near-sensitive information
- Don't use BASIC authentication outside of a PetStore kind of demo application and sometimes not even there
- Don't store any secrets in your system! If you simply must store something, make sure it is encrypted or hashed. Encryption can drag down performance but that is okay. At least your system will still be more reliable than it would be if it were hacked.
- Don't mistake Base64 encoding with encryption. Believe me, a lot of people do that.
- If you implement password hashing, for example using SHA-1, further harden it by using a salt. The salt is a random sequence of characters and digits used to season a password before hashing it. The salt itself need not be a secret although it is important that it be unique for every user.
- Run applications with the least privileges they need to function, and no more. There is no reason to run a database or application server process as local administrator or worse still, with system privileges. If your vendor says their product can only run as system or elevated privileges, consider a different product/vendor.
- Revisit you page caching policy. Don't cache if don't have to.
- Always have a security policy if you don't already have one. As SANS describes it "Policies describe purpose, scope, policy statements, actions and responsibilities. Security policies must be written to reduce the effort required in maintaining them, yet be clear in the objectives, boundaries and procedures required in enforcing them." Make sure your product has a password policy, a logon banner, notification policy and session timeout policy
- Always analyze your system for threats. Use a threat model and develop a threat mitigation strategy. I have recently used the STRIDE model and have found it useful.
- Be wary of the 10 software myths highlighted by Cigital
- Be afraid. Be very afraid.
My description above in no way summarizes all there is to know or even does justice to the topic. "Writing Secure Code" by Howard and LeBlanc is a book I strongly recommend to all developers. I have found many articles on SecurityFocus.com to be very useful, especially this one by K.N. Mookhey is a must-read. You may also download OWASP's WebGoat found here. Learning about software vulnerabilities by actually exploiting them, can be a great way to grasp the subject.
There's more to say on this in future entries.