Leverage proxy caching with nginx by removing Set-Cookie header
The following is a result of a bug within WebKit's Dev Tools used by Google Chrome and Apple's Safari. I have made a bug report with CrBug, who then identified the regression within WebKit Changeset 116952. I would like to thank @Grumpy and @Matthieu Cormier for their help is tracking this one down. I can't wait for the next build of Chrome Canary :).
I have nginx setup on my server along with PHP-FPM, and during making a new website and trying to make sure that it is as quick as possible I went through Google Chrome's Audit tools. Among some of the errors it gave me this.
Leverage proxy caching (10)
The following publicly cacheable resources contain a Set-Cookie
header. This security vulnerability can cause cookies to be shared
by multiple users.
So what I would like to know is, what do I have to add to the following statement in order for it not to set a Set-Cookie header for this domain. I would then take that information and apply it to css, img, ect subdomains so that it can be properly cached by the browser.
server {
gzip on;
gzip_static on;
listen 80;
server_name img.domain.tld;
root /www/domain/tld;
index index.php index.htm index.html;
location ~* \.(gif|png|jpg|jpeg|svg)$ {
expires 30d;
}
include php_fpm;
}
Follow up for request for more information by Grumpy.
Here is the configuration file that I am for the PHP FPM include, used in the img sub domain.
The PHP-FPM include
location ~ \.php$ {
fastcgi_pass unix:/tmp/php.socket;
fastcgi_param SCRIPT_FILENAME
$document_root$fastcgi_script_name;
include fastcgi_params;
}
As you can see, it should only activate when the location ends with a php file extension.
Funny thing is, I also have a css file that is being reported as having a set-cookie header, and that's being served by the css subdomain that does not have a php-fpm included in it ... here is that part of the configuration file.
server {
gzip_static on;
listen 80;
server_name css.domain.tld;
root /www/domain/css;
index index.htm index.html;
location ~* \.(css)$ {
expires 7d;
}
}
The files are ...
Leverage proxy caching (5)
The following publicly cacheable resources contain a Set-Cookie
header. This security vulnerability can cause cookies to be shared
by multiple users.
- style.css (served by css.domain.tld)
- 2009EMSWeekLogoSmall.jpg (served by domain.tld)
- EMS%20FOUR.jpg (served by domain.tld)
- get_adobe_reader.png (served by img.domain.tld)
- dhs-ntas-badge-small.jpg (served by dhs.gov)
the domain.tld server configuration looks like this.
server {
gzip on;
gzip_static on;
listen 80;
server_name .domain.tld;
root /www/domain/www;
index index.php index.htm index.html;
location ~* \.(htm|html|ico|icns|hqx|gif|png|svg|jpg|jpeg|svg)$ {
expires 1d;
}
include php_fpm;
}
Solution 1:
Identifying a resource to be cached is a non-default behavior. So, whatever is causing this notification by Chrome is an object you specified to be cached.
The directive to cache (public in this case) can be set in 2 ways.
- Your nginx tells it to cache.
- PHP tells it to cache, which is then forwarded by nginx.
Per your above nginx configuration, and ignoring the entire include php_fpm;
, there's nothing which would suggest #1 unless your images (gif, jpg, png) are somehow being executed.
It's also possible that PHP has such cache directive. In such case, it's something you really should be fixing from the core rather than trying to do a patch up job.
But with these two cases, you can also enter an odd scenario. If your image is not found, it will attempt to find a 404 page. And if 404 is an executable (php) either directly or indirectly, it can then carry a set cookie command. This would be a poor behavior if 404 directive is also tells it to be cached. So, be sure to check that as well. The same also obviously applies to any other error codes.
This is about all I can guess given the current information. You may want to follow up with additional information as to which exact item is causing the Chrome to give such message, if there are any errors found as well as full configuration of nginx and/or php-fpm.
I tried looking at the full HTTP headers to see if there's any indication of cookies or any custom information being passed around.
Sample response header from OP's site causing warnings.
telnet img.nassauems.net 80
Trying 205.186.162.66...
Connected to img.nassauems.net.
Escape character is '^]'.
GET http://img.nassauems.net/buttons/get_adobe_reader.png HTTP/1.1
Host: img.nassauems.net
HTTP/1.1 200 OK
Server: nginx/1.2.4
Date: Sat, 12 Jan 2013 20:24:19 GMT
Content-Type: image/png
Content-Length: 2597
Last-Modified: Fri, 28 Dec 2012 08:30:57 GMT
Connection: keep-alive
Expires: Mon, 11 Feb 2013 20:24:19 GMT
Cache-Control: max-age=2592000
Accept-Ranges: bytes
Sample response header from my site that doesn't cause warnings.
telnet www.mysite.com 80
Trying 123.123.123.123...
Connected to www.mysite.com.
Escape character is '^]'.
GET http://www.mysite.com/test.png HTTP/1.1
Host: www.mysite.com
HTTP/1.1 200 OK
Server: nginx/1.0.12
Date: Sat, 12 Jan 2013 20:21:43 GMT
Content-Type: image/png
Content-Length: 207
Last-Modified: Sat, 27 Aug 2011 04:42:30 GMT
Connection: keep-alive
Expires: Sun, 13 Jan 2013 20:21:43 GMT
Cache-Control: max-age=86400
Accept-Ranges: bytes
Can you spot the difference? I can't!
I would label this as a bug with Chrome Audit.
Solution 2:
Although in your case it seems like you might be hitting some bug in the tool that reports that your graphic files contain a Set-Cookie
directive (it's extremely unlikely that you'd be having "Set-Cookie" stuff in static files served directly by nginx with the setup you describe), I have actually encountered a situation where a Java webapp was setting some cookies I didn't want to have set.
This can be addressed through nginx with the following directives placed within the server
context (change proxy_
to fastcgi_
as required):
proxy_hide_header Set-Cookie;
proxy_ignore_headers Set-Cookie;
# important! Remember the special inheritance rules for proxy_set_header:
# http://nginx.org/ru/docs/http/ngx_http_proxy_module.html#proxy_set_header
proxy_set_header Cookie "";
All three directives above are very important: proxy_hide_header
ensures the header will not be passed back to the client, proxy_ignore_headers
ensures that the header will not automatically disable caching within nginx and, finally, proxy_set_header
ensures that a client cannot pass any prior cookies to the webapp and spoil your cache. Note my comment regarding proxy_set_header
inheritance — you cannot nest this directive (have to define all or none at a given level).
Obviously, you will also have to ensure that all your webapps still work after nuking away the cookies in such a way as above. But I know firsthand that the above does work great at getting rid of the HTTP-passed cookies!
Solution 3:
I recently noticed this and and am experiencing the same thing.
I'm confident that this is a bug in Chrome.
- I looked at the response headers in the Safari Web Inspector and it does not show a Set-Cookie either.
- I telnetted directly to my web server and executed a GET request and examined the raw headers, there is no Set-Cookie line.
Chrome may be detecting something and outputting an invalid description, or it might just be a plain bug.
Using Chrome 24.0.1312.52 on OS X
Using Safari Version 6.0.2 (8536.26.17) on OS X