HTTP headers are dynamically generated and under certain circumstances user input may be injected. This can lead to false redirection, XSS, or HTTP response splitting.
HTTP request headers have a Referer, User-Agent (client software), and Cookie field, among others. Response headers for example have a status code, Cookie, and Location (redirection target URL) field. All of them are user-supplied and may be manipulated with more or less effort. Remember to escape these header fields, too. For example when you display the user agent in an administration area.
Besides that, it is important to know what you are doing when building response headers partly based on user input. For example you want to redirect the user back to a specific page. To do that you introduced a "referer" field in a form to redirect to the given address:
http://www.yourapp.com/some_controller/some_action?referer=http://www.maliciousstuff.tld
http://www.yourapplication.com/controller/action?referer=http://www.malicious.tld%0d%0aX-Header:+Hi! <http://www.yourapplication.com/controller/action?referer=path/at/your/app%0d%0aLocation:+http://www.malicious.tld
>HTTP/1.1 302 Found [First standard 302 response]
Date: Tue, 12 Apr 2005 22:09:07 GMT
Location:Content-Type: text/html
HTTP/1.1 200 OK [Second New response created by attacker begins]
Content-Type: text/html
<html><font color=red>hey</font></html> [Arbitrary malicious input is
Keep-Alive: timeout=15, max=100 shown as the redirected page]
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html
Under certain circumstances this would present the malicious HTML to the victim. However, this only seems to work with Keep-Alive connections (and many browsers are using one-time connections). But you can't rely on this. In any case this is a serious bug, and you should update your Rails to version 2.0.5 or 2.1.2 to eliminate Header Injection (and thus response splitting) risks.
Allowing suspect requests to reach your code is not a best practice; you leave yourself open to all attacks you haven't yet heard of. Host header spoofing can cause very serious problems, and these attacks should be prevented. One popular and easy fix is to avoid the problem altogether by simply ignoring incoming requests that have suspicious host headers. In security speak, you want to ignore every request that comes in that has a host header that doesn't exactly match your system. In Nginx, this is done by setting up a default server on port 80 (and port 443 if you use HTTPS) that does nothing but return 444
server {
listen 80 default_server;
listen 443 default_server;
return 444;
}
class ApplicationController < ActionController::Base
before_action :debug_headers
private
def debug_headers
if request.env['HTTP_X_FORWARDED_HOST']
request.env.except!('HTTP_X_FORWARDED_HOST') # drop the variable
end
end
end