【问题标题】:Phoenix - invald CSRF on AJAX postPhoenix - AJAX 帖子上的 CSRF 无效
【发布时间】:2019-02-12 22:01:22
【问题描述】:

我正在学习使用 Phoenix 框架,并且正在尝试向控制器操作执行 AJAX 发布 - 但是,我遇到了 CSRF 保护问题。

对于初学者,我没有使用表单 - 只是想将文本从输入传递到控制器:

<input type="text" id="raw-input" />
<button id="send-button">Send it!</button>

<script>
$("#send-button").click(function(){
    var input = $("#raw-input").val();

    $.ajax({
        url: "/test/process",
        type: "POST",
        dataType: "json",
        beforeSend: function(xhr) {xhr.setRequestHeader("X-CSRF-Token", $("meta[name='csrf-token']").attr("content"))},
        data: {"input" : input},
        success: function(response){
            console.log(response);
        }
    });
});
</script>

控制器(还不担心做任何事情input...只是想验证一个成功的帖子!):

def process(conn, %{"input" => input}) do
    IO.puts "got it!"
end

还有路由器:

post "/test/process", TestController, :process

我几乎从一个运行良好的 Rails 应用程序中解除了 $.ajax 调用,但它在这里没有起到作用 - 运行它会返回 403 错误并记录 (Plug.CSRFProtection.InvalidCSRFTokenError) invalid CSRF (Cross Site Request Forgery) token, make sure all requests include a valid '_csrf_token' param or 'x-csrf-token' header

任何人都可以提供任何指导吗?谢谢!

【问题讨论】:

  • 你的 html 中有 CSRF 元标记吗?
  • 感谢@Gazler - 我还可以通过按照您的建议添加元标记来解决此问题。我之前测试时遗漏的事情是 Phoenix 期望参数为 _csrf_token,您甚至可以在我上面的问题中看到。只是错过了那个小细节......好吧,生活和学习!

标签: ajax phoenix-framework elixir


【解决方案1】:

这是因为 Phoenix 默认不使用 CSRF 令牌创建元标记。它们只包含在由 Phoenix 的辅助函数生成的表单中,并且它们位于隐藏的输入中。

要在 Phoenix 中以编程方式获取 CSRF 令牌,您可以致电 Plug.CSRFProtection.get_csrf_token/0。有很多方法可以将它传递给你的 JS。您可以在布局中添加元标记以将其包含在每个页面中,但这可能效率不高,因为它将为所有页面生成。您也可以将其存储在需要它们的视图中的 JS 变量中:

<input type="text" id="raw-input" />
<button id="send-button">Send it!</button>

<script>
$("#send-button").click(function(){
    var CSRF_TOKEN = <%= raw Poison.encode!(Plug.CSRFProtection.get_csrf_token()) %>;
    var input = $("#raw-input").val();

    $.ajax({
        url: "/test/process",
        type: "POST",
        dataType: "json",
        beforeSend: function(xhr) {
            xhr.setRequestHeader("X-CSRF-Token", CSRF_TOKEN);
        },
        data: {"input" : input},
        success: function(response){
            console.log(response);
        }
    });
});
</script>

【讨论】:

  • 谢谢你,这太棒了——仅供参考,当我使用你的代码时,我收到了错误Uncaught SyntaxError: Unexpected token &amp; 指的是var CSRF_TOKEN = &amp;quot;NXQ8YzQGLS0KPgskMTAXAAQeHVgaJgAAB8XZngDckuEVdiF2VPV1sw==&amp;quot;;。回想我的 Rails 体验,我记得你可以使用 raw 来解决这个问题 - 所以最终的工作版本是 var CSRF_TOKEN = &lt;%=raw Poison.encode!(Plug.CSRFProtection.get_csrf_token()) %&gt;;
  • 如果只在需要它的页面中包含元标记,如下面的答案中所做的那样,它不会为所有页面生成。
【解决方案2】:

Phoenix 已经有了助手csrf_meta_tag。像这样将它包含在布局中:

<html lang="en">
  <head>
     <%= csrf_meta_tag %>
     ...

然后像这样在你的 js 中使用它:$("meta[name='csrf-token']").attr("content")

【讨论】:

  • 你说得对,这是一个很好的解决方案——不过我应该提到我没有使用模板,所以我不适用于我的特殊情况。
【解决方案3】:

如果您想跳过 CSRF 令牌检查(如果您只开发 API),那么您可以在下面的行中注释掉 -

插件:protect_from_forgery

在您各自的 _web/router.ex 中

【讨论】:

  • 这是一个糟糕的答案,因为它没有提到禁用 CSRF 保护的危险。
猜你喜欢
  • 2016-02-05
  • 1970-01-01
  • 2014-09-03
  • 2018-02-22
  • 2017-07-06
  • 2015-04-20
  • 2018-08-02
  • 2013-12-19
  • 2014-08-29
相关资源
最近更新 更多