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 令牌或标头的主要内容,如果未能解决你的问题,请参考以下文章
如何提高 Spring MVC - Hibernate - JSP - AngularJS v1.6 的性能? [关闭]