how to test Recaptcha with jQuery Validate plugin

2019-01-09 11:17发布

问题:

I am using validate jquery plugin and recaptcha for a contact form and i woudld like to know how can i check if the code in the captcha is correct before the form get submitted if not send an error message because right now validate everything but i inserted a wrong code the form get submitted anyway. Here's my code ty in advance for anyhelp

<script type="text/javascript">
             var RecaptchaOptions = {
                lang : 'en',
                theme : 'custom',
                custom_theme_widget: 'recaptcha_widget'
             };
            </script>

            <form id="contact" method="post" action="#">

                <fieldset>
                    <label for="name_contact">NAME</label>
                    <input type="text" class="input-xlarge" id="name_contact" name="name_contact" value="" placeholder="" minlength="2">

                    <label for="email_contact">EMAIL</label>
                    <input type="email" class="input-xlarge" id="email_contact" name="email_contact" value="" placeholder="">

                    <label for="telephone">CONTACT NUMBER</label>
                    <input type="tel" class="input-xlarge" id="telephone" name="telephone" placeholder="" value="" >

                    <label for="message">MESSAGE</label>
                    <textarea id="message" class="input-xlarge" name="message" placeholder="" rows="5"></textarea>                  

                    <div id="recaptcha_widget" style="display:none">

                        <div id="recaptcha_image"></div>
                        <div class="recaptcha_only_if_incorrect_sol" style="color:red">Incorrect please try again</div>

                        <span class="recaptcha_only_if_image">Enter the words above:</span>
                        <span class="recaptcha_only_if_audio">Enter the numbers you hear:</span>

                        <input type="text" id="recaptcha_response_field" name="recaptcha_response_field" />

                        <div><a href="javascript:Recaptcha.reload()">Get another CAPTCHA</a></div>
                        <div class="recaptcha_only_if_image"><a href="javascript:Recaptcha.switch_type('audio')">Get an audio CAPTCHA</a></div>
                        <div class="recaptcha_only_if_audio"><a href="javascript:Recaptcha.switch_type('image')">Get an image CAPTCHA</a></div>

                        <div><a href="javascript:Recaptcha.showhelp()">Help</a></div>

                    </div>

                    <script type="text/javascript"
                        src="http://www.google.com/recaptcha/api/challenge?k=6Lf8RN4SAAAAAKnllVnDw23UpBIuAIdTRFgN1kmX">
                    </script>

                    <noscript>
                        <iframe src="http://www.google.com/recaptcha/api/noscript?k=6Lf8RN4SAAAAAKnllVnDw23UpBIuAIdTRFgN1kmX" height="300" width="500" frameborder="0"></iframe><br>
                        <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
                        <input type="hidden" name="recaptcha_response_field" value="manual_challenge">
                    </noscript>             

                    <button type="submit" value="" id="" name="send" class="pull-right lightblue btn-primary">SUBMIT</button>
                    </fieldset>
</form>


<script type="text/javascript">
    $(document).ready(function () {

        $("#contact").validate({
            rules: {
                "name_contact": {
                    required: true,
                    minlength: 3
                },
                "email_contact":{
                    required: true
                },
                "message":{
                    required:true
                },
                "recaptcha_response_field":{
                    required:true
                }

            },
            messages: {
                "name_contact": {
                    required: "Please, enter a name"
                },
                "email_contact":{
                    required: "Enter a valid email"
                },
                "message":{
                    required: "Please provide a comment"
                },
                "recaptcha_response_field":{
                    required: "Captcha is required"
                }
            },
            errorPlacement: function(error, element) {
                error.insertBefore(element);
            }
        });

    });
</script>

回答1:

There is no simple solution only using JavaScript or jQuery. Since you have to compare the Re-Captcha code using the API along with your private key, for proper security, you must do this process with some server-side code.

  1. User fills out form correctly except for Re-Captcha code.

  2. If Re-Captcha code is blank, normal required rule in jQuery Validate triggers a "missing Captcha" message. User can try again.

  3. A Re-Captcha code entered (correctly or incorrectly), form is submitted to your server-side code via jQuery ajax within the submitHandler callback function.

  4. Your server-side code, PHP, Perl, whatever, then uses your private API key to verify the entered Re-Captcha code against the Re-Captcha code expected by the API.

  5. If Re-Captcha code is correct, your server-side code continues as normal and returns a "success" text response to your jQuery ajax success callback function.

  6. If Re-Captcha code is incorrect, your server-side code will only return an "error" text response to your jQuery ajax success callback function, and the server-side code will do nothing else.

  7. Within your jQuery ajax success callback function, read the message text returned from the server-side code.

  8. If the returned message indicates a success, then your form was already submitted successfully and you can redirect, clear out the form, do an animation, print a message, do nothing, or whatever, etc.

  9. If the returned message indicates failure, generate a new Re-Captcha code via JavaScript, display an error message, "incorrect Captcha entered", and the user can simply try again.


This is how I did mine... you'll need to do something very much like the following.

Add a submitHandler to your .validate() options and use ajax to control the form submission. It's the only way you can interact with the Captcha and control form submission.

You'll also need to modify your server-side function to test whether the captcha passed or failed, do the appropriate function, and to return the proper ajax message, msg. Without knowing anything about your server-side code, it's impossible to say anything more specific.

(NOTE: any solution that is purely JavaScript/jQuery, without editing your server-side code, is not secure. Captcha can be easily bypassed and your private API key is exposed to the public.)

$(document).ready(function() {

    $("#contact").validate({
        // your other options and rules,
        submitHandler: function (form) {
            $.ajax({
                type: 'POST',
                data: $('form').serialize(),
                url: 'formMail.pl', // <-- whatever your server-side script, mine is a perl form mailer
                success: function (msg) {
                    if (msg.indexOf('captcha') != -1) {
                        Recaptcha.reload(); // reloads a new code
                        $('#recaptcha_response_field').before(msg); // error message
                    } else {
                        // anything else to do upon success, animations, etc.
                        // form was already submitted as per ajax
                    }
                }
            });
            return false; // blocks normal form submit
        }
    });

});

The following is only a PERL example of how I modified my server-side code which was a Form Mailer script. You'll have to adapt your server-side code in some similar fashion.

The subroutine check_captcha is called when the script first runs.

sub check_captcha {     
       my $ua = LWP::UserAgent->new();
       my $result=$ua->post(
           'http://www.google.com/recaptcha/api/verify',
           {
               privatekey => 'xxxxxxxxxxxxx',  # insert your private key here
               remoteip   => $ENV{'REMOTE_ADDR'},
               challenge  => $Form{'recaptcha_challenge_field'},
               response   => $Form{'recaptcha_response_field'}
           }
       );

       if ( $result->is_success && $result->content =~ /^true/) {
               return;  # OK - continue as normal with Form Mailer
       } else {
               # error, Form Mailer will not continue
               &error('captcha_failed'); # failed Captcha code, call error subroutine to print an error message (msg) containing the word "captcha"
       }
}

Remember that this server-side code must return a message that your jQuery picks up within your jQuery ajax success callback as msg above. In my example, if the message contains the word "captcha", that means the code was entered wrong and user must re-enter a new Captcha code.