新窗口提交表单时CSRF令牌验证失败问题求助
问题
以下是我编写的代码:
<body> <form:form id="gotoPopupPreview" name="gotoPopupPreview" method="post" action=""> <input type="hidden" name="isPreview" value="Y"> <input type="hidden" name="nttId" value="${searchVO.nttId}"> <!--...(skip)--> </form:form> <script> function openPreview(url, target, otherData){ var f = $("#gotoPopupPreview"); f.attr('action', url); f.attr('target', target); //...(skip) window.open('', target); f.submit(); } $("#submitBtn").click(function(){ var otherData = 'blahblah'; openPreview("http://www.test.or.kr/", 'test', otherData); }); </script> </body>
执行后服务器返回错误:
AccessDeniedException : org.springframework.security.web.csrf.MissingCsrfTokenException: Could not verify the provided CSRF token because your session was not found.
result :::: {"result" : "fail", "message" : "Could not verify the provided CSRF token because your session was not found."}
我确认JSP form标签库已自动添加CSRF令牌,页面源码也能看到该字段,但仍出现异常。请问是否是新窗口提交导致的问题?这种情况下该如何正确传递CSRF令牌?
解答
问题确实出在提前打开新窗口的操作上:
- 先执行
window.open('', target)创建空白窗口时,这个新窗口会生成一个全新的会话(或未关联原页面的会话)。 - 随后提交原页面表单时,表单携带的CSRF令牌属于原页面的会话,服务器在新窗口的会话中找不到对应的令牌记录,因此抛出异常。
解决方案
最简洁有效的修复方式是移除提前打开窗口的代码,直接提交表单:
function openPreview(url, target, otherData){ var f = $("#gotoPopupPreview"); f.attr('action', url); f.attr('target', target); // 去掉window.open('', target);这一行 f.submit(); }
浏览器会在表单提交时自动创建指定target的新窗口,此时新窗口的会话会和表单提交的请求自动关联,CSRF令牌验证就能正常通过。
额外注意事项
- 确保目标URL和当前页面处于同域:跨域场景下Spring Security的CSRF机制本身不生效,若需跨域提交要改用其他方案。
- 确认
form:form生成的CSRF字段正确:默认情况下Spring Security会生成名为_csrf的隐藏域,你可以在页面源码中检查是否存在类似<input type="hidden" name="_csrf" value="xxx">的字段。
内容的提问来源于stack exchange,提问作者sinichee
相关产品推荐
相关产品推荐

