Skip to content

Instantly share code, notes, and snippets.

@Zodiac1978
Last active June 23, 2024 17:39
Show Gist options
  • Save Zodiac1978/d25a8f3aebba7cd1c01c to your computer and use it in GitHub Desktop.
Save Zodiac1978/d25a8f3aebba7cd1c01c to your computer and use it in GitHub Desktop.
Safer WordPress with these .htaccess additions
# Don't show errors which contain full path diclosure (FPD)
# Use that line only if PHP is installed as a module and not per CGI
# try using a php.ini in that case.
# Change mod_php5.c to mod_php7.c if you are running PHP7
<IfModule mod_php5.c>
php_flag display_errors Off
</IfModule>
# Don't list directories
<IfModule mod_autoindex.c>
Options -Indexes
</IfModule>
# PROTECT install.php
# Uncomment or change to 'Allow from all' for install of WordPress
<Files install.php>
Order Allow,Deny
Deny from all
Satisfy all
</Files>
# Protect XMLRPC (needed for Apps, Offline-Blogging-Tools, Pingback, etc.)
# If you use that, these tools will not work anymore
<Files xmlrpc.php>
Order Deny,Allow
Deny from all
</Files>
# If you don't use the Database Optimizing and Post-by-Email features, turn off the access too:
<FilesMatch "(repair|wp-mail)\.php">
Order Deny,Allow
Deny from all
</FilesMatch>
# Prevent browser and search engines to request .log (e.g. WP DEBUG LOG) and .txt (e.g. plugins readme) files.
# Must be placed in /wp-content/.htaccess
<FilesMatch "\.(log|txt)$">
Order Allow,Deny
Deny from all
</FilesMatch>
# Hide WordPress, system & sensitive files
<FilesMatch "(^\.|wp-config(-sample)*\.php)">
Order Deny,Allow
Deny from all
</FilesMatch>
# Protect some other files
<FilesMatch "(liesmich.html|readme.html|license.txt|(.*)\.bak)">
Order Deny,Allow
Deny from all
</FilesMatch>
# Block the include-only files.
# Do not use in Multisite without reading the note in Codex!
# See: https://wordpress.org/support/article/hardening-wordpress/#securing-wp-includes
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^wp-admin/includes/ - [F,L]
RewriteRule !^wp-includes/ - [S=3]
# If you run multisite, comment the next line out (see note above)
RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
RewriteRule ^wp-includes/theme-compat/ - [F,L]
</IfModule>
# Set some security related headers
# See: http://de.slideshare.net/walterebert/die-htaccessrichtignutzenwchh2014 (GERMAN)
<IfModule mod_headers.c>
Header set X-Content-Type-Options nosniff
Header set X-XSS-Protection "1; mode=block"
# The line below is an advanced method for a more secure configuration, please see documentation before usage!
# Introduction: https://scotthelme.co.uk/content-security-policy-an-introduction/
# http://www.heise.de/security/artikel/XSS-Bremse-Content-Security-Policy-1888522.html (German)
# Documentation: https://content-security-policy.com/
# Analysis: https://securityheaders.io/
# Header set Content-Security-Policy "default-src 'self'; img-src 'self' http: https: *.gravatar.com;"
</IfModule>
# Allow WordPress Embed
# https://gist.github.com/sergejmueller/3c4351ec29576fb441fe
<IfModule mod_setenvif.c>
SetEnvIf Request_URI "/embed/$" IS_embed
<IfModule mod_headers.c>
Header set X-Frame-Options SAMEORIGIN env=!REDIRECT_IS_embed
</IfModule>
</IfModule>
#Force secure cookies (uncomment for HTTPS)
<IfModule mod_headers.c>
# Header edit is requiring Apache 2.2.4 or above
# Header always edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure
# For Apache lower than 2.2.4 you can use this:
# Header set Set-Cookie HttpOnly;Secure
# Source: https://geekflare.com/httponly-secure-cookie-apache/
</IfModule>
#Unset headers revealing versions strings
<IfModule mod_headers.c>
Header unset X-Powered-By
Header unset X-Pingback
Header unset SERVER
</IfModule>
# Filter Request Methods
# See: https://perishablepress.com/disable-trace-and-track-for-better-security/
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^(TRACE|DELETE|TRACK) [NC]
RewriteRule ^(.*)$ - [F,L]
</IfModule>
Copy link

ghost commented Aug 2, 2017

Thank you for this. It does help a lot.
However, is there a way to place the HTTP Security Headers in "wp-config.php" instead of in ".htacess" or "functions.php"? That would really simplify what I'm working on. Each time I try it it stops WordPress from loading.

Thank you in advance.

@fdenis83
Copy link

Curious, Is this meant to be in a second .htaccess file within the wp-content? I notice if you use this in the root htaccess it blocks robots.txt, which could effect website ranking.

@vladlu
Copy link

vladlu commented Mar 25, 2019

Maybe rewrite Order Deny Allow with Require?

@Zodiac1978
Copy link
Author

@fdenis83 Yes, this single block needs to be in a second .htaccess in /wp-content. Maybe I can set up a better solution soon.
https://gist.github.com/Zodiac1978/d25a8f3aebba7cd1c01c#file-htaccess-L28

@dgallegos
Copy link

dgallegos commented Aug 7, 2019

I had an issue with this, but due to using a managed WordPress I couldn't edit the .htaccess files or they didn't seem to be working. I needed this fix because a Wordpress site I administer failed a payment processor security scan with the error "Non-HttpOnly Session Cookies Identified".

I was able to pass the scan with the following gist added to my functions.php.

https://gist.github.com/dgallegos/1a7373002e5f9959315b0a6c31bd72ac

@goonee
Copy link

goonee commented Sep 27, 2022

I was wondering about the "#Force secure cookies (uncomment for HTTPS)", it looks like there's a hash mark on the line of code " #Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure," which would result in it not getting parsed. Is that an error here?

Secondly, I've tried adding that to my Security Headers (minus the #), but looking at my results from https://observatory.mozilla.org/, it says "No cookies detected," any idea what might be the problem?

@Zodiac1978
Copy link
Author

Zodiac1978 commented Sep 28, 2022

@goonee

Is that an error here?

No. The explanation is in the comment above. "(uncomment for HTTPS)". Because not every website is on https, I commented this out to not break websites after copy & pasting this code. If your website is on https you can (and should) uncomment this.

any idea what might be the problem?

If there are no cookies set then there is no need to send them with secure flag ;)

@goonee
Copy link

goonee commented Sep 30, 2022

@goonee

Is that an error here?

No. The explanation is in the comment above. "(uncomment for HTTPS)". Because not every website is on https, I commented this out to not break websites after copy & pasting this code. If your website is on https you can (and should) uncomment this.

any idea what might be the problem?

If there are no cookies set then there is no need to send them with secure flag ;)

Thanks for the info! Sorta new to this, so just trying to navigate through it all best I can:)

@robi052
Copy link

robi052 commented May 8, 2023

Hi,

In cpanel server info see Apache Version | 2.4.57. Header always edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure dont work, but work Header set Set-Cookie HttpOnly;Secure. But why and how remove set-cookie | PH_HPXY_CHECK=s1; path=/. When scan website on securityheaders.com or other websites see both line

  1. set-cookie | HttpOnly;Secure;SameSite=Strict
  2. set-cookie PH_HPXY_CHECK=s1; path=/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment