Hi there,
The htaccess directives below are intended to secure/harden WordPress.
Whilst implementing the directives, it occurred to me that a number of these may be unsupported e.g.
I would appreciate it if the wider community and/or Litespeed team can provide feedback on the directives below and whether the construct below achieves the following.
The htaccess directives below are intended to secure/harden WordPress.
Whilst implementing the directives, it occurred to me that a number of these may be unsupported e.g.
<if></if>
based on the knowledge article at https://www.litespeedtech.com/suppo...iki:config:unsupported_apache_modules_by_lsws . It isn't sufficiently clear as to if this is a complete. I have assumed it is.I would appreciate it if the wider community and/or Litespeed team can provide feedback on the directives below and whether the construct below achieves the following.
- Full support for Litespeed whilst maintaining compatability with Apache
- Secure and if there are any additional improvements
- Performant
- Alternatives if there are particular directives that are not supported by Litespeed.
Apache config:
# BEGIN WordPress
# Instatiate “mod_rewrite” module for Apache
<IfModule mod_rewrite.c>
# Enable Rewrite module
RewriteEngine On
# Declare Rewrite base
RewriteBase /
# Ignore Rewrite condition if index.php is requested
RewriteRule ^index\.php$ - [L]
# Rewrite request if file and/or directory is not present
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
# BEGIN custom directives
# Disable directory listing
Options All -Indexes
# Limit file upload size. If you do not accept file uploads you can configure this at a minimum as per the below. The below is configured for 1MB.
# LimitRequestBody 1024000
# Configure custom error pages
# ErrorDocument 404 /notfound.php
# ErrorDocument 403 /forbidden.php
# ErrorDocument 500 /error.php
# Configure default error pages
# ErrorDocument 401 default
# ErrorDocument 403 default
# Enable Security Headers
<IfModule mod_headers.c>
# X-Frame-Options
Header always set X-Frame-Options "SAMEORIGIN"
# X-XSS-Protection
Header always set X-XSS-Protection "1; mode=block"
# X-Content-Type-Options
Header always set X-Content-Type-Options nosniff
# Referrer-Policy
Header always set Referrer-Policy "strict-origin"
# Content-Security-Policy
# Header set Content-Security-Policy-Report-Only default-src 'self' 'unsafe-inline' https://fonts.googleapis.com; script-src 'self' 'unsafe-inline' https://maps.googleapis.com; frame-ancestors 'self'; block-all-mixed-content; form-action 'self'; font-src 'self' [URL]https://fonts.gstatic.com[/URL] data:; img-src 'self' https://secure.gravatar.com data:;
Header set Content-Security-Policy default-src 'self' 'unsafe-inline' https://fonts.googleapis.com; script-src 'self' 'unsafe-inline' https://maps.googleapis.com; frame-ancestors 'self'; block-all-mixed-content; form-action 'self'; font-src 'self' [URL]https://fonts.gstatic.com[/URL] data:; img-src 'self' https://secure.gravatar.com data:;
# Feature Policy
Header set Feature-Policy "geolocation 'none'; midi 'none'; camera 'none'; usb 'none'; magnetometer 'none'; accelerometer 'none'; vr 'none'; speaker 'none'; ambient-light-sensor 'none'; gyroscope 'none'; microphone 'none'"
# Unset headers revealing versions strings
Header unset X-Powered-By
Header unset X-Pingback
Header unset SERVER
# Disable Entity Tag Header
Header unset ETag
FileETag None
#Set secure cookies
Header always edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure;SameSite=Strict
# Set Keep Alive Header
Header set Connection keep-alive
# Instructs the proxy to store both a compressed and uncompressed version of the resource
<FilesMatch ".(js|css|xml|gz|html|woff|woff2|ttf)$">
Header append Vary: Accept-Encoding
</FilesMatch>
</IfModule>
# Protect number of important WordPress and web server files such as config, ini and log files (this also includes wp-config.php etc)
<FilesMatch "^(wp-config\.php|wp-mail\.php|repair\.php|xmlrpc\.php|php\.ini|php5\.ini|install\.php|php\.info|readme\.html|bb-config\.php|\.htaccess|\.htpasswd|error_log|error\.log|PHP_errors\.log|\.svn|\.log|\.bak|wlwmanifest.xml|\..*)">
Require all denied
</FilesMatch>
# Prevent WordPress usernames from enumerating
RewriteCond %{REQUEST_URI} !^/wp-admin [NC]
RewriteCond %{QUERY_STRING} ^author=\d+ [NC,OR]
RewriteCond %{QUERY_STRING} ^author=\{num [NC]
RewriteRule ^(.*)$ - [F,L]
# Block access to WordPress login page from malformed requests
RewriteCond %{REQUEST_METHOD} POST
RewriteCond %{REQUEST_URI} ^(.*)?wp-login\.php(.*)$ [NC,OR]
RewriteCond %{REQUEST_URI} ^(.*)?wp-admin?(/)$ [NC]
RewriteCond %{HTTP_REFERER} !(.*)domain\.co(.*) [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^-?$ [OR]
RewriteCond %{HTTP_USER_AGENT} ^.*(jorgee|morfeusfirefox\/34.0|mozilla\/4.0|firefox\/40.1).* [NC]
RewriteRule ^(.*)$ - [F,L]
# Restrict access to WordPress PHP files from plugin and theme directories
RewriteCond %{REQUEST_URI} ^(.*)?wp-content/plugins/(.*\.php)$ [NC]
RewriteRule ^(.*)$ - [F,L]
RewriteCond %{REQUEST_URI} ^(.*)?wp-content/themes/(.*\.php)$ [NC]
RewriteRule ^(.*)$ - [F,L]
# Block access to WordPress includes folder
RewriteCond %{REQUEST_URI} ^(.*)?wp-admin/includes/(.*\.php)$ [NC, OR]
RewriteCond %{REQUEST_URI} ^(.*)?wp-includes/js/tinymce/langs/(.*\.php)$ [NC, OR]
RewriteCond %{REQUEST_URI} ^(.*)?wp-includes/theme-compat/(.*\.php)$ [NC]
RewriteRule ^(.*)$ - [F,L]
<If "%{REQUEST_URI} =~ m#^(.*)?/wp-content/uploads/(.*\.txt)#">
Require all denied
</If>
# Block Nuisance Requests
# https://perishablepress.com/block-nuisance-requests
<IfModule mod_alias.c>
# RedirectMatch 403 (?i)\.php\.suspected
# RedirectMatch 403 (?i)\.(git|well-known)
# RedirectMatch 403 (?i)apple-app-site-association
# RedirectMatch 403 (?i)/autodiscover/autodiscover.xml
RewriteCond %{REQUEST_URI} ^(.*)?(\.php\.suspected|\.well-known|\.git|apple|autodiscover)(.*)$ [NC]
RewriteRule ^(.*)$ - [F,L]
</IfModule>
# Blocking the »ReallyLongRequest« Bandit
# https://perishablepress.com/blocking-reallylongrequest-bandit/
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_METHOD} .* [NC]
RewriteCond %{THE_REQUEST} (YesThisIsAReallyLongRequest|ScanningForResearchPurpose) [NC,OR]
RewriteCond %{QUERY_STRING} (YesThisIsAReallyLongRequest|ScanningForResearchPurpose) [NC]
RewriteRule ^(.*)$ - [F,L]
</IfModule>
# 6G FIREWALL/BLACKLIST
# @ https://perishablepress.com/6g/
# 6G:[QUERY STRING]
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{QUERY_STRING} (eval\() [NC,OR]
RewriteCond %{QUERY_STRING} (127\.0\.0\.1) [NC,OR]
RewriteCond %{QUERY_STRING} ([a-z0-9]{2000,}) [NC,OR]
RewriteCond %{QUERY_STRING} (javascript:)(.*)(;) [NC,OR]
RewriteCond %{QUERY_STRING} (base64_encode)(.*)(\() [NC,OR]
RewriteCond %{QUERY_STRING} (GLOBALS|REQUEST)(=|\[|%) [NC,OR]
RewriteCond %{QUERY_STRING} (<|%3C)(.*)script(.*)(>|%3) [NC,OR]
RewriteCond %{QUERY_STRING} (\\|\.\.\.|\.\./|~|`|<|>|\|) [NC,OR]
RewriteCond %{QUERY_STRING} (boot\.ini|etc/passwd|self/environ) [NC,OR]
RewriteCond %{QUERY_STRING} (thumbs?(_editor|open)?|tim(thumb)?)\.php [NC,OR]
RewriteCond %{QUERY_STRING} (\'|\")(.*)(drop|insert|md5|select|union) [NC]
RewriteRule .* - [F]
</IfModule>
# 6G:[REQUEST METHOD]
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_METHOD} ^(connect|debug|move|put|trace|track) [NC]
RewriteRule .* - [F]
</IfModule>
# 6G:[REFERRER]
<IfModule mod_rewrite.c>
RewriteCond %{HTTP_REFERER} ([a-z0-9]{2000,}) [NC,OR]
RewriteCond %{HTTP_REFERER} (semalt.com|todaperfeita) [NC]
RewriteRule .* - [F]
</IfModule>
# 6G:[REQUEST STRING]
<IfModule mod_alias.c>
RedirectMatch 403 (?i)([a-z0-9]{2000,})
RedirectMatch 403 (?i)(https?|ftp|php):/
RedirectMatch 403 (?i)(base64_encode)(.*)(\()
RedirectMatch 403 (?i)(=\\\'|=\\%27|/\\\'/?)\.
RedirectMatch 403 (?i)/(\$(\&)?|\*|\"|\.|,|&|&?)/?$
RedirectMatch 403 (?i)(\{0\}|\(/\(|\.\.\.|\+\+\+|\\\"\\\")
RedirectMatch 403 (?i)(~|`|<|>|:|;|,|%|\\|\{|\}|\[|\]|\|)
RedirectMatch 403 (?i)/(=|\$&|_mm|cgi-|muieblack)
RedirectMatch 403 (?i)(&pws=0|_vti_|\(null\)|\{\$itemURL\}|echo(.*)kae|etc/passwd|eval\(|self/environ)
RedirectMatch 403 (?i)\.(aspx?|bash|bak?|cfg|cgi|dll|exe|git|hg|ini|jsp|log|mdb|out|sql|svn|swp|tar|rar|rdf)$
RedirectMatch 403 (?i)/(^$|(wp-)?config|mobiquo|phpinfo|shell|sqlpatch|thumb|thumb_editor|thumbopen|timthumb|webshell)\.php
</IfModule>
# 6G:[USER AGENT]
<IfModule mod_setenvif.c>
SetEnvIfNoCase User-Agent ([a-z0-9]{2000,}) bad_bot
SetEnvIfNoCase User-Agent (archive.org|binlar|casper|checkpriv|choppy|clshttp|cmsworld|diavol|dotbot|extract|feedfinder|flicky|g00g1e|harvest|heritrix|httrack|kmccrew|loader|miner|nikto|nutch|planetwork|postrank|purebot|pycurl|python|seekerspider|siclab|skygrid|sqlmap|sucker|turnit|vikspider|winhttp|xxxyy|youda|zmeu|zune) bad_bot
# Block IPs with 6G Firewall
# https://perishablepress.com/block-ips-6g-firewall/
# Apache < 2.3
<IfModule !mod_authz_core.c>
Order Allow,Deny
Allow from all
Deny from env=bad_bot
</IfModule>
# Apache >= 2.3
<IfModule mod_authz_core.c>
<RequireAll>
Require all Granted
Require not env bad_bot
</RequireAll>
</IfModule>
</IfModule>
# END custom directives
Last edited by a moderator: