【问题标题】:Implementing 2 way SSL using spring boot使用 Spring Boot 实现 2 路 SSL
【发布时间】:2016-02-21 20:58:03
【问题描述】:

我正在创建一些宁静的 Web 服务,并正在使用 Spring-Boot 创建一个嵌入式 tomcat 容器。

其中一个要求是这实现了 2 路 SSL。我一直在查看 HttpSecurity 对象,并且可以使用以下方法使其仅通过 SSL 通道运行 Web 服务:-

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

    System.out.println("CONFIGURED");

    http
        // ...
        .requiresChannel()
            .anyRequest().requiresSecure();
}

我似乎找不到一种使 Web 服务仅可供提供有效客户端证书的应用程序访问的方法。

我只有 SSL 的基本知识,因此即使是正确方向的一般指针也将不胜感激。

正在部署的服务器将包含多种应用程序 - 这是唯一需要使用 2-way SSL 锁定的服务器。我真正想要的是一种锁定单个应用程序以仅接受客户端证书的方法。

【问题讨论】:

  • 感谢您的回复。提供的链接似乎是为了完全锁定 tomcat 7,但是将部署它的服务器是共享资源,因此上面将混合有安全和非安全项目。我真正想要的是一种使用 Spring Security 和客户端证书锁定单个 Web 应用程序的方法。
  • 所以它可能是来自 Spring Boot 的嵌入式 tomcat 容器,我需要研究更多。

标签: java ssl spring-security spring-boot tomcat8


【解决方案1】:

我遇到了类似的问题,并想我会分享我的解决方案。

首先,您需要了解 SSL 证书身份验证将在您的 Web 服务器端处理(参见 dur 的解释,使用“clientAuth=want”设置)。 然后,必须配置您的 Web 应用程序才能处理提供的(和允许的)证书,将其映射到用户等。

我与您的细微差别是我将 Spring Boot 应用程序打包到 WAR 存档中,然后将其部署在现有的 Tomcat 应用程序服务器上。

我的 Tomcat 的 server.xml 配置文件定义了一个 HTTPS 连接器,如下:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
    maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
    keystoreFile="/opt/tomcat/conf/key-stores/ssl-keystore.jks"
    keystorePass=“some-complex-password“
    clientAuth="want" sslProtocol="TLS"
    truststoreFile="/opt/tomcat/conf/trust-stores/ssl-truststore.jks"
    truststorePass=“some-other-complex-password” />

小注释以避免任何混淆:keystoreFile 包含用于 SSL 的证书/私钥对(仅),而 truststoreFile 包含允许客户端 SSL 身份验证的 CA 证书(请注意,您也可以将客户端证书直接添加到该信任-商店)。

如果您在 Spring Boot 应用程序中使用嵌入式 tomcat 容器,您应该能够使用以下属性键/值在应用程序的属性文件中配置这些设置:

server.ssl.key-store=/opt/tomcat/conf/key-stores/ssl-keystore.jks
server.ssl.key-store-password=some-complex-password
server.ssl.trust-store=/opt/tomcat/conf/trust-stores/ssl-truststore.jks
server.ssl.trust-store-password=some-other-complex-password
server.ssl.client-auth=want

然后,在我的网络应用程序中,我声明一个特定的 SSL 配置,如下所示:

@Configuration
@EnableWebSecurity
//In order to use @PreAuthorise() annotations later on...
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SSLAuthConfiguration extends WebSecurityConfigurerAdapter {

    @Value("${allowed.user}")
    private String ALLOWED_USER;

    @Value("${server.ssl.client.regex}")
    private String CN_REGEX;

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure (final HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
                .authorizeRequests()
                .antMatchers("/url-path-to-protect").authenticated() //Specify the URL path(s) requiring authentication...
            .and()
                .x509() //... and that x509 authentication is enabled
                    .subjectPrincipalRegex(CN_REGEX)
                    .userDetailsService(userDetailsService);
    }

    @Autowired
    //Simplified case, where the application has only one user...
    public void configureGlobal (final AuthenticationManagerBuilder auth) throws Exception {
        //... whose username is defined in the application's properties.
        auth
            .inMemoryAuthentication()
                .withUser(ALLOWED_USER).password("").roles("SSL_USER");
    }

}

然后我需要声明 UserDetailsS​​ervice bean(例如在我的应用程序的主类中):

@Value("${allowed.user}")
private String ALLOWED_USER;

@Bean
public UserDetailsService userDetailsService () {

    return new UserDetailsService() {

        @Override
        public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
            if (username.equals(ALLOWED_USER)) {
                final User user = new User(username, "", AuthorityUtils.createAuthorityList("ROLE_SSL_USER"));
                return user;
            }
            return null;
        }
    };
}

就是这样!然后我可以将@PreAuthorize(“hasRole(‘ROLE_SSL_USER’)”) 注释添加到我想要保护的方法中。

总结一下,认证流程如下:

  1. 用户提供 SSL 证书;
  2. Tomcat 根据其信任库进行验证;
  3. 自定义 WebSecurityConfigurerAdapter 从证书的 CN 检索“用户名”;
  4. 应用程序对与检索到的用户名关联的用户进行身份验证;
  5. 在方法级别,如果使用@PreAuthorize("hasRole('SSL_USER')") 注解,应用程序将检查用户是否具有所需的角色。

【讨论】:

    【解决方案2】:

    你可以配置clientAuth=want,见Apache Tomcat 8 Configuration Reference

    如果您希望 SSL 堆栈在接受连接之前需要来自客户端的有效证书链,请设置为 true。如果您希望 SSL 堆栈请求客户端证书,请设置为 want,但如果没有提供则不会失败。 false 值(这是默认值)将不需要证书链,除非客户端请求受使用 CLIENT-CERT 身份验证的安全约束保护的资源。

    然后用Spring Security - X.509 Authentication读取客户端证书:

    您还可以将 SSL 与“相互身份验证”一起使用;然后,作为 SSL 握手的一部分,服务器将向客户端请求有效证书。服务器将通过检查其证书是否由可接受的权威机构签署来验证客户端。如果提供了有效证书,则可以通过应用程序中的 servlet API 获取。 Spring Security X.509 模块使用过滤器提取证书。它将证书映射到应用程序用户并加载该用户的一组授予权限,以与标准 Spring Security 基础架构一起使用。

    clientAuth 也可以设置为want,如果您仍然希望 SSL 连接成功,即使客户端不提供证书。不提供证书的客户端将无法访问任何受 Spring Security 保护的对象,除非您使用非 X.509 身份验证机制,例如表单身份验证。

    【讨论】:

      猜你喜欢
      • 2012-10-03
      • 1970-01-01
      • 2021-02-19
      • 1970-01-01
      • 1970-01-01
      • 2020-09-01
      • 2018-03-28
      • 2017-08-15
      • 2020-01-07
      相关资源
      最近更新 更多