Block Passwords Found in Known Data Breaches
Checks new passwords against the Have I Been Pwned database of breached passwords when users change or reset them, and asks for a different one if it appears there.
Opens WPIDE on
Code
$wpide_breach_count = function ( $password ) {
$hash = strtoupper( sha1( (string) $password ) );
$prefix = substr( $hash, 0, 5 );
$cache = 'wpide_hibp_' . $prefix;
$body = get_transient( $cache );
if ( false === $body ) {
$response = wp_remote_get( 'https://api.pwnedpasswords.com/range/' . $prefix, array(
'timeout' => 4,
'headers' => array( 'Add-Padding' => 'true', 'User-Agent' => 'WordPress password check' ),
) );
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
return 0;
}
$body = wp_remote_retrieve_body( $response );
set_transient( $cache, $body, 12 * HOUR_IN_SECONDS );
}
if ( preg_match( '/^' . substr( $hash, 5 ) . ':(\d+)/m', $body, $m ) ) {
return (int) $m[1];
}
return 0;
};
$wpide_breach_message = 'This password has appeared in a data breach and is unsafe. Please choose a different one.';
add_action( 'user_profile_update_errors', function ( $errors, $update, $user ) use ( $wpide_breach_count, $wpide_breach_message ) {
if ( ! empty( $user->user_pass ) && $wpide_breach_count( $user->user_pass ) > 0 ) {
$errors->add( 'wpide_pwned', '<strong>Error:</strong> ' . $wpide_breach_message );
}
}, 10, 3 );
add_action( 'validate_password_reset', function ( $errors ) use ( $wpide_breach_count, $wpide_breach_message ) {
$pass = isset( $_POST['pass1'] ) ? (string) wp_unslash( $_POST['pass1'] ) : '';
if ( $pass && $wpide_breach_count( $pass ) > 0 ) {
$errors->add( 'wpide_pwned', $wpide_breach_message );
}
} );
Notes
Only the first 5 characters of the password's SHA-1 hash are sent (k-anonymity), never the password; if the service cannot be reached, the password is allowed.
How to add this snippet
- Install WPIDE on your WordPress site (it is free) and open Code Snippets.
- Use snippet above adds it from the library in one click. Or copy the code into a new snippet with the same code type.
- It is added inactive: review the code and settings, then switch it on.