pyx / sanic-wtf

Sanic meets WTForms

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

csrf failed when run with workers

ohahlev opened this issue · comments

I try to run guestbook; and it is working fine until I set workers=4, because my machine is a 4-core monster; and nightmare starts to come.

  1. steps to reproduce
  • git clone git@github.com:ohahlev/guestbook-sanic-wtf.git
  • python app.py
  • try to submit data again and again
  1. expected results
    form can be always submitted without error

  2. what really happens
    Sometimes form is submitted successfully, and sometimes not. I print out form.errors, and see that, the error is "csrf failed"

Hi @ohahlev in your implementation you are using a global variable for session (https://github.com/ohahlev/guestbook-sanic-wtf/blob/master/app.py#L16)

I presume in your actual app you have sessions stored elsewhere?

This global variable will not be shared amongst the different workers, so the csrf token will only be valid on a particular worker.

if it's not shared, what's the recommended solution to have the csrf value shared across workers?

if it's not shared, what's the recommended solution to have the csrf value shared across workers?

One way is to use a persistent storage such as a database. The global variable as storage in guestbook example is for self-contained demonstration purpose, you need something better in production.

I was chatting with the devs for Sanic (https://community.sanicframework.org/t/restructuring-create-server-to-leverage-workers/832/8?u=its-a-feature) and it appears that the value I set for the "WTF_CSRF_SECRET_KEY" is duplicated for each worker. So, if each worker gets that variable, why do we have the issue where only one worker can successfully handle the response?

I was chatting with the devs for Sanic (https://community.sanicframework.org/t/restructuring-create-server-to-leverage-workers/832/8?u=its-a-feature) and it appears that the value I set for the "WTF_CSRF_SECRET_KEY" is duplicated for each worker. So, if each worker gets that variable, why do we have the issue where only one worker can successfully handle the response?

I read the discussion you mentioned, looks like that's what you INTENDED. You want to share the secret key across workers.

If the code snippet "ahopkins" quoted there is what you are using, you are initializing your secret keys (notice I said keys, not a single key) per worker, I didn't follow the development of Sanic lately, but if workers are process based like you mentioned, that means your code:

mythic.config[
    "WTF_CSRF_SECRET_KEY"
] = str(uuid.uuid4()) + str(uuid.uuid4)

will be executed for as many times as the number of works (processes), and you are generating that many different secret keys (provided no collision here), in that case, the CSRF token validation should fail unless your POST request is handle by the VERY SAME worker that render your form request to begin with, that is, using same secret key both to render and to verify. It's by design, since we are assuming outside attackers don't know your secret key so that it's almost impossible for them to forged a token that can be validated.

Find some way to generate the secret key once and once only, then share it between your workers, ENV var suggested by "ahopkins" seems a good idea.

And something off-topic, initializing the secret key randomly in worker code has the side effect of no persistent CSRF token between service restarts, imagine, client C opened a new tab in browser with your form rendered with secret key S, while client C spent sometime to fill out the form, the service restarts, a new secret key S' was generated, the validation will fail should client C submit the form with now outdated CSRF token, this might or not might be what you want.

So, I mentioned in that thread (https://community.sanicframework.org/t/restructuring-create-server-to-leverage-workers/832/7?u=its-a-feature) that even when i set that value to something static, like "5" in that message i just linked, i still get the same effect. So, there's something else that's coming into play.

Yeah, by design for my application if the application restarts, I want all of the csrf and secret keys to invalidate.

So, I mentioned in that thread (https://community.sanicframework.org/t/restructuring-create-server-to-leverage-workers/832/7?u=its-a-feature) that even when i set that value to something static, like "5" in that message i just linked, i still get the same effect. So, there's something else that's coming into play.

Yeah, by design for my application if the application restarts, I want all of the csrf and secret keys to invalidate.

Could you show me a minimal app with the issue?