1

Is there any plugin or relatively straightforward and accepted way to add a recaptcha to the login for the admin page?

My research so far has come up with nothing. I'm curious if others have looked into this with any result.

  • I would highly recommend not trying to do this. Your code could introduce other bugs into the system and allow an attacker to compromise it. If you're worried about bots brute forcing your install, for example, use the tools in Craft to rate limit them, change your CP login URL periodically, and consider implementing rate limiting on the server side as well (nginx has rate limiting built-in for example). – RitterKnight Oct 27 '17 at 15:23
  • Thanks @RitterKnight, I see now it is probably both unnecessary and not a great idea – bbeecher Nov 3 '17 at 16:27
2

We do this at Transform Studios at the DNS level by using cloudflare’s Web Application Firewall. You can basically add a rule which targets any url that matches the control panel login page and secure it with a captcha challenge before giving access to the page. I’ve found this is best to handle security before visitors even hit your site and more importantly prevents any core code base changes or creation of addons.

| improve this answer | |
1

As far as I know there is no "build in way" to achieve this. There is a way but it's really ugly and I would suggest you not to do what I write. Maybe someone can make it a little bit "cleaner" better or whatever but this code should actually not be used. It's only some kind of food for thought..

Ok so... you could inject a custom javascript code during the login process that adds a captcha to the login html...

public function init(){
    parent::init();
    if(craft()->request->url === "/admin/login"){
        // build your captcha, store the correct one in your session and build your html here
        craft()->templates->includeJs(
            // after document ready, append your html to the form
            // $("#login-form").append(yourHtml); or something like that
        );
    }
}

Like I said, it's a but ugly but I was not able to find a "clean way". The other workaround would be adding your code directly into the login.html but as soon as this file is updated you would have to include your html again (or you would have to prevent updates at all)

Then you can use this hook Link to check if the passed paramter matches yours. The following code is just an example. I didn't include any security checks. Don't use this as it is on your website.

craft()->on('userSession.onLogin', function(Event $event){
    $captcha = craft()->request->getPost('yourCaptchaParam');
    if($captcha !== craft()->httpSession->get('captcha')){
        $event->performAction = false;
    }
    return false;
});

Edit: ups sry - I saw too late you want to use the reCaptcha and not a captcha.. but the process would be the same

Edit2: This is the default craft login action. You can try to remove the default event handler from the button and attach your own in your init as well

submitLogin: function()
{
    var data = {
        loginName: this.$loginNameInput.val(),
        password: this.$passwordInput.val(),
        rememberMe: (this.$rememberMeCheckbox.prop('checked') ? 'y' : '')
    };

    Craft.postActionRequest('users/login', data, $.proxy(function(response, textStatus)
    {
        if (textStatus == 'success')
        {
            if (response.success)
            {
                window.location.href = Craft.getUrl(response.returnUrl);
            }
            else
            {
                //since you have no ganish, just change that to a jquery method
                Garnish.shake(this.$form);
                this.onSubmitResponse();

                // Add the error message
                if (!error)
                {
                     error = Craft.t('An unknown error occurred.');
                }

                this.$error = $('<p class="error" style="display:none">'+error+'</p>').insertAfter($('.buttons', this.$form));
                this.$error.velocity('fadeIn');
            }
        }
        else
        {
            this.$submitBtn.removeClass('active');
            this.$spinner.addClass('hidden');
            this.loading = false;
        }

    }, this));

    return false;
},
| improve this answer | |
  • Would I essentially be creating a simple Craft plugin that accomplishes these things? (Thanks for the detailed response!) – bbeecher Oct 23 '17 at 23:17
  • Yes. You only need one file and this site pluginfactory.io can create it for you. I made around 25 sites with craft in the last few years and not a single one had no custom plugin. That's how craft is supposed to work – Robin Schambach Oct 24 '17 at 4:34
  • Craft's login form actually submits via ajax craft/app/resources/js/compressed/login.js Adding Recaptcha to the admin login does not look possible without some extreme measures (modifying the login.js to include the g-recaptcha-response and only serving uncompressed js... alternatively creating a custom admin login) :( – bbeecher Oct 26 '17 at 22:39
  • or you could try to remove the default event handler from the button and just include a custom ajax function to it. I copied crafts function in my answer, its not too complicated to change it, since it's quite simple. And by the way: building a custom login is really easy too. I had to made that for one project too. You just need to copy paste many things – Robin Schambach Oct 27 '17 at 3:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.