Keeping your WordPress site secure should always be at the top of your priority list. While WordPress itself is relatively secure, it’s the additional steps you take as a developer that ensure your site isn’t vulnerable to some of the most common attacks. The following tips address security vulnerabilities and bad practices, helping you protect your site and users from harm.
(I’ve gathered these trusty code snippets from some of my older blog posts. Some might be a bit old, but they might still come in handy.)
1. Prevent Users from Sharing Login Credentials
It’s one thing to share a Netflix password, but when users start sharing credentials on your WordPress site, it becomes a security issue. You want to ensure that each account is only used by one person at a time to prevent account sharing, data leaks, or worse. This snippet limits users to a single active login session at a time. If someone logs in while another session is active, the previous one is terminated. This stops users from sharing their login credentials with others.
function matt_watson_login_one_instance() {
global $sessions;
$sessions = WP_Session_Ttokens::get_instance( get_current_user_id() );
$sessions->destroy_others( wp_get_session_token() );
}
add_action('setup_theme', 'matt_watson_login_one_instance', 0);
2. Prevent Clickjacking in WordPress
Clickjacking is a malicious technique where attackers trick users into clicking something different from what they think they’re clicking. Attackers often use iframes to load your site invisibly on their own malicious website. By adding the X-FRAME-OPTIONS
header to your site, you can instruct the browser not to display your content within an iframe, thereby protecting your site from clickjacking attempts.
function matt_watson_prevent_clickjacking() {
header( 'X-FRAME-OPTIONS: SAMEORIGIN' );
}
add_action( 'send_headers', 'matt_watson_prevent_clickjacking', 10 );
3. Stop WordPress from Loading in a Frame (Older Browsers Too!)
While the X-FRAME-OPTIONS
header works well for most modern browsers, older versions of browsers (such as Internet Explorer 8 and earlier) don’t support it. To protect users who may still be using older browsers, this JavaScript fallback ensures that your site can’t be loaded in a frame on those browsers either. It continuously checks if the site is loaded in a frame and, if it is, wipes out the content.
try { top.document.domain } catch (e) {
var f = function() {
document.body.innerHTML = '';
};
setInterval( f, 1 );
if ( document.body ) {
document.body.onload = f;
}
}
4. Enforce Version Control in WordPress
WordPress allows users to edit theme files and install plugins directly from the dashboard. While this might seem convenient, it’s not ideal from a security standpoint, especially in environments where multiple users have access to the admin area. By disabling file editing and plugin installations via the WordPress dashboard, you can ensure that all changes go through your version-controlled workflow, avoiding surprise edits and potential vulnerabilities.
define( 'DISALLOW_FILE_EDIT', true );
define( 'DISALLOW_FILE_MODS', true );
5. Limit Login Attempts to Prevent Brute Force Attacks
Brute force attacks happen when malicious users or bots repeatedly try to guess login credentials. To mitigate this, you can limit the number of login attempts a user can make before they are temporarily locked out. In this snippet, after three failed login attempts, the user is locked out for a defined period, reducing the likelihood of a brute force attack succeeding.
function matt_watson_limit_login_attempts() {
$lockout_duration = 1800; // Lockout duration in seconds (30 minutes)
$data = get_transient( 'mattwatson_attempted_login' ) ?: [ 'tried' => 0 ];
$data['tried']++;
if ( $data['tried'] >= 3 ) {
// Logic for handling lockout after 3 failed attempts
// Example: temporarily block user login for the duration
}
set_transient( 'mattwatson_attempted_login', $data, $lockout_duration );
}
add_action( 'wp_login_failed', 'matt_watson_limit_login_attempts' );
6. Prevent XSS by Escaping Values in Your WordPress Templates
Cross-site scripting (XSS) is one of the most common vulnerabilities on the web. It occurs when an attacker injects malicious code into your site, often via user inputs that are displayed without proper sanitation. By using WordPress functions like esc_attr()
and esc_html()
when displaying user-generated content, you can prevent XSS attacks. These functions escape any special characters that could be interpreted as code, ensuring that only safe data is output.
Here’s how you should sanitize user input in your WordPress templates:
<input type="text" value="<?php echo esc_attr( $my_value ); ?>">
These six tips provide a solid foundation for securing your WordPress site. From preventing account sharing and brute force attacks to mitigating XSS vulnerabilities, these strategies will help ensure that your WordPress site remains safe from common threats.