WordPress Best Practices for Security
WordPress Security Best Practices on Azure App Services (Windows/Linux)
NOTICE After November 28, 2022, PHP will only be supported on App Service on Linux.
Best Practices
When it comes to Security, there are a few Best Practices recommended when using Azure App Services.
- Modifications in
wp-config.php
file:- Change default
$table_prefix
fromwp_
to a unique string - Utilize the encoding for Keys and Salts
- Disable File Editing with:
define('DISALLOW_FILE_EDIT', true);
- This will remove
edit_themes
,edit_files
, andedit_plugins
capabilities to all users.
- This will remove
- Change default
- DO NOT use weak passwords or usernames like: admin, administrator, test123, password, etc.
- Keep WordPress updated.
- Backup regularly
- Use Backups for Azure App Services.
- Web Server config modifications
- Restrict/Limit access to
wp-config.php
andwp-login.php
- Prevent clickjacking with header:
X-FRAME-OPTIONS = SAMEORIGIN
- Restrict/Limit access to
- Delete
xml-rpc.php
if not used - Enable Static/Dynamic IP Restrictions
- PHP modifications:
- Reduce XSS Attacks:
- Add
session.cookie_httponly = true
inphp.ini
or.user.ini
- Add
- Reduce XSS Attacks:
- Use a WordPress security plugin
Modifications in wp-config.php
- Change the
$table_prefix
fromwp_
to something unique.- Example:
$table_prefix = 'mysite_';
- Example:
- Utilize the encoding for Keys and Salts
- You can generate these using the following: https://api.wordpress.org/secret-key/1.1/salt/
- Disable File Editing by adding
define('DISALLOW_FILE_EDIT', true);
- This will remove
edit_themes
,edit_files
, andedit_plugins
capabilites to all users.
- This will remove
Password Recommendations
It is always recommended to use a strong password for WordPress. This should include some of the following examples:
- Uppercase and lowercase characters
- Numbers
- Special haracters (@, #, *, etc.)
- A minimum of 10 characters preferred.
- Avoid using common phrases like: admin, administrator, test, password, 1234, etc.
WordPress Updates
You can enable various levels of auto updates for WordPress by adding the following in your wp-config.php
file.
define('WP_AUTO_UPDATE_CORE', true);
- When set to
true
- Development, minor, and major updates are all enabled. - When set to
false
- Development, minor, and major updates are all disabled. - When set to
'minor'
- Minor updates are enabled, development, and major updates are disabled.
Backup Regularly
Follow these steps in the Azure App Service documentation for backing up your site with the Backup feature. https://docs.microsoft.com/en-us/azure/app-service/manage-backup
Web Server config
- Restrict/limit access to
wp-config.php
andwp-login.php
-
Nginx
location = /wp-config.php { deny all; } location = /wp-login.php { allow xxx.xxx.xxx.xxx; deny all; }
-
Apache
<Files wp-config.php> # Apache 2.2 Order Deny,Allow Deny from all # Apache 2.4+ Require all denied </Files> <Files wp-login.php> # Apache 2.2 Order Deny,Allow Deny from all Allow from xxx.xxx.xxx.xxx Allow from xxx.xxx.xxx.xxx # Apache 2.4+ Require all denied Require ip xxx.xxx.xxx.xxx Require ip xxx.xxx.xxx.xxx </Files>
-
IIS
<location path="wp-config.php"> <system.webServer> <security> <ipSecurity allowUnlisted="false" /> </security> </system.webServer> </location> <location path="wp-login.php"> <system.webServer> <security> <ipSecurity allowUnlisted="false"> <add ipAddress="xxx.xxx.xxx.xxx" allowed="true" /> </ipSecurity> </security> </system.webServer> </location>
-
- Prevent clickjacking by adding an addditional header:
X-FRAME-OPTIONS = SAMEORIGIN
- Apache
# Inside the apache2.conf or httpd.conf file Header always append X-Frame-Options SAMEORIGIN
- IIS
<system.webServer> <httpProtocol> <customHeaders> <add name="X-Frame-Options" value="SAMEORIGIN" /> </customHeaders> </httpProtocol> </system.webServer>
- Apache
Enable Static/Dynamic IP Restrictions
IP restrictions can be enabled in App Services by setting up access restrictions. More information on this can be found here: https://docs.microsoft.com/en-us/azure/app-service/app-service-ip-restrictions
- Dynamic IP Restrictions
- Apache
# Requires libapache2-modsecurity to be installed # ex. apt-get install libapache2-modsecurity SecRuleEngine On <LocationMatch "^/.*"> # initialise the state based on X-Forwarded-For ip address SecRule REQUEST_HEADERS:X-Forwarded-For "@unconditionalMatch" "phase:2,initcol:ip=%{MATCHED_VAR},pass,nolog,id:100" # if greater then burst_rate_limit then pause set RATELIMITED var and then return 509 SecRule IP:ACCESS_COUNT "@gt " "phase:2,deny,status:509,setenv:RATELIMITED,skip:1,nolog,id:102" # if above rule doesnt match increment the count SecAction "phase:2,setvar:IP.access_count=+1,pass,nolog,id:103" # set the base rate to one per second SecAction "phase:5,deprecatevar:IP.access_count=1/1,pass,nolog,id:104" # set a header when ratelimited Header always set Retry-After "10" env=RATELIMITED </LocationMatch> ErrorDocument 509 "Rate Limit Exceeded"
- IIS
<system.webServer> <security> <dynamicIpSecurity enableLoggingOnlyMode="true"> <denyByConcurrentRequests enabled="true" maxConcurrentRequests="10" /> <denyByRequestRate enabled="true" maxRequests="30" requestIntervalInMilliseconds="300" /> </dynamicIpSecurity> </security> </system.webServer>
- Apache
PHP Modifications
- Reduce Cross Site Scripting (XSS) attacks:
- Add
session.cookie_httponly = true
in thephp.ini
,.user.ini
, or custom.ini
file being loaded into PHP.
- Add
WordPress security plugin
There are many different WP Security plugins out there that you could use. Using any one of them could help provide better overall security for your WordPress site compared to not having one at all. A list of some well known plugins are below:
- Wordfence Security: https://wordpress.org/plugins/wordfence/
- All In One WP Security: https://wordpress.org/plugins/all-in-one-wp-security-and-firewall/
- Sucuri Security: https://wordpress.org/plugins/sucuri-scanner/
Update for new WordPress on Linux App Service Marketplace offering (2022)
More information regarding this offering can be found here: https://github.com/Azure/wordpress-linux-appservice
Updating Nginx headers
This will allow for updating many different headers for WordPress security. To do this, follow the steps below:
- Copy the required config file to the
/home
directory.cp /etc/nginx/conf.d/spec-settings.conf /home/custom-spec-settings.conf
- Edit
/home/custom-spec-settings.conf
using vi/vim editors to add custom settings.
NOTE: you can also upload a custom config file to /home
directory using file manager. Navigate to file manager through this URL: <Wordpress_App_Name>.scm.azurewebsites.net/newui/fileManager
. Upload the custom configuration file in /home
directory (ex: /home/custom-spec-settings.conf
)
-
Edit
/home/custom-spec-settings
and at the bottom of file you can add the headers for securityadd_header Content-Security-Policy "default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval';" always; add_header X-Xss-Protection "1; mode=block" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload'; add_header Referrer-Policy "strict-origin"; add_header Permissions-Policy "geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self)";
Remove phpinfo()
file
It is strongly recommended to remove any file that contains phpinfo()
. By doing so, this will ensure that the database credentials stored as environment variables are not exposed to the public.