1

I'm reading through Mozilla's Secure Coding Guidelines, and found this statement:

Don't trust any user data (input, headers, cookies etc). Validate it before using it

I'm using the codeigniter framework, and am using the following (mostly built-in functions) for inputs and cookies:

Inputs

  • global xss filtering is set to TRUE
  • CSRF protection is set to enabled

Cookies

  • cookies are flagged as secure
  • cookies are flagged HTTPOnly
  • cookies are encrypted

Headers. This is where I'm running into an issue. How do I protect my site against header injection? Haven't been able to figure this out.

Also, while I am validating user inputs like passwords, etc., am wondering if there is some other type of validation that needs to be done?

1
  • 2
    None of your examples has got anything to do with protecting the server from malicious or otherwise unexpected data sent by the client (except perhaps cookie encryption, if that is indeed what you're doing).
    – yfeldblum
    Commented May 10, 2012 at 5:43

2 Answers 2

4

I use HTTP response header splitting as an example below, but the solution at the end works equally well when the injection is into the response content body.

For example, an attacker supplies an input

/
Access-Control-Allow-Origin: evil.org

and then the server uses that input to generate headers

response.setHeader("Location", input)

which results in the headers

 Location: /
 Access-Control-Allow-Origin: evil.org

One solution is to carefully check all code that specifies headers and make sure it does not use unfiltered/untrusted inputs to generate the headers. This is error-prone, time consuming, and is not guaranteed to hold under maintenance.

A more robust solution is to use library methods like response.setHeader that refuse inputs that contain newlines. If response.setHeader did

 void setHeader(String name, String value) {
   if (!(match(name,  "^[A-Za-z\\-]*\\z") &&
         match(value, "[^\u0020\u0021-\u0023-\u007f]*"))) {
     throw ...;
   }
   ... 
 }

then an attacker might be able to deny service, but would not be able to split headers, and your logs would contain traces pointing to the problematic setHeader call.

If you're using a framework, often you can wrap your response objects so that the header methods do this.

2
  • 1
    Thank you for this thorough response. I accepted your answer, but can't upvote it since I'm new to security.stackexchange (all my points so far are on SO).
    – chowwy
    Commented May 10, 2012 at 0:45
  • 1
    Now that I can upvote, it's upvoted!
    – chowwy
    Commented May 14, 2012 at 15:38
3

General. "Validate input before using it" means you must write code to check that the input is of the expected form (e.g., check it against a whitelist) before you use it. This is part of your responsibility when writing the code. You must do this everywhere that your code recieves inputs from untrusted sources.

Setting configuration flags (like global XSS protection or CSRF protection) is not a replacement for validating input before using it.

See, e.g., OWASP's guidelines for a lot more information about this subject.

Make sure you also read up about escaping of values before output.

Header injection. Check the value against a whitelist that is derived based upon the type of value you are expecting: e.g., every character in the input should be in a certain whitelist of allowable characters, or the input string should match some carefully constructed regexp. Make sure sure that your whitelist does not include any newlines or other control characters.

Passwords. There's not a lot of validation that makes sense. You might want to check that the password does not contain any '\0' (nul) bytes, just as a sanity check. Probably the first and only thing you should do with a password is immediately hash it (using bcrypt, PBKDF2, or scrypt), then never look at or use the cleartext password again. As long as you make sure to follow that pattern, probably no additional validation is needed.

If you ever send the password by email, check that the password does not contain newlines or other control characters. If you insert the password into a database, make sure to use SQL prepared statements to form the database query (don't use string concatenation). If you ever display the password on a web page by including it in dynamic HTML (probably a bad idea...), then make sure you HTML-escape the password properly before including it in the HTML.

5
  • Thank you very much for this (I don't have enough points to upvote yet). A few things: I checked my framework's documentation and have found a way to setup validation for all user inputs; appreciate your advice on that. Also, I am already escaping queries, and user passwords are protected with bcrypt; users can reset passwords, but we don't send them out. And passwords have to be alphanumeric and 8 characters long. I have one other question on header injection, but I will put it in the next comment.
    – chowwy
    Commented May 10, 2012 at 14:00
  • I don't understand where to check the headers for injection. I'm reading some tutorials on headers, and downloaded Live Headers in Firefox to see what comes up when I visit sites. I'm trying to figure out where header issues are dealt with in my application.
    – chowwy
    Commented May 10, 2012 at 14:25
  • @chowwy: 1. For database queries: Don't escape SQL queries. Instead, use prepared statements. 2. For preventing header injection: you must validate all values that will ever be inserted into a HTTP header. You can validate these values at the entrance point to your code, as soon as you receive them. Validation should be written to ensure that the value doesn't contain anything that might be interpreted as a newline (and you might want to make it stricter, just in case). See MikeSamuel's answer for further information.
    – D.W.
    Commented May 10, 2012 at 18:18
  • Okay, thanks. This is all useful info. Again, much appreciated.
    – chowwy
    Commented May 10, 2012 at 20:23
  • Now that I can upvote, I've upvoted this.
    – chowwy
    Commented May 14, 2012 at 15:38

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .