I've discovered an interesting issue when attempting to use Content Security Policy to secure my site and also ServiceWorker to speed it up and let it run offline.
It's a standard Wordpress site and Plugin developers have a naughty habit of using external resources, particularly in the /wp-admin/ section. I don't what to whitelist a ton of stuff on the main site (particularly unsafe-eval, a frequent culprit in the admin section), so what I did was make a main CSP, then in /wp-admin/ I unset and reset a less restrictive set.
Here's a sample of the code I'm using to unset the CSP when you're in the admin area of the site:
<Location /wp-admin/>
<IfModule mod_headers.c>
Header always unset Content-Security-Policy
Header unset Content-Security-Policy
Header set Content-Security-Policy " default-src 'self' ps.w.org;"
</IfModule>
</Location>
And it works fine unless you've been to (or have another tab open to) the main area of the site, at which point the ps.w.org directive (and others) are ignored. A bunch of assets end up blocked, scripts don't work, etc. Refreshing the page while in the admin section temporarily loads the correct CSP, so I know it's being used; it's just being overwritten by the main one. Sometimes the same happens to the main site, loading the admin CSP too.
Is the ServiceWorker caching the CSP or what exactly is going on here? Is there some way to get the ServiceWorker to respect the CSP that page should be sending in it's headers? For now I've just merged the two CSP settings into one and removed my over-broad rules for the admin area but it's not ideal.
Related
On one of my sites I have Header set Strict-Transport-Security "max-age=31536000" env=HTTPS and this was enough for HSTS to be preloaded but the exact same snippet in my .htaccess file doesn't allow preloading on another site. I've went with Header set Strict-Transport-Security: "max-age=31536000; includeSubDomains; preload" env=HTTPS which fixed the issue but I'm wondering why the shorter version worked and preloaded a the first site but not the second?
Any insight would be appreciated.
why the shorter version worked
The short version couldn't have "worked". It would have been sufficient to implement HSTS, but not to have been accepted for the HSTS preload list.
Something else in your config must have been sending the complete header.
The only way to confirm what is actually going on is to record the HTTP request/response headers being sent on the request, not by the directives in your (.htaccess?) config file.
Even the directive you posted is not necessarily sufficient by itself. You must have something that is setting the HTTPS environment variable (this is not the same as the HTTPS server variable). And if you have canonical redirects from www to non-www (or vice versa) then you are missing the always argument to set the header on the 301 redirect (HTTPS only) - which is also a requirement of the "preload list".
It is far easier and less prone to error to implement HSTS "preload" in the server config. If you only have access to .htaccess then I would be hesitant to go for "preload list" submission.
See also my answer to the following related question on CodeReview SE:
https://codereview.stackexchange.com/questions/250805/hsts-recommendations-in-htaccess
I have a specific question regarding satisfying the Pingdom Tools criteria of "Serve the following static resources from a domain that doesn't set cookies".
My situation is quite specific and I've googled extensively, followed multiple guides and even went as far as asking my hosting provider but didn't get help there (which I assumed).
This is my scenario:
I have a website called "www.wheretofarminwow.com" and I've run the speed test at tools.pingdom.com and I get the "Serve the following static resources from a domain that doesn't set cookies" message.
I've moved the static files from wheretofarminwow.com to another site wtfiwstatic.com
And I assumed that domain "www.wtfiwstatic.com" would be cookieless because it doesn't doesn't do anything but just host those static files, but I keep on getting that "Serve the following static resources from a domain that doesn't set cookies" message from Pingdom.
I've even added a htaccess rule on that domain to try to not set any cookies:
<IfModule mod_headers.c>
<FilesMatch "\.(ttf|ttc|otf|eot|woff|woff2|font.css|css|js|jpg|jpeg|png|gif)$">
Header set Access-Control-Allow-Origin "*"
Header append Vary: Accept-Encoding
RequestHeader unset Cookie
Header unset Cookie
Header unset Set-Cookie
</FilesMatch>
</IfModule>
Hoping the bright community at Stack overflow could give me some insight on my situation and perhaps guide me to achieve my goal.
Thanking in advance,
Johnny
Ok, I think I figured it out.
It turns out as I was using Cloudflare on wtfiwstatic.com, Cloudflare sets a cookie to every request for security reasons and can't be disabled. Hope this helps someone in a similar situation.
Sources:
https://www.keycdn.com/support/how-to-use-cookie-free-domains/
https://support.cloudflare.com/hc/en-us/articles/200169816-Can-I-serve-a-cookieless-domain-or-subdomain-through-Cloudflare-
I'm running and Amazon EC2 with Ubuntu 14.4 and Apache2 with no PHP or other server-side script--just a static content site. I used this tutorial to get to the point I am at now with the apache file (see screenshot at link below):
https://www.digitalocean.com/community/tutorials/how-to-configure-apache-content-caching-on-ubuntu-14-04
I want to have a directive (if that is the nomenclature) that tells Apache to not cache a single, specific file only, but still handle everything else as it is already configured. I'm no computer whizz here--just learning. Is there a way to do this? Currently I have made a new directory inside my images folder called "no-cache" where the image I do not want cached lives.
I tried adding a second location tag below the first one with "CacheDisable on" inside it, however this is not supported. Also tried using a Directory tag, but this also does not work with the current configuration.
Thanks in advance!
/etc/apache2/sites-enabled/000.default.conf
The link you provided is a bit confusing since it mentions so many different types of caching.
When dealing with Webservers and caching, what you usually mean is sending cache messages (using http headers) to define how the browser should handle caching, to improve visitors performance. This is the last item discussed in that link of yours, despite being the most common. The first section talks about Apache caching files itself to improve its own performance and is much less common.
If client side caching using mod_expiries is what you mean, then you can control this with location headings:
#Allow long term assets to be cached for 6 months as they are versioned and should never change
<Location /assets/libraries/ >
ExpiresDefault A15724800
Header set Cache-Control "public"
</Location>
#Do not cache these files
<Location /login >
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
</Location>
I've a more detailed blog on this here: https://www.tunetheweb.com/performance/http-performance-headers/caching/.
I have a uWSGI service running behing an apache front-end. The part of my apache conf handling that lools like:
<Location /myapp>
SetHandler uwsgi-handler
uWSGISocket /var/run/uwsgi/myapp.sock
Allow from all
</Location>
and I'd like to add a custom header to the responses of my app. I know I can do that by adding some code in the app, but I would prefer doing it with mod_headers, by adding the following line in the Location directive
Header set Custom-Header "hello world"
It does not seem to work, although mod_headers documentation states
This directive can replace, merge or remove HTTP response headers.
The header is modified just after the content handler and output filters are run,
allowing outgoing headers to be modified.
What do I do wrong, or understand wrong?
As stated in the docs mod_uwsgi is very raw and uses the 'assbackwards' mode, unless you enable the CGI mode. This mode (assbackwards) gives superior performance but breaks basically all of the filters. You should use mod_proxy_uwsgi (fully apache-friendly) or let uWSGI do the hard work for you using the internal routing:
http://uwsgi-docs.readthedocs.org/en/latest/InternalRouting.html
(or the --add-header more invasive option)
We have been attempting to configure our server not to cache our .htm files as it is causing a few issues with our analytics package as well as not displaying the pages correctly if the visitor hits the back button in their browser.
We have attempted to tackle it by adding:
<FilesMatch "\.(htm)$">
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
Header set Warning "Testing"
</FilesMatch>
to our httd file but it does not appear to execute, however, when we move the Header set outside of the FilesMatch it appears to execute fine..
Anyone have any ideas where we are going wrong?
I recently needed to figure out the same kind of problem and, although this post pointed me in the right direction, I wanted to share some clarifying information for the edification of those who search on this topic in the future.
David, your initial FilesMatch was not working because FilesMatch only works on real, physical files that exist on your filesystem. http://httpd.apache.org/docs/current/sections.html states it as:
The Directory and Files directives, along with their regex counterparts, apply directives to parts of the filesystem.
This is also why your second post using LocationMatch resolved the issue. Also from http://httpd.apache.org/docs/current/sections.html, it states:
The Location directive and its regex counterpart, on the other hand, change the configuration for content in the webspace. < SNIP > The directive need not have anything to do with the filesystem. For example, the following example shows how to map a particular URL to an internal Apache HTTP Server handler provided by mod_status. No file called server-status needs to exist in the filesystem.
<Location /server-status>
SetHandler server-status
</Location>
The Apache docs summarizes this behavior with the following statement:
Use Location to apply directives to content that lives outside the filesystem. For content that lives in the filesystem, use Directory and Files. An exception is < Location / >, which is an easy way to
apply a configuration to the entire server.
For those that want to understand more of the mechanics, this is how I understand the internals:
Location directives match based on the HTTP request URI (e.g. example.com/this/is/a/uri.htm without the example.com part).
Directory and Files directives, on the other hand, match based on whether there is a directory path or file in the filesystem of the DocumentRoot that matches to respective part of the the HTTP request URI
The Apache docs summarizes this behavior as:
What to use When
Choosing between filesystem containers and webspace containers is actually quite easy. When applying directives to objects that reside in the filesystem always use Directory or Files. When applying directives to objects that do not reside in the filesystem (such as a webpage generated from a database), use Location.
[IMPORTANT!] It is important to never use Location when trying to restrict access to objects in the filesystem. This is because many different webspace locations (URLs) could map to the same filesystem location, allowing your restrictions to be circumvented.
This issue has now been resolved.
In order to get it to work we have changed from using FilesMatch to LocationMatch and now the headers are being set perfectly.
We believe this is because the page is being redirected from a JSP page to an HTML page.
<LocationMatch "\.(htm|html)$">
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
Header set Warning "Testing"
</LocationMatch>
Hopefully others will find this helpful.