Preventing Bot Attacks on WordPress using No Captcha reCaptcha
There are many different solutions to prevent bots from submitting web forms; one of the most popular solutions is reCaptcha. reCaptcha actually displays an image with some text in it and user has to enter the text to submit the form successfully. It was difficult for bots to read the text on the image, but as bots algorithms become more advanced, they started breaking this security. It was no more safe. This old method is pretty bad in terms of user friendliness. Then Google created a new reCaptcha called No Captcha reCaptcha.
In this tutorial we will look at what exactly No Captcha reCaptcha is and how to create a plugin which integrates reCaptcha in WordPress Login, Registration and Comment forms to prevent various types of attacks.
A Look at No Captcha reCaptcha
No Captcha reCaptcha just displays a checkbox asking the user to check it if he/she is not a bot. It might look very hackable but internally Google uses advanced algorithms and methods to find if the user is a bot or not. This new model is more user friendly and secure than the old one.
How Does it Work?
It may seem like a simple checkbox but it's not a checkbox at all. Its a graphics that behaves like a checkbox. Most bots don't run JavaScript so they cannot emulate it. But for the bots which can emulate, this is tracked down by mouse movement and Google's Adsense fraud click detection algorithms.
Registerating a No Captcha reCaptcha App
Users who install this plugin need to register their website to retrieve a site key and secret key.
You need to create a settings page for the plugin which allows the WordPress administrator to install the site key and secret key they retrieved from reCaptcha admin panel.
function no_captcha_recaptcha_menu() { add_menu_page( "reCapatcha Options", "reCaptcha Options", "manage_options", "recaptcha-options", "recaptcha_options_page", "", 100 ); } function recaptcha_options_page() { ?> <div class="wrap"> <h1>reCaptcha Options</h1> <form method="post" action="options.php"> <?php settings_fields( "header_section" ); do_settings_sections( "recaptcha-options" ); submit_button(); ?> </form> </div> <?php } add_action( "admin_menu", "no_captcha_recaptcha_menu" ); function display_recaptcha_options() { add_settings_section( "header_section", "Keys", "display_recaptcha_content", "recaptcha-options" ); add_settings_field( "captcha_site_key", __("Site Key"), "display_captcha_site_key_element", "recaptcha-options", "header_section" ); add_settings_field( "captcha_secret_key", __("Secret Key"), "display_captcha_secret_key_element", "recaptcha-options", "header_section" ); register_setting( "header_section", "captcha_site_key" ); register_setting( "header_section", "captcha_secret_key" ); } function display_recaptcha_content() { echo __( '<p>You need to <a href="https://www.google.com/recaptcha/admin" rel="external">register you domain</a> and get keys to make this plugin work.</p>' ); echo __( "Enter the key details below" ); } function display_captcha_site_key_element() { ?> <input type="text" name="captcha_site_key" id="captcha_site_key" value="<?php echo get_option('captcha_site_key'); ?>" /> <?php } function display_captcha_secret_key_element() { ?> <input type="text" name="captcha_secret_key" id="captcha_secret_key" value="<?php echo get_option('captcha_secret_key'); ?>" /> <?php } add_action( "admin_init", "display_recaptcha_options" );
Let's see how the above code works:
- We created a settings page on the WordPress admin dashboard.
- This settings page displays two input text fields for site key and secret key.
- These keys are stored as WordPress options. We name the options as
site_key
andsecret_key
Preventing Comment Spams
You need to integrate reCaptcha in front end comments forms to prevent bots from putting spam comments.
Create a style.css file in your plugin directory and place this code
#submit { display: none; }
The above code hides the submit button in the WordPress comment form so that we can place the reCaptcha box above the submit button by inserting both submit button and reCaptcha box manually.
Here is the code to integrate reCaptcha on comment forms
add_action( "wp_enqueue_scripts", "frontend_recaptcha_script" ); function frontend_recaptcha_script() { if( get_option( 'captcha_site_key' ) && get_option( 'captcha_secret_key' ) ) { wp_register_script( "recaptcha", "https://www.google.com/recaptcha/api.js" ); wp_enqueue_script( "recaptcha" ); $plugin_url = plugin_dir_url( __FILE__ ); wp_enqueue_style( "no-captcha-recaptcha", $plugin_url . "style.css" ); } } add_action( "comment_form", "display_comment_recaptcha" ); function display_comment_recaptcha() { if( get_option( 'captcha_site_key' ) && get_option( 'captcha_secret_key' ) ) { ?> <div class="g-recaptcha" data-sitekey="<?php echo get_option( 'captcha_site_key' ); ?>"></div> <input name="submit" type="submit" value="Submit Comment"> <?php } } add_filter( "preprocess_comment", "verify_comment_captcha" ); function verify_comment_captcha( $commentdata ) { if( isset( $_POST['g-recaptcha-response'] ) ) { $recaptcha_secret = get_option( 'captcha_secret_key' ); $response = file_get_contents( "https://www.google.com/recaptcha/api/siteverify?secret=" . $recaptcha_secret . "&response=" .$_POST['g-recaptcha-response'] ); $response = json_decode( $response, true ); if( true == $response["success"] ) { return $commentdata; } else { echo __( "Bots are not allowed to submit comments." ); return null; } } else { if( get_option( 'captcha_site_key' ) && get_option( 'captcha_secret_key' ) ) { echo __( "Bots are not allowed to submit comments. If you are not a bot then please enable JavaScript in browser." ); return null; } else { return $commentdata; } } }
Let's see how the above code works:
- We en-queued Google's reCaptcha JavaScript file to WordPress frontend by using
wp_enqueue_scripts
action. - We also en-queued the style.css file using
wp_enqueue
_style - Inside the comment form we display the checkbox using
comment_form
action. - When the comment is submitted and before inserting it to the database, WordPress calls the
preprocess_comment
filter. Inside the filter we check if the user is human or bot. If human then we return the comment to be inserted otherwise we return null to prevent the comment from being added to database.
Preventing Brute Force Login Attacks
We need to integrate reCaptcha in the admin login form to prevent bots from running a brute force attack to crack passwords. Here is the code to integrate it on admin login form
add_action( "login_enqueue_scripts", "login_recaptcha_script" ); function login_recaptcha_script() { if( get_option( 'captcha_site_key' ) && get_option( 'captcha_secret_key' ) ) { wp_register_script( "recaptcha_login", "https://www.google.com/recaptcha/api.js" ); wp_enqueue_script( "recaptcha_login" ); } } add_action( "login_form", "display_login_captcha" ); function display_login_captcha() { if( get_option( 'captcha_site_key' ) && get_option( 'captcha_secret_key' ) ) { ?> <div class="g-recaptcha" data-sitekey="<?php echo get_option('captcha_site_key' ); ?>"></div> <?php } } add_filter( "wp_authenticate_user", "verify_login_captcha", 10, 2 ); function verify_login_captcha( $user, $password ) { if( isset( $_POST['g-recaptcha-response'] ) ) { $recaptcha_secret = get_option( 'captcha_secret_key' ); $response = file_get_contents( "https://www.google.com/recaptcha/api/siteverify?secret=" . $recaptcha_secret . "&response=" . $_POST['g-recaptcha-response'] ); $response = json_decode( $response, true ); if( true == $response["success"] ) { return $user; } else { return new WP_Error( "Captcha Invalid", __( "<strong>ERROR</strong>: You are a bot" ) ); } } else { if( get_option( 'captcha_site_key' ) && get_option( 'captcha_secret_key' ) ) { return new WP_Error( "Captcha Invalid", __( "<strong>ERROR</strong>: You are a bot. If not then enable JavaScript" ) ); } else { return $user; } } }
Let's see how the above code works:
- We en-queued Google's reCaptcha JavaScript file to WordPress admin login, registration and lost password pages by using the
login_enqueue_scripts
action. - We displayed the checkbox using the
login_form
action. - Before producing the final authentication result, WordPress runs the
wp_authenticate_user
filter to let us add a extra validation step. We check if the user is bot or human inside this filter. If its human we return the user object else we return and WordPress error object.
Preventing Creation of Fake Accounts
We need to integrate reCaptcha in the admin registration form to prevent bots from creating fake accounts. Here is the code to integrate it on admin registration form
add_action( "register_form", "display_register_captcha" ); function display_register_captcha() { if( get_option( 'captcha_site_key' ) && get_option( 'captcha_secret_key' ) ) { ?> <div class="g-recaptcha" data-sitekey="<?php echo get_option( 'captcha_site_key' ); ?>"></div> <?php } } add_filter( "registration_errors", "verify_registration_captcha", 10, 3 ); function verify_registration_captcha( $errors, $sanitized_user_login, $user_email ) { if( isset( $_POST['g-recaptcha-response'] ) ) { $recaptcha_secret = get_option( 'captcha_secret_key' ); $response = file_get_contents( "https://www.google.com/recaptcha/api/siteverify?secret=" . $recaptcha_secret . "&response=" . $_POST['g-recaptcha-response'] ); $response = json_decode( $response, true ); if( true == $response["success"] ) { return $errors; } else { $errors->add( "Captcha Invalid", __( "<strong>ERROR</strong>: You are a bot" ) ); } } else { if( get_option( 'captcha_site_key' ) && get_option( 'captcha_secret_key' ) ) { $errors->add( "Captcha Invalid", __( "<strong>ERROR</strong>: You are a bot. If not then enable JavaScript" ) ); } else { return $errors; } } return $errors; }
Let's see how the above code works:
- We displayed the checkbox using
register_form
action. - Before producing the final authentication result WordPress runs the
registration_errors
filter to let us add a extra validation step. We check if the user is bot or human inside this filter. If its human we return empty error object else we add a add to the error object and return it.
Preventing Bots Submitting Lost Password Form
We need to integrate reCaptcha in the admin lost password form to prevent bots from submitting this form. Here is the code to integrate it on admin lost password form
add_action( "lostpassword_form", "display_login_captcha" ); add_action( "lostpassword_post", "verify_lostpassword_captcha" ); function verify_lostpassword_captcha() { if( isset( $_POST['g-recaptcha-response'] ) ) { $recaptcha_secret = get_option( 'captcha_secret_key' ); $response = file_get_contents( "https://www.google.com/recaptcha/api/siteverify?secret=" . $recaptcha_secret . "&response=" . $_POST['g-recaptcha-response'] ); $response = json_decode( $response, true ); if( true == $response["success"] ) { return; } else { wp_die( __( "<strong>ERROR</strong>: You are a bot" ) ); } } else { if( get_option( 'captcha_site_key' ) && get_option( 'captcha_secret_key' ) ) { wp_die( __( "<strong>ERROR</strong>: You are a bot. If not then enable JavaScript" ) ); } else { return; } } return $errors; }
Let's see how the above code works:
- We displayed the checkbox using
lostpassword_form
action. - Before producing the final password reset link WordPress runs the
lostpassword_post
action to let us add a extra validation step. We check if the user is bot or human inside this filter. If its human we return nothing else we kill the script with an error message.
Final Thoughts
Its a new way to protect your website forms from bots and increase user friendliness. You can also learn how Google detects bot or human internally using this new type of captcha. Once you have integrated this plugin in your WordPress site write your experiences below.
About Narayan Prusty
Narayan is a web astronaut. He is the Founder of QScutter. He loves to share ideas. When not coding he enjoys playing football. You will often find him at QNimate, his personal blog.
Thanks for explanation. I will use this for my site.
Great article.
Is there any way to make this captcha responsive?
http://www.w3sanju.in/google-recaptcha-javascript-validation/