预防
Java 不提供针对 CSRF 攻击的内置保护;开发人员必须通过手动强制执行反 CSRF 令牌或使用许多经过良好测试的可用库之一来实现它。
小服务程序 API
当使用标准的 Servlet API 时,双重提交 cookie 技术可以如下实现。要生成用作标记的随机字符串,可以使用SecureRandom该类,例如:
public class CSRF {
public static String getToken() throws NoSuchAlgorithmException{
// generate random data
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
byte[] data = new byte[16];
secureRandom.nextBytes(data);
// convert to Base64 string
return Base64.getEncoder().encodeToString(data);
}
}
假设使用 JSP 页面呈现 HTML 页面,可以使用以下代码段将 CSRF 令牌添加到表单和响应 cookie:
<%
// generate a random CSRF token
String csrfToken = CSRF.getToken();
// place the CSRF token in a cookie
javax.servlet.http.Cookie cookie = new javax.servlet.http.Cookie("csrfToken", csrfToken);
response.addCookie(cookie);
%>
<form action="/action" method="POST">
<input type="hidden" name="csrfToken" value="<%= csrfToken %>"/>
</form>
最后,对于每个操作,通过检查 cookie 中的 CSRF 令牌是否与表单中的值匹配来确保请求是合法的:
public void doAction(HttpServletRequest request, HttpServletResponse response) {
// get the CSRF cookie
String csrfCookie = null;
for (Cookie cookie : request.getCookies()) {
if (cookie.getName().equals("csrf")) {
csrfCookie = cookie.getValue();
}
}
// get the CSRF form field
String csrfField = request.getParameter("csrf");
// validate CSRF
if (csrfCookie == null || csrfField == null || !csrfCookie.equals(csrfField)) {
try {
response.sendError(401);
} catch (IOException e) {
// ...
}
return;
}
// ...
}
参考
OWASP -跨站点请求伪造备忘单MITRE - CWE 352