Spring MVC 4 AngularJS 1.3 HTTP POST 具有空 CSRF 令牌或标头

Posted

技术标签:

【中文标题】Spring MVC 4 AngularJS 1.3 HTTP POST 具有空 CSRF 令牌或标头【英文标题】:Spring MVC 4 AngularJS 1.3 HTTP POST has null CSRF token or header 【发布时间】:2014-10-24 21:33:58 【问题描述】:

当我禁用 CSRF 保护时,我接受 AngularJS 发送的所有 POST 请求,但是当它启用时,我收到以下错误:

错误:

HTTP 状态 403 - 在请求参数“_csrf”或标头“X-CSRF-TOKEN”上发现无效的 CSRF 令牌“null”。

据我了解,请求没有发送任何内容来匹配 _csrf 令牌,或者没有设置标头。

我的 html 标头代码中有这个:

<head>
  (...)
  <meta name="_csrf" content="$_csrf.token"/>
  <meta name="_csrf_header" content="$_csrf.headerName"/>
  (...)
</head>

我查看了此处发布的有关 CSRF 和 Spring 的问题,但不幸的是,尽管我尝试使用发布的各种代码示例作为解决方案,但我并没有设法解决我的问题。

我认为我应该以某种方式将 CRSF 数据与我的 POST 请求一起发送,但我不知道该怎么做。

我会很感激任何帮助:)

【问题讨论】:

【参考方案1】:

你看过关于 angularJS $http 和 XSRF-token 的文档吗(同样的东西):

https://docs.angularjs.org/api/ng/service/$http 向下滚动到Cross Site Request Forgery (XSRF) Protection

你可以配置 AngularJs 来自动处理它:

The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName properties of either $httpProvider.defaults at config-time, $http.defaults at run-time, or the per-request config object.

【讨论】:

我可以询问代码示例如何做到这一点吗? AngularJS 的在线文档对我来说有点难以理解。【参考方案2】:

我想知道为什么您想在编写为具有 javascript 前端的控制器中使用 CSRF 保护。 CSRF 的目标是避免另一个站点发送带有不需要数据的重定向后查询。如果您使用 AngularJs 来获取受 csrf 保护的内容,那么任何恶意网站都将能够向浏览器发送 javascript 代码以首先获取令牌,然后发布不需要的数据。恕我直言,您在使用 Ajax 时不应依赖 CSRF 保护。

【讨论】:

@eslaron 看来我应该在发帖前阅读一下同站点来源政策。除非浏览器出现严重问题,否则我描述的那种攻击是有希望被禁止的。将删除那个愚蠢的帖子... 所以最好让 CSRF 在 spring 和 angularjs 之间工作,但经过这么长时间我仍然无法让它工作。【参考方案3】:

您可以尝试将name="_csrf" 更改为name="csrf"。 Laravel 中似乎不允许使用下划线。如果谈论标题,就是这种情况。

例如:

$token = Request::header('_csrf'); // Not working

$token = Request::header('csrf'); // Working!

请注意,以上内容适用于 Laravel 4.2

【讨论】:

【参考方案4】:

快速而肮脏的解决方案:

JSP 页面

为简单起见,只需使用 jQuery 访问元标记中的标记并将它们放入 JavaScript 变量中(这可能会有所改进,只是还没有时间了解如何直接从 AngularJS 读取元标记值)。

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<head>
    <script src="<c:url value='/resources/js/jquery-2.1.4.min.js'/>" type="text/javascript"></script>
    <script src="<c:url value='/resources/js/angular/angular.min.js'/>" type="text/javascript"></script>
    <sec:csrfMetaTags />
    <c:if test="$!empty _csrf.token">
        <script type="text/javascript">
            var csrfParameter = $("meta[name='_csrf_parameter']").attr("content");
            var csrfHeader = $("meta[name='_csrf_header']").attr("content");
            var csrfToken = $("meta[name='_csrf']").attr("content");
        </script>
    </c:if>
</head>
确保页面中确实呈现了 CSRF 令牌(即该页面受 Spring CSRF 过滤器保护),即当您查看源代码时页面中包含类似以下内容(实际上是元标记将在一行中,它只是在尝试使用原始 HTML 时在 *** 预览中正确显示):
<meta name="_csrf_parameter" content="_csrf" />
<meta name="_csrf_header" content="X-CSRF-TOKEN" />
<meta name="_csrf" content="38452f36-d47b-4d49-b7ec-8b08cb8f9fa8" />
<script type="text/javascript">
    var csrfParameter = $("meta[name='_csrf_parameter']").attr("content");
    var csrfHeader = $("meta[name='_csrf_header']").attr("content");
    var csrfToken = $("meta[name='_csrf']").attr("content");
</script>

AngularJS 配置

将以下内容添加到您的应用(或模块)配置中。这里使用 AngularJS 的 $window 服务来访问上面隐式放入 window.csrfToken 等的 JavaScript 变量来配置 $http 服务:

app.run(['$http', '$window', '$document', function($http, $window) 
    $http.defaults.headers.post[$window.csrfHeader] = $window.csrfToken;
]);

您可能还想添加

    $http.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';

也作为默认标题。

【讨论】:

以上是关于Spring MVC 4 AngularJS 1.3 HTTP POST 具有空 CSRF 令牌或标头的主要内容,如果未能解决你的问题,请参考以下文章

使用AngularJS配置Spring MVC

Spring MVC 和 Angularjs

如何提高 Spring MVC - Hibernate - JSP - AngularJS v1.6 的性能? [关闭]

AngularJS 和 Spring MVC 安全性

Spring MVC + AngularJS + JWT 令牌过期 - HowTo

使用 Spring MVC 和 AngularJS 的方法 DELETE