【问题标题】:How to setup session and CSRF protection in Plug?如何在 Plug 中设置会话和 CSRF 保护?
【发布时间】:2018-06-02 04:45:40
【问题描述】:

我目前正在通过尝试制作一个小型 Plug 项目来学习 Elixir。除了会话和 CSRF 保护之外,大部分都很好。当我发出 GET 请求时,我在 Firefox 或 HTTPie 中看不到会话 cookie,当我发出 POST 请求时,我收到 500 错误(但记录器是静默的)。

这是我当前的路由器代码:

defmodule ElxSimpleApi.Web do
  require Logger

  use Plug.Router
  import Plug.Conn

  alias ElxSimpleApi.{Models, Repo}

  plug Plug.Logger, log: :debug
  plug Plug.Parsers, parsers: [:urlencoded, :json],
    pass: ["text/*", "application/json"],
    json_decoder: Poison

  plug :put_secret_key_base

  plug Plug.Session, store: :cookie,
    key: "_elx_simple_api_session",
    encryption_salt: "elxsimpleapienc",
    signing_salt: "elxsimpleapisign",
    log: :debug
  plug :fetch_session
  plug Plug.CSRFProtection


  plug :match
  plug :dispatch

  # A bunch of routes here, omitted for clarity

  match _ do
    send_resp(conn, 404, "oops")
  end

  defp fetch_person(:int, id), do: Models.Person |> Repo.get(id)
  defp fetch_person(:str, sid), do: fetch_person(:int, String.to_integer(sid))

  defp ecto_to_map(struct) do
    struct |> Map.from_struct |> Map.drop([:__meta__])
  end

  defp put_secret_key_base(conn, _) do
    put_in conn.secret_key_base, "d5b2hHZGsUfcYB8lImcxooaLfVBlB5bg/z9a99jjHuXTvt7yb5neykHrYEjuNFnD"
  end
end

请告诉我我做错了什么。谢谢!

更新:感谢@josé-valim 的建议,我现在知道 500 错误是由无效的 CSRF 令牌引起的。但是cookie仍然没有被设置。

【问题讨论】:

  • 尝试在use Plug.Router 之后添加use Plug.Debugger,看看添加调试器是否会为您提供正确的堆栈跟踪、日志记录和一切。

标签: session csrf session-management elixir


【解决方案1】:

显然,问题与this issue:有关。Plug.CSRFProtection 不会自动将 CSRF 令牌放入会话中,并且 Plug.Session 不会真正创建会话,直到放入某些东西。

我必须添加这个插件(就在plug Plug.CSRFProtection 之后):

defp put_csrf_token_in_session(conn, _) do
  Plug.CSRFProtection.get_csrf_token
  conn |> put_session("_csrf_token", Process.get(:plug_unmasked_csrf_token))
end

【讨论】:

  • 很高兴你知道了。如果有任何改进文档的地方,请发送 PR!
  • 说实话,我认为 Plug.CSRFProtection 本身在这方面可以改进。有时间我会尝试做 PR,虽然我对 Elixir 很陌生。
【解决方案2】:

如果你想获得 csrf_token 最好使用 Plug.CSRFProtection.get_csrf_token() 而不是直接点击Process.get

目前,如果启用 csrf_protection(protect_from_forgery),它将默认将令牌设置为会话字段 "_csrf_token"。可以配置字段名称。

如果您创建自己的会话存储 (@behaviour Plug.Session.Store) 并且希望 csrf_protection 工作,您需要自己在自定义会话存储中处理 "_csrf_token"

【讨论】:

    【解决方案3】:

    我还添加了一个像这样的插件

    defp put_csrf_token_in_session(conn, _) do
        conn
        |> Plug.Conn.put_req_header("x-csrf-token", Plug.CSRFProtection.get_csrf_token)
        |> put_session("_csrf_token", Process.get(:plug_unmasked_csrf_token))
      end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-10
      • 2011-04-02
      • 2014-01-23
      • 2013-08-07
      • 2014-01-25
      • 2014-05-21
      • 2019-02-03
      • 2019-11-29
      相关资源
      最近更新 更多