如何在Plug中设置会话和CSRF保护?

时间:2017-12-19 17:24:38

标签: session elixir csrf session-management elixir-framework

我正在尝试制作一个小型插件项目,目前正在学习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仍未设置。

3 个答案:

答案 0 :(得分:2)

显然,问题与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

答案 1 :(得分:1)

如果要获取csrf_token,最好使用 Plug.CSRFProtection.get_csrf_token() 而不是直接点击Process.get

当前,如果启用了csrf_protection(protect_from_forgery),则默认情况下会将令牌设置为会话字段"_csrf_token"。可以配置字段名称。

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

答案 2 :(得分:0)

我还添加了一个插头

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