spring-boot/security-我可以使用x509证书作为身份验证的额外层吗?

kmb7vmvb  于 2021-07-24  发布在  Java
关注(0)|答案(1)|浏览(575)

我正在构建一个android应用程序,它与受spring安全保护的restapi通信。
由于android应用程序是“公共的”,没有密钥等是安全的,我想创造不同的障碍,使事情复杂,以保护我的api尽可能多。
我想增加更多安全性的一种方法是确保调用我的api的人有一个证书。我不想在我的api信任库中创建数千个证书,所以我只想确保调用者有一个我隐藏在android应用程序密钥库中的证书。
在示例中,我发现springsecurity中的“普通”x509certificate身份验证要求每个用户都有一个唯一的证书,然后这个证书将替换basic auth或jwt auth。我想有个人客户端jwt令牌,但确保每次调用都带来我的一个android应用程序证书,以确保(更多)有人从我的android应用程序调用我的api。
这是可能的还是仅仅是不可能的?
创建resttemplate时,可以使用密钥库和信任存储对其进行配置,这样就很容易了。但是对于保护我的restapi来说似乎更困难,因为我需要证书+jwt令牌或基本身份验证。
我没有对securityconfig使用xml配置。我改为扩展websecurityconfigureradapter。如果可以在configure(httpsecurity-http)方法中配置,那就太好了,但是我想也许我可以在onceperrequestfilter中实现这一点?也许在jwtauthfilter之前配置一个过滤器?
编辑:在我找到的所有spring安全配置示例中,它们似乎总是使用证书作为身份验证。我只想进行配置,这样当有人调用example.com/api/**时,它会检查证书是否被我的自定义信任存储批准(这样我就“知道”这可能是来自我的应用程序的调用),但是如果有人调用example.com/website,它应该使用默认的java信任存储。
如果有人调用example.com/api/**我希望我的服务器
检查证书,如果在我的自定义信任库中证书未被批准,则终止连接。
如果证书没有问题,请使用basic-/jwt身份验证建立https(或者如果在连接建立https连接之前无法终止连接,请继续)到user auth。

v7pvogib

v7pvogib1#

我想我知道了。这里是我如何配置它,它似乎工作。
这个 "/**" endpoint是一个网站,它应该与没有任何特定证书的任何浏览器一起工作,但它需要管理员权限(您需要以管理员身份登录)。
这个 "/api/**" 以及 "/connect/**" 端点需要正确的证书、正确的api密钥和有效的基本或jwt令牌身份验证。

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

    http.authorizeRequests()
            .antMatchers("/**").hasRole("ADMIN")
        .and()
            .formLogin()
                .loginPage("/loginForm")
                .loginProcessingUrl("/authenticateTheUser")
                .permitAll()
        .and()
            .logout()
                .permitAll().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS);

    http.requestMatchers()
            .antMatchers("/connect/**","/api/**")
        .and()
            .addFilterBefore(new APIKeyFilter(null), UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(new JwtAuthorizationFilter(), BasicAuthenticationFilter.class)
            .csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
            .httpBasic()
            .authenticationEntryPoint(authenticationEntryPoint)
        .and()
            .authorizeRequests()
            .antMatchers("/connect/**").hasAnyRole("MASTER,APPCALLER,NEGOTIATOR,MEMBER")
            .antMatchers("/api/**").hasAnyRole("MASTER,MEMBER,ANONYMOUS");

}

apikeyfilter类检查api密钥,并确保调用中使用的证书在我的服务器信任存储中得到批准。api密钥检查是我必须配置的全部,扩展的x509authenticationfilter将自动检查请求证书。我的apikeyfilter如下所示:

public class APIKeyFilter extends X509AuthenticationFilter {

    private String principalRequestHeader = "x-api-key";

    private String apiKey = "XXXX";

    public APIKeyFilter(String principalRequestHeader) {
        if (principalRequestHeader != null) {
            this.principalRequestHeader = principalRequestHeader;
        }
        setAuthenticationManager(new AuthenticationManager() {
            @Override
            public Authentication authenticate(Authentication authentication) throws AuthenticationException {
                if(authentication.getPrincipal() == null) {
                    throw new BadCredentialsException("Access Denied.");
                }
                String rApiKey = (String) authentication.getPrincipal();
                if (authentication.getPrincipal() != null && apiKey.equals(rApiKey)) {
                    return authentication;
                } else {
                    throw new BadCredentialsException("Access Denied.");
                }
            }
        });
    }

    @Override
    protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
        return request.getHeader(principalRequestHeader);
    }

    @Override
    protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
        X509Certificate[] certificates = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
        if (certificates != null && certificates.length > 0) {
            return certificates[0].getSubjectDN();
        }
        return super.getPreAuthenticatedCredentials(request);
    } 
}

cred找到了这些帮助我把事情组合起来的资源:
spring引导-需要api密钥和x509,但不是所有端点都需要
具有多路径的spring安全http antmatcher

相关问题