django-simple-captcha icon indicating copy to clipboard operation
django-simple-captcha copied to clipboard

BaseCaptchaTextInput should set autocomplete=off on the hashkey HiddenInput

Open eerotal opened this issue 4 years ago • 2 comments

In Firefox, if you fetch a new CAPTCHA via Ajax and change the image src and hashkey values with JavaScript, the new hashkey is remembered between page reloads. However, each time the page is reloaded, a new CAPTCHA image is provided. The result is that the CAPTCHA is impossible to solve since the image received from the server doesn't correspond to the hashkey in the DOM. The autofill happens because autocomplete="off" is not set on the hidden hashkey input. ~~The behavior of Firefox does seem quite odd since values written to the visible input box are not preserved. Only the value set with JavaScript is preserved between reloads.~~ (EDIT: Ah, autocomplete=off is set on the visible input field so of course that's not preserved.) I also tested with Chromium/Chrome but the issue doesn't manifest itself there.

Anyway, my workaround for now is to define a new widget class for the CaptchaField which sets autocomplete=off for all of the CAPTCHA fields:

class CustomCaptchaTextInput(CaptchaTextInput):
    def __init__(self, *args, **kwargs):
        if not "attrs" in kwargs:
            kwargs["attrs"] = {}

        kwargs["attrs"].update({"autocomplete": "off"})

        super().__init__(*args, **kwargs)

How to reproduce:

  1. Use the following Django source files

views.py

def test(request):
    ctx = { "form": TestForm() }
    return HttpResponse(render(request, 'test.html', ctx))

forms.py

class TestForm(forms.Form):
    captcha = CaptchaField()

test.html

<head>
    <script>
    document.addEventListener("DOMContentLoaded", () => {
        document.querySelector("#reset").addEventListener("click", async () => {
            document.querySelector("#id_captcha_0").value = "THIS IS AUTOFILLED"
        });
    });
    </script>
</head>

<body>
    <form action=".">
        {% csrf_token %}
        {{form.captcha}}
        <button id="reset" type="button">Reset</button>
    </button>
</body>
  1. Open the page with Firefox. I used version 78.10.0esr.
  2. Open the DOM inspector and confirm that the CAPTCHA image src and the hidden hashkey input value belong to the same CAPTCHA.
  3. Click the Reset button. The hashkey should change to "THIS IS AUTOFILLED".
  4. Reload the page eg. with F5.
  5. Confirm that the CAPTCHA image src has changed to a new image but the hidden hashkey input value is still "THIS IS AUTOFILLED". This would cause subsequent CAPTCHA validations to always fail.

eerotal avatar Jun 13 '21 17:06 eerotal

Good catch! Would you mind submitting a quick PR that fixes this? :pray:

mbi avatar Oct 05 '21 19:10 mbi

Sure! I'll look into the PR soon.

eerotal avatar Oct 05 '21 20:10 eerotal

Hey @eerotal I noticed you never ended up submitting a PR (I created one off of your branch). Do you think it's ready to be merged? Looks good me...

mbi avatar Aug 25 '22 09:08 mbi

Sorry, I have totally forgot this issue. I think I planned to improve the tests further, but I can have a look soon and confirm whether the changes are ready.

eerotal avatar Aug 26 '22 17:08 eerotal

PR merged, thank you!

mbi avatar Sep 11 '22 18:09 mbi