Java CSRF:为每个请求生成令牌

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16322067/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 06:17:57  来源:igfitidea点击:

CSRF: Generate token for every request

javajspspring-securitycsrf

提问by

Right now, we have csrf token per session. And adding this token jsp's using hidden field. following snippet gives only one per session:

现在,我们每个会话都有 csrf 令牌。并使用隐藏字段添加此令牌jsp。以下代码段每个会话仅提供一个:

token = (String) session.getAttribute(CSRF_TOKEN_FOR_SESSION_NAME);
    if (null==token) {
        token = UUID.randomUUID().toString();
        session.setAttribute(CSRF_TOKEN_FOR_SESSION_NAME, token);
    }

and for every request,

对于每个请求,

//calls the above snippet and this time token will not be null 
String st = CSRFTokenManager.getTokenForSession(request.getSession());
String rt = CSRFTokenManager.getTokenFromRequest(request);

here, usings equals to compare the strings and returning either true or false.

在这里,使用等于比较字符串并返回 true 或 false。

my question is, what happens if I try to generate the token for every request without getting the token from session. And while comparing, I will get from the session and request. is this good idea or missing something?

我的问题是,如果我尝试为每个请求生成令牌而不从会话中获取令牌会发生什么。在比较时,我将从会话和请求中获取。这是个好主意还是遗漏了什么?

Instead of using the above snippets, I will go with following

我将不使用上述代码段,而是使用以下内容

    //for every request generate a new and set in session
    token = UUID.randomUUID().toString();
    session.setAttribute(CSRF_TOKEN_FOR_SESSION_NAME, token);

    //get the token from session and request and compare
    String st = (String) request.getSession().getAttribute("CSRF_TOKEN_FOR_SESSION_NAME");
    String rt = CSRFTokenManager.getTokenFromRequest(request);

采纳答案by Jay Lindquist

You'll want to flip around the flow that you stated above. After every compare you should create a new token.

你会想要翻转你上面提到的流程。每次比较后,您应该创建一个新令牌。

One large drawback to token-per-request is if the user hits the back button in their browser:

token-per-request 的一大缺点是如果用户点击浏览器中的后退按钮:

  • User visits Page1 and stores TokenAin session.
  • User clicks a link to Page2, submitting TokenA. The app verifies TokenAin session and gives the user TokenB.
  • User hits the back button to go back to Page1, session information is not updated.
  • Page1 still only has information for TokenA, user clicks a link or submits a form to Page3 submitting TokenA, but the session only knows about TokenB
  • App considers this a CSRF attack
  • 用户访问 Page1 并TokenA在会话中存储。
  • 用户单击指向 Page2 的链接,提交TokenA. 该应用程序TokenA在会话中进行验证并为用户提供TokenB.
  • 用户点击后退按钮返回第 1 页,会话信息未更新。
  • Page1仍然只有TokenA用户点击链接或向Page3提交表单的信息TokenA,但会话只知道TokenB
  • 应用认为这是 CSRF 攻击

Because of this, you need to take great care of how and when the tokens are updated.

因此,您需要非常注意令牌的更新方式和时间。

回答by Mangu Singh Rajpurohit

Apart from the solution suggested by Jay, I will suggest you to avoid caching of your web-pages by setting various cache-control headers in the response to client.

除了 Jay 建议的解决方案之外,我还建议您通过在对客户端的响应中设置各种缓存控制标头来避免缓存您的网页。