【发布时间】:2021-11-27 02:29:56
【问题描述】:
我已要求实施 CSRF 以防止对 java 服务器应用程序的攻击。它是一个提供大量 Web REST API 服务的应用程序。 我查看了许多指南并在堆栈上搜索了here,但仍有一些顾虑。 我知道不需要 GET 请求。
所以,如果我错了,请纠正我。
- 浏览器首次发送请求以获取会话的 CSRF 令牌,大约 30 分钟
- 然后浏览器将此令牌放入脚本并发送到后端。
这是我的过滤器。
public class ValidateCSRFToken implements Filter {
private static final Logger LOGGER = LoggerFactory.getLogger(ValidateCSRFToken.class);
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
// Spring put the CSRF token in session attribute "_csrf"
CsrfToken csrfToken = (CsrfToken) httpServletRequest.getAttribute("_csrf");
// Send the cookie only if the token has changed
String actualToken = httpServletRequest.getHeader("X-CSRF-TOKEN");
if (!StringUtils.isEmpty(csrfToken)) {
LOGGER.info("CSRF token " + csrfToken.getToken());
}
if (!StringUtils.isEmpty(actualToken)) {
LOGGER.info("X-CSRF-TOKEN " + actualToken);
}
if (actualToken == null || !actualToken.equals(csrfToken.getToken())) {
String pCookieName = "CSRF-TOKEN";
Cookie cookie = new Cookie(pCookieName, csrfToken.getToken());
cookie.setMaxAge(-1);
cookie.setHttpOnly(false);
cookie.setPath("/");
httpServletResponse.addCookie(cookie);
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
这是我的网络安全:
//Start chain for restricting access.
http.addFilterAfter(new ValidateCSRFToken(), CsrfFilter.class)
.authorizeRequests()
//The following paths…
.antMatchers("**")
// …are accessible to all users (authenticated or not).
.permitAll()
.antMatchers( "/actuator/**").permitAll()
// All remaining paths…
.anyRequest()
// ...require user to at least be authenticated
.authenticated()
.and()// And if a user needs to be authenticated...
.formLogin()
// ...redirect them to /username`
.loginPage("/username")
.and()
.logout().clearAuthentication(true).invalidateHttpSession(true).deleteCookies("JSESSIONID")
.and()
// If user isn't authorised to access a path...
.exceptionHandling()
// ...redirect them to /403
.accessDeniedPage("/403")
.and()
.cors()
.and()
.csrf();
// .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());;
所以,问题是:
- 如何验证不通过过滤链?
- 第一次浏览器自带第一个请求怎么办,也就是说,我们怎么知道这个请求属于浏览器而不是攻击者?
【问题讨论】:
-
你不需要自己验证,spring security已经有一个CSRF过滤器,所以你可以去掉过滤器。其次,仅当您在服务器上更改某些内容时才需要发送令牌,因此在 POST、PUT、UPDATE 期间。回答你的第二个问题:你不知道,这就是为什么你有其他安全性,如 CORS、用户登录、令牌、会话 cookie、密码等。永远不要相信客户端或请求。你总是验证“你是谁(身份验证),你可以做你想做的事吗?(授权)”
-
阅读 Spring Security 中的 CSRF 章节以及如何实现它。阅读关于 CSRF 攻击的 OWASP 以了解您在保护自己免受 cheatsheetseries.owasp.org/cheatsheets/… 的影响
-
然后阅读 CSRF 上的 spring 安全参考章节docs.spring.io/spring-security/site/docs/current/reference/…
-
假设浏览器第一次通过 Login API 向后端发送请求。然后这个请求仍然没有 CSRF 令牌(或没有??)和 Spring 生成令牌,但允许请求获取登录逻辑。那么,为什么 bowser 启动时,只发送获取令牌的请求而没有任何逻辑,而用户甚至在 borwser 中什么也不做。我们确信令牌已生成并发回。然后当用户想要登录时,浏览器已经在会话中拥有令牌并提出请求。换句话说,创建专用服务只是为了生成令牌。好吃吗?
-
我想在之前的评论中说,第一次没有令牌传递到应用程序的逻辑内部。所以,是的,我需要一个过滤器来防止它并只返回令牌。
标签: java spring-boot spring-security csrf csrf-token