Secure apache webserver

Know how to keep the bad guys
at a distance

Go to the menu-list
img alttext

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

Rolling down a narrow tunnel

Editing .htaccess can be tricky,
don't rush into it

List of copy/paste codes for your .htaccess file:

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

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

(Not an advertisement) 


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:

(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: ""

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; script-src-elem 'self' 'nonce-%{UNIQUE_ID}e=' 'sha256-[value]' 'sha256-[value]' 'sha256-[value]'; script-src-attr 'self'; script-src 'self'; style-src-elem 'self' 'nonce-%{UNIQUE_ID}e=' 'sha256-[value]' 'sha256-[value]' 'sha256-[value]'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src data: 'self'; media-src 'self'; frame-src 'self'; 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:


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
#Require not ip 1.2.3
#Require not host gov
#Require not host
Require all granted
Require not ip

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 ^(.*)$$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} (|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.


Social (and other) things: