Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSRF tokens not sessioned when using scope and memory_sessions #348

Open
keatonuw opened this issue Sep 26, 2024 · 1 comment
Open

CSRF tokens not sessioned when using scope and memory_sessions #348

keatonuw opened this issue Sep 26, 2024 · 1 comment
Labels

Comments

@keatonuw
Copy link

Hi!

I've encountered some strange behavior when using Dream.memory_sessions as middleware within a Dream.scope. Forms that contain injected CSRF tokens via Dream.csrf_tag do not seem to store these tokens in the sessions, per the logger:

dream.csrf  WARN REQ 2 CSRF token not for this session

Confusingly, all works as expected if the Dream.memory_sessions middleware is replaced with Dream.cookie_sessions.

I've created a modified version of d-form to reproduce the bug:

let show_form ?message request =
  <html>
  <body>

%   begin match message with
%   | None -> ()
%   | Some message ->
      <p>You entered: <b><%s message %>!</b></p>
%   end;

    <form method="POST" action="/">
      <%s! Dream.csrf_tag request %>
      <input name="message" autofocus>
    </form>

  </body>
  </html>

let () =
  Dream.run
  @@ Dream.logger
  @@ Dream.router [

        Dream.scope "/" [Dream.memory_sessions] [
            Dream.get  "/"
              (fun request ->
                Dream.html (show_form request));

            Dream.post "/"
              (fun request ->
                match%lwt Dream.form request with
                | `Ok ["message", message] ->
                  Dream.html (show_form ~message request)
                | _ ->
                  Dream.empty `Bad_Request);

        ];
  ]

I'm afraid I'm too new to the framework to tell whether this is a bug or mistake on my end. Hope this is enough info! Thanks!

@alxtuz
Copy link
Collaborator

alxtuz commented Oct 3, 2024

There is a bug at how Dream handles middlewares in a scope. It creates its own instance of middlewares for each route. In our case, each of the routes:

 Dream.get "/"
 Dream.post "/"

will have their own memory_sessions middleware with their own hash table as a back-end storage. Therefore, sessions created on GET requests will never be found in session storage of POST requests. As a result, tokens created on GET and sent back with POST will never match to tokens created in session storage on server, because corresponding session will not be found in POST’s session storage.
I'll prepare PR with fix soon.
For now, you can use middleware for the entire server:

  Dream.run
  @@ Dream.logger
  @@ Dream.memory_sessions
  @@ Dream.router [

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants