Wordpress
XML RPC Disable
XML-RPC is a WordPress feature that enables the transfer of data between WordPress and other systems. It has now been largely replaced by REST API but is still included in installations for backwards compatibility.
If it is enabled on WordPress, an attacker can perform brute force, pingback (SSRF) attacks, etc.
- For Apache
XML-RPC can be disabled by adding/(creating a .htaccess file) with below lines in .htaccess file on WordPress’s root directory.
<Files xmlrpc.php>
order deny,allow
deny from all
</Files>
- If you want to use this feature, you can allow an IP.
<Files xmlrpc.php>
order deny,allow
deny from all
allow from 192.168.1.101
</Files>
- For Nginx
XML-RPC can be disabled by adding below lines in nginx.config.
location ~* ^/xmlrpc.php$ {
return 403;
}
With the use of the plugin, XMP RCP can be disabled. There is a plugin to disable XML RPC.
References
https://www.wpbeginner.com/plugins/how-to-disable-xml-rpc-in-wordpress/
https://kinsta.com/blog/xmlrpc-php/
https://blogvault.net/wordpress-disable-xmlrpc/
https://www.malcare.com/blog/wordpress-disable-xmlrpc/
User Enumeration Via JSON File
WordPress includes a REST API that can be used to list the information about the registered users on a WordPress installation. The REST API exposed user data for all users who had authored a post of a public post type. WordPress 4.7.1 limits this to only post types which have specified that they should be shown within the REST API.
There are some plugins to stop this attack.
References
https://www.jinsonvarghese.com/prevent-wordpress-username-enumeration/
User Enumeration Via author Parameter
If permalinks are enabled, in many WordPress installations it is possible to enumerate all the WordPress usernames iterating through the author archives. Whenever a post is published, the username or alias is shown as the author. For example, the URL http://wordpress_site.com/?author=1 will show all the posts from user id 1. Attackers can abuse this functionality to figure out which usernames are available on the site.
- This can be prevented by adding a few lines in .htaccess file.
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_URI} ^/$
RewriteCond %{QUERY_STRING} ^/?author=([0-9]*)
RewriteRule ^(.*)$ http://yoursite.com/? [L,R=301]
</IfModule>
References
https://www.acunetix.com/vulnerabilities/web/wordpress-username-enumeration/
Brute Force Attack at Login Page.
To prevent brute force attack at the login page, you will need to add the following configuration in apache, IIS and Nginx config files.
- For Apache
This attack can be prevented by adding below lines in .htaccess file.
ErrorDocument 401 default
- For IIS
This attack can be prevented by adding below lines in web.config file.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
</system.webServer>
<!-- Existing Configuration Excluded -->
<location path="wp-login.php" overrideMode="Allow">
<system.webServer>
<security>
<authentication>
<anonymousAuthentication enabled="false" />
<windowsAuthentication enabled="true" />
</authentication>
</security>
</system.webServer>
</location>
</configuration>
- For Nginx
This attack can be prevented by adding below lines in nginx.config file.
error_page 401 http://yourwordpress.com/wp-admin/wp-login.php
Limit Access to wp-login.php by IP
If you want to log in to the admin area of the WordPress then you can white list your IP to log in to the WordPress application.
- For Apache
Add the following lines in .htaccess file.
# Block access to wp-login.php.
<Files wp-login.php>
order deny,allow
allow from 203.0.113.15
deny from all
</Files>
If you want to add more than one IP address, you can add the following lines in .htaccess file:
# Block access to wp-login.php.
<Files wp-login.php>
Require ip 203.0.113.15 203.0.113.16 203.0.113.17
# or for the entire network:
# Require ip 203.0.113.0/255.255.255.0
</Files>
- For IIS
Add the following lines in the web.config file.
<location path="wp-admin">
<system.webServer>
<security>
<ipSecurity allowUnlisted="false"> <!-- this rule denies all IP addresses, except the ones mentioned below -->
<!-- 203.0.113.x is a special test range for IP addresses -->
<!-- replace them with your own -->
<add ipAddress="203.0.113.15" allowed="true" />
<add ipAddress="203.0.113.16" allowed="true" />
</ipSecurity>
</security>
</system.webServer>
</location>
- For Nginx
Add the following lines for one and more than one IP in nginx.config file.
error_page 403 http://example.com/forbidden.html;
location /wp-login.php {
allow 203.0.113.15
# or for the entire network:
# allow 203.0.113.0/24;
deny all;
}
Plugins to Prevent Brute Force Attack.
Following plugins can help to prevent brute force attack.
- Limit Login Attempts Reloaded
- SiteGuard WP Plugin
- Brute Force Login Protection
- WordPress Login & Security, Anti Hacker Plugin
- Loginizer
- Change wp-admin login
References
https://wordpress.org/support/article/brute-force-attacks/
https://wordpress.org/plugins/tags/brute-force/
https://wordpress.org/plugins/search/admin+rename/
Injection Attacks
SQL Injection (SQLi)
All data in SQL queries must be SQL-escaped before the SQL query is executed to prevent SQL injection attacks. WordPress provides helper classes to assist with escaping SQL queries $wpdb.
Selecting Data
The escaped SQL query ($sql in this example) can then be used with one of the methods:
- $wpdb->get_row($sql)
- $wpdb->get_var($sql)
- $wpdb->get_results($sql)
- $wpdb->get_col($sql)
- $wpdb->query($sql)
Inserting and Updating Data
- $wpdb->update($sql)
- $wpdb->insert($sql)
Like Statements
- $wpdb->prepare($sql)
Cross-Site Scripting (XSS)
Escaping is the process of securing output by stripping out unwanted data, like malformed HTML or script tags, preventing this data from being seen as code.
Escaping helps secure your data before rendering it for the end-user and prevents XSS (Cross-site scripting) attacks.
WordPress has a few helper functions you can use for most common scenarios.
esc_html() – Use this function anytime an HTML element encloses a section of data being displayed.
<?php echo esc_html( $title ); ?>
esc_url() – Use this function on all URLs, including those in the src and href attributes of an HTML element.
<img src="<?php echo esc_url( $great_user_picture_url ); ?>" />
esc_js() – Use this function for inline Javascript.
<a href="#" onclick="<?php echo esc_js( $custom_js ); ?>">Click me</a>
esc_attr() – Use this function on everything else that’s printed into an HTML element’s attribute.
<ul class="<?php echo esc_attr( $stored_class ); ?>"> </ul>
esc_textarea() – encodes text for use inside a textarea element.
<textarea><?php echo esc_textarea( $text ); ?></textarea>
Escaping with Localization Rather than using echo to output data, it’s common to use the WordPress localization functions, such as _e() or __().
These functions simply wrap a localization function inside an escaping function:
esc_html_e( 'Hello World', 'text_domain' );
// same as
echo esc_html( __( 'Hello World', 'text_domain' ) );
These helper functions combine localization and escaping:
- esc_html__()
- esc_html_e()
- esc_html_x()
- esc_attr__()
- esc_attr_e()
- esc_attr_x()
Note: Whenever you’re outputting data make sure to properly escape it.
References
https://developer.wordpress.org/themes/theme-security/data-sanitization-escaping/
https://developer.wordpress.org/themes/theme-security/data-validation/
Note
- If other vulnerabilities occur in Themes and Plugins, you can follow our PHP Recommendation to prevent those vulnerabilities since WordPress is built on PHP.