.htaccess of WordPress to improve the security

Last revision: 26 of April of 2020

Table of contents

If you use perhaps Apache httpd or LiteSpeed or any system based on these Web servers interests to you to form the file .htaccess by the root of the configuration of your WordPress of a complex way (more from the one than she comes by defect).

Configurations in concrete blocks

HTTPS via Proxy

It is possible that there is proxy in front of your website, reason why if it is thus, we must inform to the system to tell him that it is already activated and that it does not execute certain elements.

# BEGIN HTTPS via Proxy SetEnvIf X-Forwarded-Proto https HTTPS=on # END HTTPS via Proxy

PageSpeed module

Although it can be a good solution in certain cases, by defect we will form the PageSpeed Module of inactive form by defect since there will be several configurations including which it makes this module in our configuration.

# BEGIN ModPagespeed <IfModule pagespeed_module> ModPagespeed in off </IfModule> # END ModPagespeed

Blockade of .ht<loquesea>

By defect we will block the external accesses to the configuration files, and this same one.

# START - [Security] Blocked the access to files €œ.ht€ and €œ.ftp€ <FilesMatch €œ^ \. ([Hh] [Tt]) €œ> Deny from all </FilesMatch> <FilesMatch €œ^ \. ([FF] [Tt] [Partido popular]) €œ> Deny from all </FilesMatch> # END

To deactivate the listing of directories

Some systems by defect allow that when acceding to a folder that does not have a file of execution by defect shows all the contents. If this it is the case, we can deactivate this default.

# BEGIN Directory browsing <IfModule mod_autoindex.c> Options - Indexes </IfModule> # END Directory browsing

Canonical domain

Although WordPress manages the redirections well and the main domains, in the cases in which we only use a domain, the best thing is to make that management controlled from .htaccess. In this case we formed three elements.

In this first block, we formed the main domain and we realised/we forced his use.

# [Security] Configuration of the canonical domain RewriteCond % \ {HTTP_HOST}! subdomain \ .example \ .com RewriteRule (. *) https://subdomain.example.com% \ {REQUEST_URI} [L, R=308]

Later we verified if or it is not activated the HTTPS and, if the request is not becoming, force.

RewriteCond % \ {HTTPS}! on RewriteRule (. *) https://% \ {HTTP_HOST} % \ {REQUEST_URI} [L, R=308]

€œRare€ request blockade

By general norm requests GET and POST usually are realised, even HEAD. Other request types usually are strange and in very few cases they will be necessary for the use of WordPress.

# [Security] Bloqueamos the requests DRAWS UP and to TRACK RewriteCond % \ {REQUEST_METHOD} ^ (DRAWS UP|TRACK) RewriteRule. * - [F]

Blockade of accesses to files with data

Some habitual files in WordPress include concrete information on versions and some data. Thanks to this code we blocked the accesses to files of reading or licenses.

# [Security] general static Files RewriteRule readme \. (HTML|txt) - [L, R=404] RewriteRule (license|license|LICENSE) \. (HTML|txt) - [L, R=404]

Important files of WordPress

Some files exist that by the information which they contain or by their lack of use can be interesenta to block. The main one is wp-config that includes much information. Others are wp-cron (that are recommended to execute by means of an administrator of tasks, the files of installation of WordPress (once made the installation these are not necessary to execute) and an historical file of management of connections (that the majority of facilities does not use).

# [Security] own Files of WordPress RewriteRule ^wp-config - [L, R=404] RewriteRule ^wp-cron \ .php - [L, R=404] RewriteRule ^wp-admin/(install|setup-config) \ .php - [L, R=404] RewriteRule ^wp-links-opml \ .php$ - [L, R=404]

Blockade of listing of users

Although it is not a serious element that knows the list of users of a site, in some cases it is possible that it is not wanted to have access to cards or pages of the list of users. In order to avoid this we can block the habitual accesses that the own system of permanent connections includes.

# [Security] Bloqueo of listing of users RewriteCond % \ {QUERY_STRING} ^author= [NC] RewriteRule. * - [F, L] RewriteRule ^author/- [F, L]

Blockade of listings of folders

One of the forms of detection of the existence of elements (plugins, themes€¦) it is the detection of the existence of folders. So that the tools of pentesting have more problems, he is better to apply a code 404.

# [Security] Bloqueo of listings of RewriteRule folders ^wp-content/mu-plugins/$ - [L, R=404] RewriteRule ^wp-content/(plugins|themes)/(. +)/$ - [L, R=404]

Blockade of €œuncertain€ files

In some folders a series of elements exists that, by general norm, they do not have because to be or to execute themselves.

# [Security] Bloqueo of uncertain files RewriteRule ^wp-content/uploads/.+ \. (HTML|js|php|shtml|swf) $ - [L, R=403] RewriteRule ^wp-content/plugins/.+ \. (css \ .map|js \ .map|aac|avi|bz2|cur|docx? |eot|exe|flv|gz|heic|htc|m4a|midi? |mov|mp3|mp4|MEP? g|ogg|ogv|otf|pdf|pptx? |to rar|rtf|to tar|tgz|tiff? |ttc|wav|webm|webp|wmv|xlsx? |zip) - [L, R=404]

Other blockades

Some general files of configuration, of logs and similars that by general norm they do not have to be accessible from outside.

# [Security] Other RewriteRule blockades ^sftp-config.json - [L, R=404] RewriteRule (Access|error) _log - [L, R=404] RewriteRule (^#.*#|\. (BAK|config|dist|fla|Inc. |INI|log|psd|sh|SQL|sw [op])|~) $ - [L, R=404]

Access opened to AJAX of the administrator

Independent of the decisions that are taken from blockades, the system of access of AJAX, who can be used from the frontal of the site.

# START - [Functionality] Dejamos access opened to AJAX of the administrator <FilesMatch €œwp-admin/admin-ajax \ .php " > Allow from all </FilesMatch> # END

Mitigation CVE-2018-6389

By general norm he is better to block the possible attack that can be carried out of simple form with the load of all the scripts. In order to avoid it he is better to block his load.

# START - [Security] Mitigation CVE-2018-6389 <FilesMatch €œyou praise (scripts|styles) \ .php " > Deny from all </FilesMatch> # END

Control of the wp-includes

In the folder of the includes usually there are elements that usually are not executed of external form, and by this, generally, he is better to block his execution.

Includes ### START WP RewriteRule ^wp-admin/includes/- [F, L] RewriteRule! ^wp-includes/- [S=3] RewriteRule ^wp-includes/[^/] + \ .php$ - [F, L] RewriteRule ^wp-includes/js/tinymce/langs/.+ \ .php - [F, L] RewriteRule ^wp-includes/theme-compat/- [F, L] ### includes END WP

Simple control of attacks XSS

It avoids very simple attacks of cross-scripting by means of the URL.

### START SQL Injection RewriteCond % \ {QUERY_STRING} (\ <|%3C). *script.* (\ >|%3E) [NC, OR] RewriteCond % \ {QUERY_STRING} GLOBALS (=|\ [|\ % 0.2 [0-9A-Z] \ {}) [OR] RewriteCond % \ {QUERY_STRING} _REQUEST (=|\ [|\ % 0.2 [0-9A-Z] \ {}) RewriteRule ^ (. *) $ index.php [F, L] ### END SQL Injection

An important detail is that if within the panel you manage codes of publicity or other types of scripts, this system can be very aggressive according to the second line (the one that includes scripts), reason why it would be possible to be eliminated.

Code by defect of WordPress

We integrate the code that it recommends to us and usually it generates own WordPress.

RewriteRule ^index \ .php$ - [L] RewriteCond % \ {REQUEST_FILENAME}! - f RewriteCond % \ {REQUEST_FILENAME}! - d RewriteRule. /index.php [L]

To improve uncertain requests

With this all the internal requests that become of the site from HTTP they will happen automatically to HTTPS. In addition other systems are added to force that navigation is made exclusively by HTTPS (HSTS).

# BEGIN Strict-Transport-Security <IfModule mod_headers.c> Header always set Content-Security-Policy: upgrade-insecure-requests; Header always set Strict-Transport-Security €œmax-age=10886400; includeSubDomains; preload€ Header always set X-XSS-Protection €œ1; mode=block€ Header always set X-Content-Type-Options €œnosniff€ Header always set Referrer-Policy €œorigin-when-cross-origin€ </IfModule> # END Strict-Transport-Security

Complete content of .htaccess

The complete file would be of the following way:

# BEGIN HTTPS via Proxy SetEnvIf X-Forwarded-Proto https HTTPS=on # END HTTPS via Proxy # BEGIN ModPagespeed <IfModule pagespeed_module> ModPagespeed in off </IfModule> # END ModPagespeed # START - [Security] Blocked the access to files €œ.ht€ <FilesMatch €œ^ \. ([Hh] [Tt]) €œ> Deny from all </FilesMatch> # END # BEGIN Directory browsing <IfModule mod_autoindex.c> Options - Indexes </IfModule> # END Directory browsing # START regular Expression of WordPress <IfModule mod_rewrite.c> RewriteEngine On # [Security] Configuration of the canonical domain RewriteCond % \ {HTTP_HOST}! subdomain \ .example \ .com RewriteRule (. *) https://subdomain.example.com% \ {REQUEST_URI} [L, R=308] RewriteCond % \ {HTTPS}! on RewriteRule (. *) https://% \ {HTTP_HOST} % \ {REQUEST_URI} [L, R=308] # [Security] Bloqueamos the requests DRAWS UP and to TRACK RewriteCond % \ {REQUEST_METHOD} ^ (DRAWS UP|TRACK) RewriteRule. * - [F] # [Security] general static Files RewriteRule readme \. (HTML|txt) - [L, R=404] RewriteRule (license|license|LICENSE) \. (HTML|txt) - [L, R=404] # [Security] own Files of WordPress RewriteRule ^wp-config - [L, R=404] RewriteRule ^wp-cron \ .php - [L, R=404] RewriteRule ^wp-admin/(install|setup-config) \ .php - [L, R=404] RewriteRule ^wp-links-opml \ .php$ - [L, R=404] # [Security] Bloqueo of listing of users RewriteCond % \ {QUERY_STRING} ^author= [NC] RewriteRule. * - [F, L] RewriteRule ^author/- [F, L] # [Security] Bloqueo of listings of RewriteRule folders ^wp-content/mu-plugins/$ - [L, R=404] RewriteRule ^wp-content/(plugins|themes)/(. +)/$ - [L, R=404] # [Security] Bloqueo of uncertain files RewriteRule ^wp-content/uploads/.+ \. (HTML|js|php|shtml|swf) $ - [L, R=403] RewriteRule ^wp-content/plugins/.+ \. (css \ .map|js \ .map|aac|avi|bz2|cur|docx? |eot|exe|flv|gz|heic|htc|m4a|midi? |mov|mp3|mp4|MEP? g|ogg|ogv|otf|pdf|pptx? |to rar|rtf|to tar|tgz|tiff? |ttc|wav|webm|webp|wmv|xlsx? |zip) - [L, R=404] # [Security] Other RewriteRule blockades ^sftp-config.json - [L, R=404] RewriteRule (Access|error) _log - [L, R=404] RewriteRule (^#.*#|\. (BAK|config|dist|fla|Inc. |INI|log|psd|sh|SQL|sw [op])|~) $ - [L, R=404] </IfModule> # END # START - [Functionality] Dejamos access opened to AJAX of the administrator <FilesMatch €œwp-admin/admin-ajax \ .php " > Allow from all </FilesMatch> # END # START - [Security] Mitigation CVE-2018-6389 <FilesMatch €œyou praise (scripts|styles) \ .php " > Deny from all </FilesMatch> # END # BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteBase/includes ### START WP RewriteRule ^wp-admin/includes/- [F, L] RewriteRule! ^wp-includes/- [S=3] RewriteRule ^wp-includes/[^/] + \ .php$ - [F, L] RewriteRule ^wp-includes/js/tinymce/langs/.+ \ .php - [F, L] RewriteRule ^wp-includes/theme-compat/- [F, L] ### includes END WP ### START SQL Injection RewriteCond % \ {QUERY_STRING} (\ <|%3C). *script.* (\ >|%3E) [NC, OR] RewriteCond % \ {QUERY_STRING} GLOBALS (=|\ [|\ % 0.2 [0-9A-Z] \ {}) [OR] RewriteCond % \ {QUERY_STRING} _REQUEST (=|\ [|\ % 0.2 [0-9A-Z] \ {}) RewriteRule ^ (. *) $ index.php [F, L] ### END SQL Injection RewriteRule ^index \ .php$ - [L] RewriteCond % \ {REQUEST_FILENAME}! - f RewriteCond % \ {REQUEST_FILENAME}! - d RewriteRule. /index.php [L] </IfModule> # END WordPress # BEGIN Strict-Transport-Security <IfModule mod_headers.c> Header always set Content-Security-Policy: upgrade-insecure-requests; Header always set Strict-Transport-Security €œmax-age=10886400; includeSubDomains; preload€ Header always set X-XSS-Protection €œ1; mode=block€ Header always set X-Content-Type-Options €œnosniff€ Header always set Referrer-Policy €œorigin-when-cross-origin€ </IfModule> # END Strict-Transport-Security