Spring Security CSRF 令牌不适用于 AJAX 调用和表单提交在同一个 JSP 中
Posted
技术标签:
【中文标题】Spring Security CSRF 令牌不适用于 AJAX 调用和表单提交在同一个 JSP 中【英文标题】:Spring Security CSRF Token not working with AJAX call & form submit in same JSP 【发布时间】:2015-01-26 17:23:41 【问题描述】:我正在尝试通过参考以下链接在我的项目中实现 spring security (ver 3.2.3) CSRF 令牌
http://docs.spring.io/autorepo/docs/spring-security/4.0.0.CI-SNAPSHOT/reference/htmlsingle/#csrf http://docs.spring.io/autorepo/docs/spring-security/4.0.0.CI-SNAPSHOT/reference/htmlsingle/#the-csrfmetatags-tag
我能够在没有 AJAX 调用的情况下成功地将 CSRF 令牌集成到 JSP 中。 但是当我尝试使用 AJAX 调用 JSP 时,得到“无效的 CSRF 令牌异常”。 经过分析,我发现 AJAX 调用和表单提交都使用相同的令牌,因此我得到“无效的 CSRF 令牌异常”。
请任何人帮助我解决这个问题。有没有办法生成两个令牌,即一个用于 AJAX 调用,一个用于表单提交
安全性.xml
<access-denied-handler ref="accessDenied" />
<intercept-url pattern="/**" access="ROLE_1" />
<form-login default-target-url='/loginUser.htm' always-use-default-target='true' authentication-failure-url='/forms/common/login.jsp?error=true' />
<logout logout-success-url="/forms/common/logout.jsp" invalidate-session="true" delete-cookies="JSESSIONID" />
<session-management invalid-session-url="/forms/common/sessionexpired.jsp" session-authentication-error-url="/forms/common/login.jsp?Error=alreadyLoggedin" >
<concurrency-control expired-url="/forms/common/sessionexpired.jsp" max-sessions="1" error-if-maximum-exceeded="true" />
</session-management>
<csrf request-matcher-ref="csrfSecurityRequestMatcher"/>
</http>
<beans:bean class="com.concerto.pg.login.security.CsrfSecurityRequestMatcher" id="csrfSecurityRequestMatcher"/>
JSP
<head>
<sec:csrfMetaTags />
<script type="text/javascript" charset="utf-8">
function changeList(id,option)
var csrfParameter = $("meta[name='_csrf_parameter']").attr("content");
var csrfToken = $("meta[name='_csrf']").attr("content");
var institution = document.getElementById("institutionId").value;
var data = ;
data[csrfParameter] = csrfToken;
data["institutionId"] = option;
if(id=="institutionId")
var result ='';
$.ajax(
type: "GET",
async: false,
url: './getMerchantByInstitution.htm',
data: data,//"institutionId=" + option,
dataType:'json',
success: function (res)
result = res;
var htmlVar = '';
for (var i=0; i<result.length; i++)
htmlVar += '<option
value="'+result[i]+'">'+result[i]+'</option>';
htmlVar += '<option value="ALL">ALL</option>';
$('#merchantId').html(htmlVar);
);
</script>
</head>
添加在 < input type="hidden" name="$_csrf.parameterName" value="$_csrf.token" /> 表单标签中的语句
感谢和问候, 湿婆
【问题讨论】:
【参考方案1】:这解决了我的问题:
<meta name="_csrf" th:content="$_csrf.token"/>
<meta name="_csrf_header" th:content="$_csrf.headerName"/>
使用 org.thymeleaf.extras:thymeleaf-extras-springsecurity4:3.0.2.RELEASE
【讨论】:
【参考方案2】:要在启用 CSRF 的情况下发出 AJAX/JSON 请求,您必须将 CSRF 令牌作为 HTTP 请求 Header 传递,而不是参数或其他数据。
在页面上,您的元标记应如下所示:
<meta name="_csrf" content="$_csrf.token"/>
<meta name="_csrf_header" content="$_csrf.headerName"/>
然后,在 JS 代码的某处准备值:
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
将 CSRF 令牌作为标头传递:
$.ajax(
type: "GET",
async: false,
url: './getMerchantByInstitution.htm',
data: "institutionId=" + option,
beforeSend: function(xhr)
// here it is
xhr.setRequestHeader(header, token);
,
success: function(obj)
// ....
,
....
虽然这完全取决于您,但我建议使用 JSON.stringify 之类的东西来传递 数据,但这当然取决于。
参考在这里:
http://docs.spring.io/spring-security/site/docs/3.2.0.CI-SNAPSHOT/reference/html/csrf.html#csrf-include-csrf-token-ajax
希望这会有所帮助。
【讨论】:
【参考方案3】:我希望下面的答案有所帮助。 进行这些更改
var csrfParameter = $("meta[name='_csrf_parameter']").attr("content");
var csrfToken = $("meta[name='_csrf']").attr("content");
var csrfHeader = $("meta[name='_csrf_header']").attr("content"); // THIS WAS ADDED
之后
data[csrfParameter] = csrfToken;
data["institutionId"] = option;
headers[csrfHeader] = csrfToken; // THIS WAS ADDED
终于改变了ajax调用:
url: './getMerchantByInstitution.htm',
headers: headers, // THIS WAS ADDED
data: data,//"institutionId=" + option,
dataType:'json',
让我知道这是否有效。
【讨论】:
如果我没记错的话,Spring 甚至不会检查 CSRF 标记的 GET 方法...? 这取决于你如何配置它,编码既是艺术也是科学以上是关于Spring Security CSRF 令牌不适用于 AJAX 调用和表单提交在同一个 JSP 中的主要内容,如果未能解决你的问题,请参考以下文章
使用 Spring Security 重命名 CSRF 令牌头名称
无法使用 Spring Security 创建 CSRF 令牌
Spring Security - CSRF - 如何重置 CSRF 令牌并记录潜在的 CSRF 攻击(OWASP 推荐)