【问题标题】:Spring Boot securing same endpoint with CSRF token and BasicAuthSpring Boot 使用 CSRF 令牌和 BasicAuth 保护相同的端点
【发布时间】:2019-03-22 03:10:19
【问题描述】:

我有一个 Spring Boot REST 应用程序,它有两个主要部分:

  • 我想用令牌保护 ajax 调用的 UI
  • 我想要进行基本身份验证的公共端点

据我了解,我无法使用 CSRF 令牌保护公共端点,因为它们需要会话。问题是,有些端点需要两者都可以访问,那么当 UI 使用 CSRF 并禁用基本身份验证的 CSRF 时,如何使用 CSRF 保护它们?

这是我目前拥有的,我完全禁用 csrf 以便基本工作......

http.requestMatchers().antMatchers("/form/fill", "/form/fill/*", "/form/fillParams", "/form/fillParams/*").and()
                .csrf().disable().authorizeRequests().anyRequest().hasAnyRole(SecurityConfiguration.ROLE_FORMS_AUTHOR,
                        SecurityConfiguration.ROLE_FORM_FILLER, SecurityConfiguration.ROLE_ADMIN)
                .and().httpBasic();

编辑:我找到了this 旧答案,我想知道是否有一种方法可以针对我的情况利用它,但我仍然不确定如何区分“本地”用户和经过身份验证的用户httpBasic()

【问题讨论】:

  • 对于公共 url 使用 .permitAll() 并且对于任何请求都应该进行身份验证。
  • @kj007 也许我表述错误,但是“公共”的仍然应该用 httpBasic 保护,但是 httpBasic 和 CSRF 令牌不会一起工作,除非你有额外的“握手”请求来检索令牌,这将使 RESTful 失效。

标签: spring-security


【解决方案1】:

在您的 Spring Security java 配置文件中,您可以按如下方式配置 HttpSecurity 对象,以便仅对某些请求启用 CSRF 检查(默认情况下对所有传入请求启用,禁用将禁用所有请求传入请求,因此请求 Mather 可以在此处提供您要启用或禁用 csrf 的路径。)。

确保将 /urls-with-csrf-check/** 替换为您的路径或多个路径。

 @Override
    protected void configure(HttpSecurity http) throws Exception {

        RequestMatcher csrfRequestMatcher = new RequestMatcher() {
            private RegexRequestMatcher requestMatcher =
                    new RegexRequestMatcher("/urls-with-csrf-check/**", null);

            public boolean matches(HttpServletRequest httpServletRequest) {
                if (requestMatcher.matches(httpServletRequest)) {
                    return true;
                }
                return false;
            }
        };

        http.requestMatchers().antMatchers("/form/fill", "/form/fill/*", "/form/fillParams", "/form/fillParams/*").and()
                .csrf()
                .requireCsrfProtectionMatcher(csrfRequestMatcher)
                .and()
                .authorizeRequests().anyRequest().hasAnyRole(SecurityConfiguration.ROLE_FORMS_AUTHOR, SecurityConfiguration.ROLE_FORM_FILLER, SecurityConfiguration.ROLE_ADMIN)
                .and().httpBasic();
    }

【讨论】:

  • 谢谢,我现在只需要找出一种方法来识别本地用户。我设法用 "XMLHttpRequest".equals(request.getHeader("X-Requested-With")) 检查了 ajax,但是有一些正常的表单提交。我唯一想到的是一个隐藏的字段并检查它是否存在,但这不是很安全。
  • 你可以为http基本定义角色??如果我没听错
  • 好点,我可以检查用户角色,但是如何仅从 HttpServletRequest 中获取角色?
  • Spring security 将检查 Principal 是否具有“local”权限(您可以在 ant matcher hasRole("local") 中使用)
  • 但是我如何在 requireCsrfProtectionMatcher 中结合它,例如为此权限启用 CSRF?
【解决方案2】:

通过@kj007 的输入,我能够完成这项工作。 我正在使用requireCsrfProtectionMatcher,这就是我的匹配器的样子:

public class UIRequestMatcher implements RequestMatcher {

    public static final List<GrantedAuthority> USER_ROLES = new ArrayList<>();
    static {
        USER_ROLES.add(new SimpleGrantedAuthority(SecurityConfiguration.ROLE_ADMIN));
        USER_ROLES.add(new SimpleGrantedAuthority(SecurityConfiguration.ROLE_FILES_AUTHOR));
        USER_ROLES.add(new SimpleGrantedAuthority(SecurityConfiguration.ROLE_FORMS_AUTHOR));
        USER_ROLES.add(new SimpleGrantedAuthority(SecurityConfiguration.ROLE_TEMPLATES_AUTHOR));
    }

    @Override
    public boolean matches(HttpServletRequest request) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        return "POST".equals(request.getMethod()) && auth.getAuthorities().stream().anyMatch(USER_ROLES::contains);
    }

}

所以我正在检查 Authentication 是否有我的任何用户角色,因为我的基本身份验证应该只用于我的技术用户。

【讨论】:

    猜你喜欢
    • 2013-07-20
    • 2019-08-29
    • 2023-01-27
    • 2018-07-25
    • 1970-01-01
    • 1970-01-01
    • 2021-03-15
    • 2014-09-01
    • 1970-01-01
    相关资源
    最近更新 更多