Table of Contents
- Introduction
- About Fortress
- Default Settings and Workflow
- Secure Two Factor Authentication – TOTP
- Password Security
– Secure password hashing
– Password policy
– Disabling password resets for privileged users
– Disable application passwords
– Decrease password reset link duration
– Destroy all user sessions on password change - Rate Limiting
– Login throttling
– Password reset throttling - Secure Session Management
– Custom user session storage
– Session management and security
– Fortress Sudo mode
Introduction
Snicco, the team behind the Fortress Security plugin, are an enterprise WordPress development team and independent security research firm.
Through their research and guidance they have helped 24 of the most well-known security plugins patch vulnerabilities in their code – many extremely serious that could have led to a full site takeover. Their security research found DOS vulnerabilities, a complete lack/misunderstanding of encryption, and unjustifiable security shortcuts. Many plugins even copied code from others verbatim, introducing inherent security issues into their codebase, and every plugin evaluated had at least 1 vulnerability, with most having 3 or more.
Based on their research and the serious issues present in other solutions, they have created Fortress, a plugin that focuses on keeping WordPress locked down by significantly upgrading WordPresses own security practices, adding secure 2FA, rate limiting, more secure sessions, and forcing strong passwords with best available cryptography.
About Fortress
No Security Compromises
The core idea behind hosting partnerships is only to include what can be done effectively at the plugin level and nothing more. You get EVERYTHING that can be hardened effectively in PHP and NONE of the things that are useless at best and resource hogs at worst.
Unlike other security plugins, Fortress is NOT built for the lowest common denominator, which means there are no security compromises by:
- Purposefully NOT supporting prehistoric PHP versions and instead only supporting 7.4+|8+|8.1+
- Partnering directly with hosting companies so that most of the ambiguity of the unknown runtime is prevented. (The reason every other plugin stores encryption keys in the database is because it’s the only thing they can rely on being available).
Fortress Modules
Fortress consists of four modules that you can use independently of each other:
- Authentication
- Password Security
- Rate limiting
- Session Management
All four modules are activated by default, and together they harden your security at every step of your website’s authentication lifecycle.
Quality Assurance
Fortress undergoes rigorous quality assurance testing to ensure every code base change works. This includes 1200 automated tests before every single release across all combinations of supported WordPress and PHP versions.
WP-CLI Configuration
Fortress is built with a CLI-first approach and has full feature parity between the Web UI and the WP-CLI.
To improve the developer experience and reliability of the default WP-CLI, Snicco have created their own open-source BetterWPCLI library, and this is used everywhere in Fortress.
Customization
All of the modules in Fortress are highly customizable and can be configured per user role. Even the most complex scenarios can be accommodated.
Default Settings and Workflow
Everything in Fortress is configurable, so if there’s a default setting that you wish to change (or make recommendations about to your clients) it’s all flexible. That all said, these are the 3 things that may change the workflow of your clients and/or team members with the default settings:
- 2FA is required for administrators and editors, it is not optional.
- Password resets are disabled by default for administrators and editors, so out of the box, this needs to be done via WP-CLI.
- For anyone working inside the website for extended periods, the sudo timeout is 10 mins by default. This means you can still navigate around the UI, but to say install/delete a plugin or start editing a post, they will be required to authenticate.
Secure Two-Factor Authentication
One of the biggest problems with many security plugins (both now and in the past) is that their two-factor authentication is not only NOT secure, but its activation may also have led to your website being hacked in certain circumstances. Snicco provided numerous plugin vendors with the code needed to fix such issues.
In Fortress, two-factor authentication employs the most up-to-date, best security practices, can be enforced at a granular level, and has its own WP-CLI.
2FA Rate Limiting
Fortress is the ONLY security plugin that rate-limits failed 2FA attempts. Without implementing rate-limiting, 2FA can be brute forced, simple as that.
By default, Fortress allows five failed 2FA attempts (configurable). The failed attempts counter is reset after a successful 2FA login.
If the rate-limiting threshold is exceeded, Fortress will “lock” the user account, which means:
- Destroying all sessions (including the current one) for the associated user.
- Resetting the password of the user to a completely random one.
- Sending the user an email about the incident.
Compatibility
- The Fortress TOTP implementation conforms with the RFC 6238 spec and works with all common authenticator apps like 1Password, Google Authenticator, etc.
- Fortress 2FA is compatible with “most” custom WordPress login forms out of the box, including WooCommerce.
Password Security
The Fortress password security features are broken down as follows:
- Main Features:
- Secure password hashing
- Password policy
- Disabling password resets for privileged users
- Tweaks:
- Disable application passwords
- Decrease password reset link duration
- Destroy all user sessions on password change
We’ll look at each of these below.
Secure Password Hashing
WordPress uses an outdated md5-based hashing scheme for password security that is no longer considered secure. Fortress solves for this.
- Fortress replaces the password-hashing functions with its own implementation based on the libsodium core PHP extension, which is the best cryptography implementation in PHP.
- Fortress encrypts the password hash with the ID of the corresponding user as additional data and stores the ciphertext in the database, making it essentially impossible for attackers to crack unless the filesystem is compromised.
- Encryption keys are stored securely on the server, not the database. Fortress prevents one big attack vector on WordPress sites, where an attacker with database access / or SQL injection changes the password for an existing user or swaps the password hashes with a password known to them.
- Other security plugins only opportunistically rehash passwords, which means that only the passwords of users who have logged in recently can be updated. Fortress can proactively update password hashes in the background (via WP-CLI) without requiring users to change their passwords AND can disallow legacy hashes after upgrading.
- Fortress can detect legacy password hashes from various sources and upgrade them to a more secure hash using encryption with argon2 algorithm.
- Fortress can automatically upgrade legacy password hashes in batches without disrupting regular site operations using its password upgrade-legacy-hashes command.
Password Policy
Fortress enforces a NO-BS password policy for all user accounts, which means:
- Passwords can be between 12 and 4096 characters, with no character restrictions and full Unicode support*. For example:
🧐🧐漢字👀docker-horse-chair
is a perfectly valid password. - Password strength must score at least a 3 out of 4 according to the zxcvbn password entropy estimator.
- The policy is enforced when a user edits their profile on the /wp-admin/profile.php page or creates a new user on the /wp-admin/user-new.php page.
- The policy is evaluated when users reset their password on the wp-login.php page.
- Users can be excluded from the password policy based on their roles or dynamically using the CheckingPasswordPolicy event.
- Fortress never allows weak passwords server-side, even if the “Confirm use of weak password” checkbox is clicked.
*The disable emoji GridPane additional security hardening measure does not interfere with password setting.
Additional Note
The zxcvbn estimator is a password strength estimator created by Dropbox inspired by password crackers that weighs 30k common passwords, common names, and surnames according to US census data, popular English words from Wikipedia and US television and movies, and other common patterns like dates, repeats, sequences, keyboard patterns, and l33t/1337 speak.
Disabling password resets for privileged users
Recovering a forgotten password is a balance between security and convenience. Fortress uses an opt-in approach for password resets to enhance security.
A user with any of the roles defined in the password_policy_excluded_roles
option will not be able to:
- request a password reset link.
- reset passwords on the profile page.
By default, this applies to users of the roles:
administrator
editor
Passwords can always be reset using WP-CLI.
- For these defined roles, Fortress intercepts the allow_password_reset hook, which WordPress uses to send a password recovery email to the user’s email, and lets the user know that they cannot reset their password.
- You have the ability to add additional user roles (e.g., for WooCommerce sites, you may wish to add the
shop_manager
role).
Edge Cases
some plugins like WooCommerce and LMS have their own mechanisms to reset passwords without using the allow_password_reset
hook. In such cases, Fortress cannot prevent password resets, and you may need to contact the plugin vendor to add the hook or inspect the code and fire it yourself at the appropriate time. More info on this can be found in part 2 of this series.
Disable application passwords
The problem: WordPress application passwords are vulnerable to social engineering attacks, where an attacker can trick an unsuspected site admin into adding a new application password by clicking on a link.
- As most sites don’t require them, Fortress completely disables WordPress application passwords by default.
- You can re-enable application passwords on the websites that require them.
WooCommerce + Zapier are a common combination that require this functionality, so on these sites it will need to turned back on.
Decrease password reset link duration
By default, WordPress password reset links are valid for 24 hours. Fortress decreases this duration to 30 minutes.
This can be adjusted if 30 minutes is too strict for your use case but is plenty of time for most websites.
Destroy all user sessions on password change
The Problem: WordPress invalidates a user’s sessions after a password change by coincidence because a user’s password hash happens to be part of his authentication cookie. To be precise, the 8th – 12th characters of the password hash are part of a user’s auth cookie. However, the difference between the 8th – 12th hash characters is not guaranteed, making this unreliable.
For this reason, Fortress explicitly destroys a user’s sessions after he changes his password.
Rate Limiting
Rate limiting is a technique used to control the rate at which requests are made to a system or service to prevent overload and to protect against malicious attacks, such as brute-force attacks, that attempt to flood a system with too many requests.
When the rate limit is reached, further requests are blocked until a later time. It is commonly used in web applications to prevent denial-of-service attacks and to limit the impact of automated bots.
Rate limiting is an important technique used to maintain the stability and security of your website by controlling the rate of requests that it receives. However, most WordPress security plugins can only protect against attacks from a single IP because they still operate with the 2000s mindset of “one attacker = one IP.” This could not be further from the truth in 2023.
Fortress includes two rate-limiting features: Password reset throttling and Login throttling and has implemented a novel (in WordPress) rate-limiting algorithm (Token Bucket) that, instead of storing all failed attempts, only needs to store a counter per IP/username/etc. This results in far less storage and uses the WP Object Cache directly instead of the database.
Password Reset Throttling
- Fortress limits password resets to once every 15 minutes per IP address.
- The purpose of password reset throttling is to prevent attackers from flooding a user’s email inbox with password reset requests.
- Password reset throttling also prevents attackers from tricking the SMTP service into sending multiple password reset emails.
Login Throttling
Login throttling is a rate-limiting mechanism that restricts the number of login attempts from various dimensions to protect against different attack vectors.
- Device ID throttling: After an honest user logs in, Fortress assigns a cryptographically secure device ID to the user’s browser that an attacker can not fake or compromise. Honest users will then only be rate-limited pretty loosely. This is a highly effective method of ensuring that honest users are not affected during a brute force attack without reverting to a UX-killing solution like Captchas.
- Username throttling: Fortress limits login attempts for a specific username.
IP throttling: Fortress throttles login attempts from specific IP addresses and allows for bursts with a refill period to prevent false positives. - Global throttling: Fortress considers all failed login attempts irrespective of the target username and remote IP.
Secure Sessions
Before diving into each of the features below, it’s important to understand what a session is and how it relates to your website’s security. Here’s a quick breakdown:
- A session in WordPress refers to the period of time when a user is logged in to the website. When a user logs in, WordPress creates a session for that user, and as long as the session is active, the user can access protected pages and perform actions that require authentication.
- The session is maintained by using a session cookie, which is a small file stored on the user’s browser. This cookie contains a unique identifier that allows WordPress to associate the user’s browser with their session.
- When the user logs out or the session expires (due to inactivity or a configured timeout), the session is destroyed, and the user is logged out of the website.
- Sessions are an essential part of WordPress security as they help ensure that only authorized users can access sensitive pages and features of the website.
Fortress makes WordPress sessions far more secure.
Custom user session storage
WordPress uses a custom session implementation that stores arbitrary data (the session) in the wp_usermeta
table. This has some disadvantages:
- The
wp_usermeta
table will get bloated if many users log in frequently. - All user sessions are stored bundled together instead of separately, keyed by their token. If your users use several devices, all session data for all sessions has to be retrieved for every authenticated request.
- Expired sessions can only be garbage collected once the user logs in on a different device.
- To update one session, all sessions have to be fetched first.
- (Theoretically) subject to time-based-side-channel attacks, though this will require a very skilled and highly motivated attacker.
Fortress solves for all of these issues with its own custom user sessions.
- Fortress offloads the storage of sessions to a custom table, where each session represents one row, with the session token being the primary key. This is both more efficient and is a crucial pre-requisite that makes all the other features of the session module possible.
- Fortress replaces the default session storage in WordPress with a custom table, making all of its session-related features possible.
- Fortress comes with a WP-CLI command to remove expired sessions from the database, which you can schedule as per your preference.
- The plugin also provides an option to destroy all sessions on your site, a more efficient and safer way to log out all users instead of rotating your site’s salts, which may not be compatible with all plugins.
Session management and security
The Problem
- WordPress uses cookies for authenticating users, and these cookies contain a session token linking to an actual WordPress session.
- An attacker can steal already valid cookies either via network communication or via malware on a user’s infected computer.
- Stolen cookies are sold to hackers in huge batches on the dark web, and WordPress sites are wide open to these attacks. Neither Core nor third-party security plugins have a solution.
At the time of writing, the Linus Tech Tips YouTube channel had just suffered a similar attack – detailed video here.
Important
Many many viruses are built for the sole purpose of cookie harvesting. This is a huge security problem, and no one in the WordPress security world even tries to protect against this.
The Solution
Fortress uses four dimensions (timeouts) to harden WordPress session security. Each of these is explained below. Configuration options are available to overwrite default values.
1. The Absolute Timeout
- Fortress will expire a session regardless of user activity after the absolute timeout has passed.
- This timeout roughly corresponds to what WordPress Core does by default.
2. The Rotation Timeout
- This security feature is used to protect user sessions from being exploited if their session token is stolen.
- After a certain period of time (default is 20 minutes), the current user session is copied to a new session token, and the old token is invalidated.
This means that if an attacker or a virus on the local machine steals a token, they have a limited amount of time (the rotation timeout period) to use it before it becomes invalid. If a user continues to use the site after the token has been stolen, they will receive a new token, and the old one will become invalid.
However, if an attacker immediately starts exploiting the stolen token, there is a race condition between them and the legitimate user. Once the rotation timeout is exceeded, the contents of the current user session are copied to a newly generated session token (auth-cookie). The first incoming client request with a valid auth cookie will receive the new auth cookie.
This means that either the legitimate user or the attacker could win and the other party will be locked out after the new auth cookie. This is a serious problem, and so shorter the window, the more secure your session is.
3. The Idle Timeout
- This timeout logs you out of your account if you haven’t been active on a website for a certain amount of time. This helps protect your account from unauthorized access if you’ve left your computer unattended or used a public computer OR if a machine is shared between multiple people using the site with different accounts.
- Fortress has a default idle timeout of 30 minutes, but you can configure it to be shorter or longer.
- The timeout is reset whenever you make an HTTP request to the website, except for when using WP-Cron or the Heartbeat API in the WordPress admin area.
4. The Sudo Mode Timeout
- This timeout requires users to re-enter their password to perform sensitive actions after logging in. This is a feature that companies like Amazon use to let you remain logged in and add items to your basket, but also make you re-authenticate when doing anything billing related.
- Once they enter the password, they can perform sensitive actions for a certain period without re-authenticating.
- Fortress has a default sudo timeout of 10 minutes, and this timeout can be changed for individual users using the sudo_timeout option.
This complements the absolute timeout and idle timeout to provide better security.
Fortress Sudo Mode
- Fortress has a feature called sudo mode that gives a user elevated privileges for a certain period after they log in. This is similar to the Linux sudo command. After the time is up, the user’s privileges go back to normal.
- During sudo mode, the user can use the website normally. If they are not in sudo mode and try to access a protected page, Fortress will ask them to confirm their password.
- If they provide the correct password, the sudo timeout is reset, and they can access the page.
Up Next: Part 2 Quick Start Configuration Guide
This is part 1 of a 2 part series of documentation. Click below to begin learning how to configure Fortress: