Perl web application security - HTTP headers
HTTP headers are included in every HTTP response from a web server. Setting the appropriate HTTP headers can reduce the risk of man-in-the-middle and cross-site-scripting attacks on a web application. You can also reduce information leaks about the web application configuration - vital data that gives a would-be attacker clues about potential vulnerabilities. Read on to find out how to set the appropriate headers in your Perl web application.
All three of major Perl web frameworks provide some kind of identifying header. Dancer and Mojolicious use “X-Powered-By” and Catalyst uses “X-Catalyst”. The problem with this header is it informs the requester the language of the application (Perl) and the web framework being used. In some cases it also reveals the version number. With this information a would-be attacker can focus on exploits that are specific to Perl or the web framework. Here’s how you can disable it:
- By default Catalyst does not turn on its application header. The header is controlled by the “enable_catalyst_header” config option, normally located in the root application class (e.g. lib/MyApp.pm) or the application config file.
- Mojolicious does not set this header since version 4.00.
- Dancer (and Dancer2) use the server tokens directive.
Web servers often broadcast information about themselves by default. For example:
This is risky for the same reason that revealing information about the underlying Perl web application is. To disable the server header in nginx, just add this line to your nginx.conf or virtual host file:
For Apache 1.3x add these lines to your virtual host file:
ServerTokens Prod ServerSignature Off
For Apache 2.x, these lines will load the mod_headers module, and remove the server header:
LoadModule headers_module /usr/lib/apache/modules/mod_headers.so Header unset Server
All of the major Perl web frameworks ship with web servers that set the server header:
# Catalyst Server: HTTP::Server::PSGI # mojolicious Server: Mojolicious (Perl) # Dancer Server: Perl Dancer 1.3121
These headers can be overwritten within the application code. For instance, if we wanted to change the server to appear to be nginx:
# Catalyst $c->response->header('Server' => 'nginx'); # Mojolicious $self->res->headers->header('Server' => 'nginx'); # Dancer / Dancer2 header 'Server' => 'nginx';
This header can prevent your application responses from being loaded within frame or iframe HTML elements (see the spec). This is to prevent clickjacking requests where your application response is displayed on another website, within an invisible iframe, which then hijacks the user’s request when they click a link on your website. Here’s how to disable it in the respective web frameworks:
# Catalyst $c->response->header('X-Frame-Options' => 'DENY'); # Mojolicious $self->res->headers->header('X-Frame-Options' => 'DENY'); # Dancer / Dancer2 header 'X-Frame-Options' => 'DENY';
This header instructs the requester to load all content from the domain via HTTPS and not load any content unless there is a valid ssl certificate. This header can help prevent man-in-middle attacks as it ensures that all HTTP requests and responses are encrypted. The Strict-Transport-Security header has a max-age parameter that defines how long in seconds to enforce the policy for. Here’s how to add it to your Perl web application:
# Catalyst $c->response->header('Strict-Transport-Security' => 'max-age=3600'); # Mojolicious $self->res->headers->header('Strict-Transport-Security' => 'max-age=3600'); # Dancer / Dancer2 header 'Strict-Transport-Security' => 'max-age=3600';
The CSP header sets a whitelist of domains from which content can be safely loaded. This prevents most types of XSS attack, assuming the malicious content is not hosted by a whitelisted domain. For example this line specifies that all content should only be loaded from the responding domain:
X-Content-Security-Policy: default-src 'self'
There is a lot to CSP (spec) and browser support is fairly good. One downside to the whitelist approach is it’s not compatible with ad services like Google’s adsense as you won’t know the domains in advance in order to whitelist them. To set the header in your facourite Perl web application, use on of these lines:
# Catalyst $c->response->header('X-Content-Security-Policy' => "default-src 'self'"); # Mojolicious $self->res->headers->header('X-Content-Security-Policy' => "default-src 'self'"); # Dancer / Dancer2 header 'X-Content-Security-Policy' => "default-src 'self'";
This is an IE only header that is used to disable mime sniffing. The vulnerability is that IE will auto-execute any script code contained in a file when IE attempts to detect the file type. This is disabled by default in IE anyway, but to enforce it:
# Catalyst $c->response->header('X-Content-Type-Options' => 'nosniff'); # Mojolicious $self->res->headers->header('X-Content-Type-Options' => 'nosniff'); # Dancer / Dancer2 header 'X-Content-Type-Options' => 'nosniff';
This is another IE-only header that prevents IE from opening an HTML file directly on download from a website. The security issue here is, if a browser opens the file directly, it can run as if it were part of the site. To add this header, use one of these lines:
# Catalyst $c->response->header('X-Download-Options' => 'noopen'); # Mojolicious $self->res->headers->header('X-Download-Options' => 'noopen'); # Dancer / Dancer2 header 'X-Download-Options' => 'noopen';
This is the final IE-only header. It was introduced in IE8 as part of the cross-site-scripting (XSS) filter functionality (more here). The header can force IE to turn on its XSS filter. Additionally it has an optional setting called “mode” that can force IE to block the entire page if an XSS attempt is detected. Here’s how to add it:
# Catalyst $c->response->header('X-XSS-Protection' => "1; 'mode=block'"); # Mojolicious $self->res->headers->header('X-XSS-Protection' => "1; 'mode=block'"); # Dancer / Dancer2 header 'X-XSS-Protection' => "1; 'mode=block'";
Adding headers in the web server
You may prefer to add these headers in the web server configuration, rather than at the application level. For nginx, use the “add_header” directive - see here for a good example. For Apache use the “Header set” directive in mod_headers (1.3, 2.x).
Testing the headers
tThere are a number of ways to check which headers your application is returning. Firstly you can use curl (replace perltricks.com with the URL to check):
curl -I perltricks.com
This will return the HTTP headers only:
HTTP/1.1 200 OK Server: nginx Date: Mon, 31 Mar 2014 01:54:59 GMT Content-Type: text/html; charset=utf-8 Connection: keep-alive Cache-Control: max-age=3600 X-Frame-Options: DENY
You can use SecurityHeaders.com’s excellent checking tool. Or you can inspect the headers yourself by using your browser’s developer mode.
These HTTP headers are easy to add and can make a reduce your application’s vulnerability to XSS and man-in-the-middle attacks, particularly for applications that allow users to upload content.
Enjoyed this article? Help us out and retweet it!
Cover photo © Andy Wright
Updates: Mojolicious application header corrected. Web frameworks server header added. (31/3/2014)