Hardening the entrance by using .htaccess
If you want to harden your website against attacks, the first thing to do is to close the front-door to keep hackers outside. The webserver is your frontdoor, you can give it instructions on how to help you make your website more secure.
The .htaccess file is a textfile that sits in your root-directory. You can write instructions in that file for the webserver, to tell him how to behave under certain circumstances and by default.
Below you will find some of the measurents that you can take.
And if you want an easy way to see the headers your server sends, then you can use the Chrome-inspection tool
Editing .htaccess can be tricky,
don't rush into it
Disable anyone to view the .htaccess file ↑
Not doing this is enabling others to study your settings
for vulnerabilities, deny access to it:# Protect .htaccess file #
<Files .htaccess>
Require all denied
</Files>
Disable anyone to view any directory ↑
This disables viewing a list of files in one of your websites' directories,
it's nobody's business so don't allow access:# No browsing in directories #
Options -Indexes
Not an advertisement, but looks like it
mod_headers ↑
This module makes it possible to change several very important headers,
it needs to start with:<ifModule mod_headers.c>- Then all the lines with mod_headers-codes
- Then a line which closes mod_headers:
</IfModule>(See below for mod_headers-implications)
mod_headers: Set Strict Transport Security ↑
When you have your site running HTTPS, then you can tell browsers in front
to only render the page using HTTPS and to do that for a long while to go.
An extra layer can be added to it:After you have setup HSTS go to the preload-website and submit your site.
# (H)STS Strict Transport Security #
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" "expr=%{HTTPS} == 'on'"
Unset several headers ↑
Because nobody needs to know what software your server is running on so don't tell them.
By default the server gives several kinds of enclosures, this can cause vulnerabilities.
Swith them off!
# Unset several headers
Header always unset Server
Header always unset X-Powered-By
Header unset X-Powered-By
Header unset X-CF-Powered-By
Header unset X-Mod-Pagespeed
Header unset X-Pingback
SRI: Subresource Integrity ↑
SRI short: you use this when you want to be sure that external scripts or stylesheets loaded by your website, are exactly as you expect. Meaning: no one has come in between to change the sourcecode
This is not as easy as most of the other security-measures: it involves using hashes with every script or stylesheet and adding that same hash to your .htaccess-file. This way, when the file changes, it's hash changes too and they do not correspond anymore, so the file will not be loaded.
Example: to your CSP after script-src you add the hash like 'sha256-[value]'
And to the script you add it as follows:<script integrity="sha256-[value]" crossorigin="anonymous">Reminder: when the script changes and you add a new version, remember to upgrade the hash too!
mod_headers: CORS headers ↑
With these headers you can specify certain types of features that can be included in your page from an external source, the idea is that the external source also adds a CORS-header in which it specifically allows your domain to use certain sources.
Where in other headers we restrict access (like with "same-origin"), with CORS-headers we specify what we allow. Not everybody needs these headers, that depends on the website you're maintaining yourself.
CORS headers could look like:# Set CORS headers #
Header add Access-Control-Allow-Origin: "https://example.com https://anotherexample.com"
Header always set Access-Control-Allow-Credentials true
Header always set Access-Control-Allow-Headers: *
mod_headers: CORP headers ↑
This header is sent by the server to instruct the client to block access to a specific resource. This is intended to protect resources against certain types of attacks.
# Setup CORP #
Header set Cross-Origin-Resource-Policy: "same-origin"
mod_headers: Xss-protection ↑
This is a deprecated header, but can still be used for older browsers. Most newer browsers removed support for this header.
# Xss-protection for older browsers #
header set X-XSS-Protection: mode=block
mod_headers: Avoid MIMEtype attacks ↑
An attacker can leverage MIME sniffing to deploy an XSS attack.
Protect your site against MIME sniffing vulnerabilities:# X-Content-Type-Options (avoid MIMEtype attacks) #
Header always set X-Content-Type-Options "nosniff"
mod_headers: More anti-XSS: CSP ↑
CSP (Content Security Policy) is a way of telling browsers to only parse code that comes from specifies sources, this avoids malicious third-party includes to run in your browsing-session.
This is not as simple as the rules above, you need to know which third-party scripts, images etc. you are including in your website, you can use f.e. the Chrome inspection tool to see where your website is getting it's recources from. Below an example of how to tell the users' browser what to accept and what not, you will have to do a thorough search on this subject to find out which settings apply to your own situation.
In this example we are giving directions for general inclusions (default-src), image-inclusions (img-src), script-inclusions (script-src) and style-inclusions (style-src):'unsafe-inline': this is a value that is often used because certain scripts do not work anymore after implying a CSP, but it is not safe.
In the example below you can see it being used in the style-src directive and this could be exploited, but because all the other directives are very explicit about the sources it will not be possible to load an external script f.e., so this should not escalate too widely, but it cán do things like a hacker changing your whole website or pieces of the content.# Content security policy
Header set Content-Security-Policy "frame-ancestors 'none'; default-src 'none'; base-uri 'self'; form-action 'self'; object-src 'none'; connect-src https://somesite.com; script-src-elem 'self' 'nonce-%{UNIQUE_ID}e=' https://somesite.com 'sha256-[value]' 'sha256-[value]' 'sha256-[value]'; script-src-attr 'self'; script-src 'self'; style-src-elem 'self' 'nonce-%{UNIQUE_ID}e=' https://exdomo.com 'sha256-[value]' 'sha256-[value]' 'sha256-[value]'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src data: 'self' https://somesite.com; media-src 'self'; frame-src 'self' https://www.youtube.com/; worker-src 'self'"
mod_headers: Referrer policy ↑
The referrer policy tells the users' webbrowser to send your website as referrer ("same-origin") when a user clicks on a link that goes to an external website,
you don't want your website to send false information,
so always set this header:# Referrer Policy #
Header set Referrer-Policy "strict-origin-when-cross-origin"
mod_headers: Permissions-Policy ↑
The Permissions-Policy (former: Feature Policy) is a way to handle certain features on your website
like the use of the camera or microphone, autoplay, getting the battery status, allowing geo-lookup, allowing or disallowing taking screenshots etc.
For example if you want to be sure that no malicious (third-)party code that "slipped through" is able to activate the users microphone and camera, then use the example below, that only gives access to your website itself:# Permissions Policy #
Header set Permissions-Policy "camera=(self), microphone=(self)"
Close mod_headers ↑
Don't forget to close mod-headers:
</IfModule>
Blocking IP-adresses ↑
Besides using the techniques as mentioned above, you can also block IP-numbers, or ranges of IP-numbers directly like:
# Block IP-numbers (with examples)
#Require not ip 1.2.3.0/24
#Require not ip 1.2.3
#Require not host gov
#Require not host example.com
<RequireAll>
Require all granted
Require not ip 1.2.3.0
</RequireAll>
More security-measures ↑
Instead of blocking, you can also use redirect-rules or rewrite-rules to handle certain requests that could be of malicious intent or install a bad-bot pit / honeypot to which bad requests are being redirected,
For example: redirect a potential attacker to a certain directory based on a request which containes the string "content", since you don't have a webpage with this string in the name, there's no reason to try and find something there (add a line to robots.txt too, to tell searchbots to stay away):
If you want you could add a script to your bad-bot pit that blocks the ip-adresses too
# Redirect common bad requests to a certain page #
RedirectMatch 301 "(?i)(.*)content" "/mybadbotpit/"Instead of redirecting, you can also use the rewrite rules (don't forget to first turn the rewrite engine on), if you want every request for HTTP rewritten to HTTPS then you can do something like this:
# Force HTTPS #
RewriteEngine On
RewriteBase /
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://mysafewebsite.com/$1 [R=301,L]You can set several conditions under which a rewrite rule should be executed, for example you can rewrite based on a query-string:
RewriteCond %{QUERY_STRING} (notallowed|donotenter) [NC,OR]On a requested URL:
RewriteCond %{REQUEST_URI} (/)(notallowed|donotenter) [NC,OR]On the user-agent:
RewriteCond %{HTTP_USER_AGENT} (badbot|morebadcrawlers) [NC,OR]On the remote host:
RewriteCond %{REMOTE_HOST} (intruder|somebadhost) [NC]On the http-referer:
RewriteCond %{HTTP_REFERER} (badsite.com|badstring) [NC,OR]Or on the request method:
RewriteCond %{REQUEST_METHOD} ^(connect|dosomethingbad) [NC]There are many ways to use these redirect- and rewrite rules based on the content of your website,
do a thorough web-search for these kinds of approaches.