0
\$\begingroup\$

I am testing captcha setups with Fastapi. Currently, I am using an in-memory session (stored in a dictionary. Seems to not be a problem as there is no load balancing, etc...).

To fill out the contact form the frontend app makes a request to start a session (thus retrieving the captcha image and setting an opaque (really just a random UUID) session cookie (expiration. Of course, the id references the in-memory session that contains the captcha answer, which is checked at the time of submission. If the captcha answer doesn't match the session's captcha is cleared and a new captcha is set in the user's session.

My question is this enough to mitigate automation attacks (I know you can pay for services etc... to get around captcha but I am trying to see what loop holes lie in this code)?

Here is my code thus far:

from captcha.image import ImageCaptcha
from fastapi import FastAPI, Request, Response, HTTPException, status

def captcha_generator(size: int):
    return ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(size))


def generate_captcha():
    captcha: str = captcha_generator(5)
    image = ImageCaptcha()
    data = image.generate(captcha)
    data = base64.b64encode(data.getvalue())
    return {"data": data, "captcha": captcha}

@app.get('/')
def main(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

@app.get('/start-session')
def start_session(request: Request):
    captcha = generate_captcha()
    request.session["captcha"] = captcha['captcha']
    captcha_image = captcha["data"].decode("utf-8")
    return StreamingResponse(io.BytesIO(base64.b64decode(captcha_image)), media_type="image/png")

@app.post('/contact-submission')
def submission(
     request: Request
    ,response: Response
    ,data # This includes the captcha answer provided by user
):

   if request.session.get("captcha", uuid.uuid4()) == data.captcha:
       return status.HTTP_200_OK
   else:
      request.session["captcha"] = str(uuid.uuid4())
      raise HTTPException(status.HTTP_403_FORBIDDEN, detail="Captcha Does not Match")

Here is what the cookie looks like:

Session Cookie

\$\endgroup\$

0

Your Answer

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

Browse other questions tagged or ask your own question.