凤凰无效CSRF

时间:2018-12-29 17:01:34

标签: elixir phoenix-framework

我正在尝试上传本地文件,但是当我执行POST请求时,出现invalid CSRF (Cross Site Request Forgery) token, make sure all requests include a valid '_csrf_token' param or 'x-csrf-token' header错误

我已经尝试调用此函数

def csrf_token(conn) do
    Plug.Conn.get_session(conn, :csrf_token)
end

我的.html.eex:

<form action="/accounts/new/csv-validator" method="post" 
enctype="multipart/form-data">
    <input type="hidden" name="_csrf_token" value="<%= @get_csrf_token() %>">
    <input class="form-control input-bordered" id="user_photo" name="user[photo]" type="file">
</form>

预期结果:成功使用有效的csrf令牌进行POST

凤凰版本:v1.3.4

2 个答案:

答案 0 :(得分:0)

在Phoenix --add-modules中是一个宏,即它是宏函数的名称:

  

@实际上是一个将@key转换为Map.get(assigns,:key)的宏。

     

https://hexdocs.pm/phoenix/templates.html

我实际上认为该报价有误,应显示为:

  

@实际上是一个将@key转换为Keyword.get(assigns,   :key)。

@来自这里:

assigns

https://hexdocs.pm/phoenix/Phoenix.Controller.html#render/3

结果,如果您这样调用render:

render(conn, template, assigns)

然后在render(conn, "page.html", message: "hello", answer: "yello") |_______________________________| ^ | assigns (a keyword list) 模板中,如果您编写page.html,则Phoenix将用@message替换它,其结果为Keyword.get(assigns, :message)

那应该表明在模板中写"hello"是胡说八道。相反,您需要做的是这样的:

@get_csrf_token()

然后,您可以在模板中编写def your_action(conn, _params) do render(conn, "page.html", csrf: csrf_token(conn) ) end 来插入令牌。

答案 1 :(得分:0)

我发现@7stud 很有教育意义并且很有帮助,但我没有给这个堆栈留下明确的解决方案;所以我想我会试一试。

使用 Phoenix 渲染 EEx 模板时,有很多选项。在这个问题中,@Leka 似乎没有使用 Phoenix.HTML,但我会将它与其他选项一起列出。

没有 Phoenix.HTML:

<form method="post" action"...">
  <input type="hidden" name="_csrf_token" value="<%= Plug.CSRFProtection.get_csrf_token() %>">
  ...
</form>

Phoenix 的版本做了同样的事情:

<form method="post" action"...">
  <input type="hidden" name="_csrf_token" value="<%= Phoenix.Controller.get_csrf_token() %>">
  ...
</form>

使用 Phoenix.HTML,各种形式的 form_for 在 POST 时会自动执行此操作(这是默认操作):

<%= form_for @conn, "..." %>
  ...
</form>

我无法从问题中 100% 判断出来,但看起来 @Leka 可能正在定义自定义 CSRF 函数。如果是这样,只要在相应的 Phoenix 视图文件中定义了该函数,就可以使用“@”宏从模板中调用该函数。

除非需要超出 Plug 提供的自定义代码,否则这种方法是不必要的。与@7stud 在渲染中使用assigns 参数的方法相同。再次,不要不尊重@7stud 的回答;这可能是对他们对@Leka 试图做的事情的解释的直接回应。