If you’re using the File Manager, make sure to enable Show Hidden Files, usually in Settings in Upper Right corner of the File Manager screen.
Included with this tutorial is a secure .htaccess file template for WordPress sites. You may copy its contents into your existing .htaccess file at the bottom, or use it as a reference. This custom made .htaccess file includes all the latest security best-practices for WordPress sites. As always, save a backup copy of your live .htaccess file so you may restore it, if the need arises.
The first section in our .htaccess template, deals with Security Headers. The default settings included in the template below will suit most sites, however there is one section in particular which sometimes requires meticulous customization to get working: Content Security Policy header, which is just a fancy term for specifying “where you allow resources to be loaded from”.
SECURITY HEADERS
Get the coveted A+ or A score for Security Headers, depending on the location of the resources you need to load. The default Security Headers options should work for most, however the Content-Security-Policy (CSP) can take a bit of effort to get just right. If you don’t want to do this step right now, you can skip to the Secure .htaccess Template, since the CSP portion is disabled by default.
Now, there is a long and safe way to create your CSP Security Header or the quick and dirty template way. Let’s present the template way first, but I recommend you to do it properly:
CONTENT SECURITY POLICY: QUICK & DIRTY TEMPLATE METHOD
You have 3 options for prebuilt Content Security Policy (CSP) headers available inside the .htaccess template:
• CSP Option1 gets A+ score. Very Restrictive. Everything must be on https. Scripts are only allowed from your website domain. May prevent page elements from showing up properly without further customization. In some cases may require a developer. You must already have an SSL certificate and your site is on https.
• CSP Option2 gets A score. Less Restrictive. Everything must be on https. Scripts allowed from your domain with allowed Eval which some themes and plugins require. CSP policy may require some customization. Has SSL and site is on https.
• CSP Option3 gets A score. Least Restrictive. EASIEST TO GET WORKING. Edit CSP policy if needed, includes most common domains needed to load the usual WordPress site resources, including bootstrap, google fonts, scripts, youtube, vimeo, amp, etc.
For a quick one-size-fits-all solution, most people may simply use Option3 and it should work as is. Once you’ve copied the below .htaccess template contents to your site’s .htaccess file, simply uncomment (remove #) the directive below Option3 and Save.
Make sure your site works and check a few different pages, if it loads fine run the Security Headers scan at: https://securityheaders.com/.
Tip: Instead of enforcing the Content Security Policy immediately, you may set it to Report violations only without enforcing them (so you can view them in the browser Console – F12). In the .htaccess template below, change this: Header set Content-Security-Policy:
To this:
Header set Content-Security-Policy-Report-Only:
If for whatever reason your site doesn’t load after making changes to your .htaccess file, there is most likely a typo or an extra character somewhere, don’t panic, just add a # again to Comment out that last change (or try to undo with ctrl-z if you’re using some sort of text editor). Worst case scenario, start over with your original .htaccess file and add the below in sections, saving .htacess each time and making sure your site loads.
Another possible scenario is: something isn’t appearing on your website after enabling Content Security Policy, and some resources are clearly not loading. Hit F12 on your keyboard, this will bring up developer tools. This is what it looks like in Firefox, for example, Chrome is very similar.
We’re viewing the Console tab, which is where the pertinent information about Content Security Policy and other errors will show up in red. In this particular example one of the resources was requested over http instead of https.
Another likely example is you see a blocked resource from a domain that is not in our CSP list. Simply add that domain to the list in Option3, in the same format as the others:
*.resourcedomain.com
I strongly recommend that you check the Console tab like above for any Content Security Policy violations, on each different Page of your site.
Note: Very rarely on some shared hosting environments, some of the following directives may cause issues if they are not permitted by the server configuration, so the first thing to try if you get a Server Error 500 is to Comment out (add # to) these: ServerSignature, Options -Indexes. If that still doesn’t resolve the server error or blank screen, start over with the original .htaccess and add the security rules in sections, one by one. Each section is separated by a blank line.
CONTENT SECURITY POLICY: LONG & SAFE METHOD
We’re going to use Report-URI’s CSP wizard tool by Scott Helme to create a custom Content-Security-Policy for your site. Go here and register:
https://report-uri.com/register
After registering and verifying your email, choose Setup in the menu, or go here: https://report-uri.com/account/setup/
In Custom subdomain type a subdomain, anything you want, and click Submit. We’re going to use it in a second.
In your existing .htaccess file, add the following:
<IfModule mod_headers.c> Header set Content-Security-Policy-Report-Only: “default-src ‘none’; form-action ‘none’; frame-ancestors ‘none’; report-uri https://{subdomain}.reporturi.com/r/d/csp/wizard” Header set Report-To: {“group”:”default”,”max_age”:31536000,”endpoints”:[{“url”:”https://{subdomain}.report -uri.com/a/d/g”}],”include_subdomains”:true} Header set NEL: {“report_to”:”default”,”max_age”:31536000,”include_subdomains”:true} </IfModule>
Now replace {subdomain} in two places to the subdomain you just created. Save .htaccess. Make sure your site loads and you haven’t made any typos.
Every time anyone visits your website, this will report the generated policy violations in the background to your Report URI account, which will allow us to generate the CSP policy based on that data. For best results, let this data accumulate naturally through your visitors for 24-48 hours. This does not affect your website performance.
Or, visit your site’s pages yourself, preferably all pages, and preferably using different browsers. This will generate enough necessary data to cover all our bases for the policy. Remember to load your internal dashboard pages too, particularly Page Builder because those always load a lot of assets.
If we don’t include those assets in the policy the Page Builder will simply not work properly. So visit the Edit screen in your backend for your Pages and Posts, and open your plugin and theme Settings pages, too.
After visiting all the possible front-end and back-end pages, go back to Report URI to check the data it has collected. From the menu choose CSP > Wizard, or go here: https://reporturi.com/account/wizard/csp/ .
You’ll see a list of items as such.
You’ll want to select Allow for each one to add it to the CSP policy. There will likely be a lot. To see the newly minted CSP policy, go to CSP > My Policies, or go here: https://reporturi.com/account/policies/csp/.
Select all that code in red and copy-paste it into the red paste-here (use a text editor):
Header set Content-Security-Policy: “PASTE-HERE” Now select and copy this newly created code above, starting with Header set until the end but without including the closing Quotation mark (“) Open your .htaccess, and Paste to overwrite the part in red of the code you added earlier, as such:
<IfModule mod_headers.c> Header set Content-Security-Policy-Report-Only: “default-src ‘none’; form-action ‘none’; frame-ancestors ‘none’; report-uri https://{subdomain}.reporturi.com/r/d/csp/wizard” Header set Report-To: {“group”:”default”,”max_age”:31536000,”endpoints”:[{“url”:”https://{subdomain}.report -uri.com/a/d/g”}],”include_subdomains”:true} Header set NEL: {“report_to”:”default”,”max_age”:31536000,”include_subdomains”:true} </IfModule>
Voila! You’re done creating your custom Content Security Policy! Reporting to Report URI will continue and you can periodically check it for updates.
Since you now have your custom CSP in your .htaccess file, you can safely delete each of #CSP Option 1, 2 and 3 (and the #Header set too) in the .htaccess template that follows.
SECURE .HTACCESS TEMPLATE
#BEGIN WP Defenders secure htaccess – add this to your existing htaccess file
# Security Headers
<IfModule mod_headers.c>
Header set X-XSS-Protection “1; mode=block”
Header always append X-Frame-Options SAMEORIGIN
Header set X-Content-Type-Options nosniff
Header set Strict-Transport-Security “max-age=31536000” env=HTTPS
Header set Referrer-Policy “no-referrer-when-downgrade”
#CSP Option1
#Header set Content-Security-Policy: “default-src https:; script-src https: ‘self’; style-src https:”
#CSP Option2
#Header set Content-Security-Policy: “default-src https:; script-src https: ‘unsafe-inline’ ‘unsafe-eval’; style-src https: ‘unsafe-inline'”
#CSP Option3
#Header set Content-Security-Policy: “default-src ‘self’ ‘unsafe-inline’ ‘unsafeeval’ *.ampproject.org *.akamai.net *.akamaized.net *.bootstrapcdn.com *.callrail.com *.calltrk.com *.cloudflare.com *.cloudfront.net *.doubleclick.net *.facebook.com *.facebook.net *.twitter.com *.google.ca *.googleadservices.com *.googletagservices.com *.google-analytics.com *.googlesyndication.com *.googleapis.com *.google.com *.googletagmanager.com *.gstatic.com *.egads.com *.eqads.com *.vimeo.com *.youtube.com *.ytimg.com *.ggpht.com *.oribi.io *.semrush.com *.zoho.com *.zohostatic.com *.zohopublic.com *.unbounce.com secure.gravatar.com code.jquery.com cdn.jsdelivr.net; img-src ‘self’ * data:; fontsrc ‘self’ * data:; connect-src *; frame-src ‘self’ *.google.com *.twitter.com *.facebook.com *.doubleclick.net”
#The following sets the Feature Policy and should fit the average WordPress website, restricts most fancy features to none or self, except payment and sync-xhr for AJAX so as not to disrupt ecommerce sites, please edit as needed.
Header set Feature-Policy: “geolocation ‘none’;camera ‘none’;microphone ‘none’;midi ‘none’;sync-xhr *;magnetometer ‘none’;gyroscope ‘none’;speaker ‘self’;fullscreen ‘self’;payment *”
</IfModule># Disable the server signature
ServerSignature Off# Pass the default character set UTF8 if your site is in English
#AddDefaultCharset utf-8# Disable directory browsing. This will prevent your file indexes from being displayed if someone tries to access an index file where it doesn’t exist.
Options -Indexes# Protect this htaccess file
<files .htaccess>
order allow,deny
deny from all
</files># Protect wpconfig.php
<files wp-config.php>
order allow,deny
deny from all
</files># Disable xml-rpc, if you use Jetpack keep in mind some features require xml-rpc
<Files xmlrpc.php>
order deny,allow
deny from all
</Files># Require HTTP 1.1 for POST in order to minimize bot attacks
<IfModule mod_rewrite.c>
RewriteCond %{THE_REQUEST} ^POST(.*)HTTP/(0\.9|1\.0)$ [NC] RewriteRule .* – [F,L] </IfModule># Deny unused request types
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_METHOD} ^(delete|trace|track|debug|move|put) [NC] RewriteRule .* – [F,L] </IfModule> #END WP Defenders secure htaccess