vlambda博客
学习文章列表

读书笔记《spring-security-third-edition》使用 TLS 的客户端证书身份验证

使用 TLS 的客户端证书身份验证

尽管用户名和密码验证非常常见,正如我们在 第 1 章中所讨论的,不安全应用剖析,在第2章< /a>,Spring Security 入门,存在允许用户提供不同类型凭据的身份验证形式。 Spring Security 也满足了这些要求。在本章中,我们将超越基于表单的身份验证,探索使用可信客户端证书的身份验证。

在本章的课程中,我们将讨论以下主题:

  • Learning how client certificate authentication is negotiated between the user's browser and a compliant server
  • Configuring Spring Security to authenticate users with client certificates
  • Understanding the architecture of client certificate authentication in Spring Security
  • Exploring advanced configuration options related to client certificate authentication
  • Reviewing pros, cons, and common troubleshooting steps when dealing with client certificate authentication

客户端证书身份验证如何工作?

客户端证书认证需要来自服务器的信息请求和来自浏览器的响应,以协商客户端(即用户的浏览器)和服务器应用程序之间的可信认证关系。这种信任关系是通过使用可信且可验证的凭据(称为证书)的交换来建立的。

与到目前为止我们所看到的大部分内容不同,对于客户端证书身份验证,servlet 容器或应用程序服务器本身通常负责通过请求证书、评估证书并将其接受为有效来协商浏览器和服务器之间的信任关系.

客户端证书身份验证也称为相互身份验证,是安全套接字层 (SSL) 协议及其后续协议Transport 的一部分层安全性 (TLS)。由于相互身份验证是 SSL 和 TLS 协议的一部分,因此需要 HTTPS 连接(使用 SSL 或 TLS 保护)才能使用客户端证书身份验证。有关 Spring Security 中 SSL/TLS 支持的更多详细信息,请参阅我们在附录中的讨论和 SSL/TLS 的实现,其他参考资料。需要在 Tomcat(或您一直用于跟随示例的应用程序服务器)中设置 SSL/TLS 以实现客户端证书身份验证。正如在附录其他参考资料中,我们将在本章的其余部分将 SSL/TLS 称为 SSL。

以下序列图说明了在协商 SSL 连接和验证用于相互身份验证的客户端证书的信任时客户端浏览器和 Web 服务器之间的交互:

读书笔记《spring-security-third-edition》使用 TLS 的客户端证书身份验证

我们可以看到,两个证书(服务器证书和客户端证书)的交换提供了双方已知的身份验证,并且可以信任以安全地继续他们的对话。为了清楚起见,我们省略了 SSL 握手的一些细节并信任证书本身的检查;但是,我们鼓励您进一步阅读 SSL 和 TLS 协议以及一般证书领域,因为存在许多关于这些主题的良好参考指南。 RFC 5246传输层安全 (TLS) 协议版本 1.2 (http://tools.ietf.org/html/rfc5246),是开始阅读有关客户端证书演示的好地方,如果您想了解更多细节,SL和 TLS:设计和构建安全系统,Eric Rescorla,Addison-Wesleyhttps://www.amazon.com/SSL-TLS-Designing-Building-Systems/dp/0201615983) 对协议及其实施进行了非常详细的审查。

基于证书的客户端身份验证的另一个名称是 X.509 身份验证。 X.509 一词源自 X.509 标准,最初由 ITU-T 组织发布,用于基于 X.500 标准的目录(LDAP 的起源,您可能还记得 第 6 章LDAP 目录服务)。后来,该标准被改编用于保护互联网通信。

我们在这里提到这一点是因为 Spring Security 中与该主题相关的许多类都引用了 X.509。请记住,X.509 本身并没有定义相互身份验证协议,而是定义了证书的格式和结构以及包含的受信任的证书颁发机构。

设置客户端证书身份验证基础结构

不幸的是,作为个人开发人员,在与 Spring Security 相对容易的集成之前,能够尝试客户端证书身份验证需要一些重要的配置和设置。由于这些设置步骤往往会给初次开发人员带来很多问题,因此我们认为引导您完成这些步骤很重要。

我们假设您使用的是本地自签名服务器证书、自签名客户端证书和 Apache Tomcat。这是大多数开发环境的典型特征;但是,您可能有权访问有效的服务器证书、证书颁发机构 (CA) 或其他应用程序服务器。如果是这种情况,您可以使用这些设置说明作为指导,并以类似的方式配置您的环境。请参阅附录其他参考资料中的 SSL 设置说明,以获取有关配置 Tomcat 和 Spring Security 以在独立环境中使用 SSL 的帮助。

了解公钥基础设施的目的

本章的重点是为学习和教育目的建立一个独立的开发环境。但是,在将 Spring Security 集成到现有的客户端证书保护环境中的大多数情况下,将有大量的基础设施(通常是硬件和软件的组合)来提供功能,例如证书授予和管理,用户自助服务和撤销。这种类型的环境定义了一个公钥基础设施——硬件、软件和安全策略的组合,从而形成了一个高度安全的身份验证驱动的网络生态系统。

除了用于 Web 应用程序身份验证之外,这些环境中的证书或硬件设备还可用于安全、不可否认的电子邮件(使用 S/MIME)、网络身份验证,甚至是物理建筑访问(使用基于 PKCS 11 的硬件设备) )。

虽然这种环境的管理开销可能很高(并且需要卓越的 IT 和流程才能很好地实施),但对于技术专业人员来说,它可以说是最安全的操作环境之一。

创建客户端证书密钥对

自签名客户端证书的创建方式与创建自签名服务器证书的方式相同——通过使用 keytool 命令生成密钥对。客户端证书密钥对的不同之处在于它需要密钥库可供 Web 浏览器使用,并且需要将客户端的公钥加载到服务器的信任库中(稍后我们将解释这是什么)。

如果您现在不想生成自己的密钥,您可以跳到下一部分并使用示例章节中 ./src/main/resources/keys 文件夹中的示例证书。否则,创建客户端密钥对,如下所示:

keytool -genkeypair -alias jbcpclient -keyalg RSA -validity 365 -keystore jbcp_clientauth.p12 -storetype PKCS12
您可以找到有关的其他信息 keytool 以及所有配置选项,位于 Oracle 站点,这里 http://docs.oracle.com /javase/8/docs/technotes/tools/unix/keytool.html/keytool.html

keytool 的大多数参数对于这个用例来说都是相当随意的。但是,当提示您为客户端证书设置名字和姓氏(公用名或 CN,所有者 DN 的一部分)时,请确保第一个提示的答案与我们在我们的Spring Security JDBC 存储。例如,[email protected] 是一个合适的值,因为我们在 Spring Security 中有 [email protected] 用户设置。命令行交互示例如下:

What is your first and last name?
[Unknown]: [email protected]
... etc
Is [email protected], OU=JBCP Calendar, O=JBCP, L=Park City, ST=UT, C=US correct?
[no]: yes

当我们配置 Spring Security 以访问来自证书认证用户的信息时,我们将看到为什么这很重要。在我们可以在 Tomcat 中设置证书身份验证之前,我们还有最后一步,这将在下一节中解释。

配置 Tomcat 信任库

回想一下,密钥对的定义包括私钥和公钥。与 SSL 证书验证和保护服务器通信类似,客户端证书的有效性需要由创建它的认证机构验证。

由于我们使用 keytool 命令创建了我们自己的自签名客户端证书,Java VM 不会隐含地信任它,因为它是由受信任的证书颁发机构分配的。

让我们看一下以下步骤:

  1. We will need to force Tomcat to recognize the certificate as a trusted certificate. We do this by exporting the public key from the key pair and adding it to the Tomcat trust store.
  2. Again, if you do not wish to perform this step now, you can use the existing trust store in .src/main/resources/keys and skip to where we configure server.xml later in this section.

  1. We'll export the public key to a standard certificate file named jbcp_clientauth.cer, as follows:
      keytool -exportcert -alias jbcpclient -keystore jbcp_clientauth.p12 
-storetype PKCS12 -storepass changeit -file jbcp_clientauth.cer
  1. Next, we'll import the certificate into the trust store (this will create the trust store, but in a typical deployment scenario you'd probably already have some other certificates in the trust store):
      keytool -importcert -alias jbcpclient -keystore tomcat.truststore 
-file jbcp_clientauth.cer

上述命令将创建名为 tomcat.truststore 的信任库并提示您输入密码(我们选择了密码 changeit)。您还将看到有关证书的一些信息,最终会被要求确认您确实信任该证书,如下所示:

      Owner: [email protected], OU=JBCP Calendar, O=JBCP, L=Park City,
ST=UT, C=US
Issuer: [email protected], OU=JBCP Calendar, O=JBCP, L=Park City,
ST=UT, C=US
Serial number: 464fc10c
Valid from: Fri Jun 23 11:10:19 MDT 2017 until: Thu Feb 12 10:10:19
MST 2043

//Certificate fingerprints:

MD5: 8D:27:CE:F7:8B:C3:BD:BD:64:D6:F5:24:D8:A1:8B:50
SHA1: C1:51:4A:47:EC:9D:01:5A:28:BB:59:F5:FC:10:87:EA:68:24:E3:1F
SHA256: 2C:F6:2F:29:ED:09:48:FD:FE:A5:83:67:E0:A0:B9:DA:C5:3B:
FD:CF:4F:95:50:3A:
2C:B8:2B:BD:81:48:BB:EF
Signature algorithm name: SHA256withRSA
Version: 3

//Extensions

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 29 F3 A7 A1 8F D2 87 4B EA 74 AC 8A 4B BC 4B 5D
)......K.t..K.K]
0010: 7C 9B 44 4A ..DJ
]
]
Trust this certificate? [no]: yes

记住新的位置 tomcat.truststore 文件,因为我们需要在我们的Tomcat配置中引用它。

密钥库和信任库有什么区别?

Java 安全套接字扩展 ( JSSE) 文档将密钥库定义为私钥及其对应公钥的存储机制。密钥库(包含密钥对)用于加密或解密安全消息等。信任库旨在在验证身份时仅为受信任的通信伙伴存储公钥(类似于在证书身份验证中使用信任库的方式)。然而,在许多常见的管理场景中,密钥库和信任库被合并到一个文件中(在 Tomcat 中,这将通过使用 keystoreFiletruststoreFile 连接器的属性)。文件本身的格式可以完全相同。实际上,每个文件都可以是任何 JSSE 支持的密钥库格式,包括 Java 密钥库 ( JKS)、PKCS 12 等。
  1. As previously mentioned, we assume you have already configured the SSL Connector, as outlined in the Appendix, Additional Reference Material. If you do not see the keystoreFile or keystorePass attributes in server.xml, it means you should visit the Appendix, Additional Reference Material to get SSL set up.
  2. Finally, we'll need to point Tomcat at the trust store and enable client certificate authentication. This is done by adding three additional attributes to the SSL connector in the Tomcat server.xml file, as follows:
//sever.xml

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
sslProtocol="TLS"
keystoreFile="<KEYSTORE_PATH>/tomcat.keystore"
keystorePass="changeit"
truststoreFile="<CERT_PATH>/tomcat.truststore"
truststorePass="changeit"
clientAuth="true"
/>
server.xml 文件位于 TOMCAT_HOME/conf/server.xml。如果您使用 Eclipse 或 Spring Tool Suite 与 Tomcat 交互,您会发现一个名为 服务器 包含 server.xml。例如,如果您使用的是 Tomcat 8,则 Eclipse 工作区中的路径可能类似于 /Servers/Tomcat v7.0 服务器localhost-config/server.xml
  1. This should be the remaining configuration required to trigger Tomcat to request a client certificate when an SSL connection is made. Of course, you will want to ensure you replace both <CERT_PATH> and <KEYSTORE_PATH> with the full paths. For example, on a Unix-based operating system, the path might look like this: /home/mickknutson/packt/chapter8/keys/tomcat.keystore.
  2. Go ahead and try to start up Tomcat to ensure that the server starts up without any errors in the logs.
还有一种方法可以配置 Tomcat 以选择性地使用客户端证书身份验证——我们将在本章后面启用它。现在,我们首先需要使用客户端证书来连接到 Tomcat 服务器。这样可以更轻松地诊断您是否已正确设置!

在 Spring Boot 中配置 Tomcat

我们还可以在 Spring Boot 中配置嵌入式 Tomcat 实例,这就是我们将在本章剩余部分使用 Tomcat 的方式。

配置 Spring Boot 以使用我们新创建的证书与 YAML 条目的属性一样简单,如以下代码片段所示:

    server:
port: 8443
ssl:
key-store: "classpath:keys/jbcp_clientauth.p12"
key-store-password: changeit
keyStoreType: PKCS12
keyAlias: jbcpclient
protocol: TLS

最后一步是将证书导入客户端浏览器。

将证书密钥对导入浏览器

根据您使用的浏览器,导入证书的过程可能会有所不同。我们将在此处提供 Firefox、Chrome 和 Internet Explorer 的安装说明,但如果您使用其他浏览器,请查阅其帮助部分或您最喜欢的搜索引擎以获得帮助。

使用火狐

执行以下步骤在 Firefox 中导入包含客户端证书密钥对的密钥库:

  1. Click on Edit | Preferences.
  2. Click on the Advanced button.
  3. Click on the Encryption tab.
  4. Click on the View Certificates button. The Certificate Manager window should open up.
  5. Click on the Your Certificates tab.
  6. Click on the Import... button.
  7. Browse to the location where you saved the jbcp_clientauth.p12 file and select it. You will need to enter the password (that is, changeit) that you used when you created the file.

应该导入客户端证书,您应该在列表中看到它。

使用 Chrome

执行以下步骤在 Chrome 中导入包含客户端证书密钥对的密钥库:

  1. Click on the wrench icon on the browser toolbar.
  2. Select Settings.
  3. Click on Show advanced settings....
  4. In the HTTPS/SSL section, click on the Manage certificates... button.
  5. In the Your Certificates tab, click on the Import... button.

  1. Browse to the location where you saved the jbcp_clientauth.p12 file and select it.
  2. You will need to enter the password (that is, changeit) that you used when you created the file.
  3. Click on OK.

使用 Internet Explorer

由于 Internet Explorer 紧密集成到 Windows 操作系统中,因此导入密钥存储会更容易一些。让我们看一下以下步骤:

  1. Double-click on the jbcp_clientauth.p12 file in Windows Explorer. The Certificate Import Wizard window should open.
  2. Click on Next and accept the default values until you are prompted for the certificate password.
  3. Enter the certificate password (that is, changeit) and click Next.
  4. Accept the default Automatically select the certificate store option and click Next.
  5. Click on Finish.

要验证证书是否正确安装,您需要执行另一系列步骤:

  1. Open the Tools menu (Alt + X) in Internet Explorer.
  2. Click on the Internet Options menu item.
  3. Click on the Content tab.
  4. Click on the Certificates button.
  5. Click on the Personal tab, if it is not already selected. You should see the certificate listed here.

结束测试

您现在应该能够使用客户端证书连接到 JBCP 日历站点。导航到 https://localhost:8443/,注意使用 HTTPS 和 8443。如果一切设置正确,当您尝试访问该站点时,应该会提示您输入证书 - 在 Firefox 中,证书显示如下:

读书笔记《spring-security-third-edition》使用 TLS 的客户端证书身份验证

但是,您会注意到,如果您尝试访问站点的受保护部分,例如 My Events 部分,您将被重定向到登录页面。这是因为我们还没有配置 Spring Security 来识别证书中的信息——此时,客户端和服务器之间的协商已经停止在 Tomcat 服务器本身。

您应该从以下代码开始 chapter08.00-日历

客户端证书身份验证故障排除

不幸的是,如果我们说第一次正确配置客户端证书身份验证(没有任何问题)很容易,那我们就是在骗你。事实是,尽管这是一个非常强大的安全设备,但浏览器和 Web 服务器制造商的文档记录都很差,而且出现的错误消息充其量是令人困惑的,最坏的情况是具有误导性。

请记住,在这一点上,我们根本没有在等式中涉及 Spring Security,因此调试器很可能无法帮助您(除非您手边有 Tomcat 源代码)。有一些常见的错误和需要检查的东西。

当您访问该站点时,系统不会提示您输入证书。这有很多可能的原因,这可能是最令人费解的问题。以下是一些需要检查的事项:

  1. Ensure that the certificate has been installed in the browser client you are using. Sometimes, you need to restart the whole browser (close all windows) if you attempted to access the site previously and were rejected.
  2. Ensure you are accessing the SSL port for the server (typically 8443 in a development setup), and have selected the HTTPS protocol in your URL. The client certificates are not presented in insecure browser connections. Make sure the browser also trusts the server SSL certificate, even if you have to force it to trust a self-signed certificate.
  3. Ensure you have added the clientAuth directive to your Tomcat configuration (or the equivalent for whatever application server you are using).
  4. If all else fails, use a network analyzer or packet sniffer, such as Wireshark (http://www.wireshark.org/) or Fiddler2 (http://www.fiddler2.com/), to review the traffic and SSL key exchange over the wire (check with your IT department first—many companies do not allow tools of this kind on their networks).

  1. If you are using a self-signed client certificate, make sure the public key has been imported into the server's trust store. If you are using a CA-assigned certificate, make sure the CA is trusted by the JVM or that the CA certificate is imported into the server's trust store.
  2. Internet Explorer, in particular, does not report details of client certificate failures at all (it simply reports a generic Page Cannot be Displayed error). Use Firefox for diagnosing if an issue you are seeing is related to client certificates or not.

在 Spring Security 中配置客户端证书认证

与迄今为止我们使用的身份验证机制不同,使用客户端证书身份验证会导致服务器对用户的请求进行预身份验证。由于服务器(Tomcat)已经确定用户提供了一个有效且值得信赖的证书,Spring Security 可以简单地信任这个有效性断言。

仍然缺少安全登录过程的一个重要组成部分,即经过身份验证的用户的授权。这就是我们的 Spring Security 配置的用武之地——我们必须向 Spring Security 添加一个组件,该组件将识别来自用户 HTTP 会话(由 Tomcat 填充)的证书身份验证信息,然后根据 Spring Security 验证提供的凭据UserDetailsS​​ervice 调用。 UserDetailsS​​ervice 的调用将导致确定证书中声明的用户是否为 Spring Security 所知道,然后它将按照通常的登录分配 GrantedAuthority规则。

使用安全命名空间配置客户端证书身份验证

考虑到 LDAP 配置的所有复杂性,配置客户端证书身份验证是一种受欢迎的缓和措施。如果我们使用安全命名空间样式的配置,添加客户端证书身份验证是一个简单的单行配置更改,添加在 HttpSecurity 声明中。继续对提供的 SecurityConfig.java 配置进行以下更改:

//src/main/java/com/packtpub/springsecurity/configuration/SecurityConfig.java
http.x509().userDetailsService(userDetailsService);
观察到 .x509() 方法引用了我们现有的 userDetailsS​​ervice() 配置。为简单起见,我们使用 UserDetailsS​​erviceImpl 实现包含在 第五章使用 Spring Data 进行身份验证。但是,我们可以很容易地将它与任何其他实现(即 LDAP 或基于 JDBC 的实现)交换。 第 4 章基于 JDBC 的身份验证)。

重新启动应用程序后,系统会再次提示您输入客户端证书,但这一次,您应该能够访问需要授权的站点区域。您可以从日志(如果您启用它们)中看到您已作为 [email protected] 用户登录。

您的代码应如下所示 chapter08.01-日历

Spring Security 如何使用证书信息?

如前所述,Spring Security 参与证书交换是从提供的证书中获取信息并将用户的凭据映射到用户服务。在 .x509() 方法的使用中,我们没有看到使这种情况发生的魔力。回想一下,当我们设置客户端证书时,类似于 LDAP DN 的 DN 与证书相关联:

    Owner: [email protected], OU=JBCP Calendar, O=JBCP, L=Park City, ST=UT, C=US

Spring Security 使用此 DN 中的信息来确定主体的实际用户名,并将在 UserDetailsS​​ervice 中查找此信息。特别是,它允许指定正则表达式,用于匹配与证书建立的 DN 的一部分,并使用这部分 DN 作为主体名称。 .x509() 方法的隐式默认配置如下:

  http.x509()
.userDetailsService(userDetailsService)
.subjectPrincipalRegex("CN=(.*?),");

我们可以看到这个正则表达式将匹配 [email protected] 值作为主体的名称。此正则表达式必须包含单个匹配组,但可以将其配置为支持应用程序的用户名和 DN 颁发要求。例如,如果您的组织证书的 DN 包含 emailuserid 字段,则可以修改正则表达式以将这些值用作经过身份验证的主体的名称。

Spring Security 证书身份验证的工作原理

借助下图,让我们回顾一下参与审查和评估客户端证书并转换为 Spring Security 身份验证会话的各种参与者:

读书笔记《spring-security-third-edition》使用 TLS 的客户端证书身份验证

我们可以看到 o.s.s.web.authentication.preauth.x509.X509AuthenticationFilter 负责检查未经身份验证的用户对呈现客户端证书的请求。如果它发现请求包含有效的客户端证书,它将使用 o.s.s.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor 提取主体,使用与证书所有者的 DN 匹配的正则表达式,如前所述。

请注意,尽管上图表明对未经身份验证的用户进行了证书检查,但当提供的证书识别出与先前已通过身份验证的用户不同的用户时,也可以执行检查。这将导致使用新提供的凭据进行新的身份验证请求。这样做的原因应该很清楚——任何时候用户提供一组新的凭据,应用程序都必须意识到这一点,并以负责任的方式做出反应,确保用户仍然能够访问它。

一旦证书被接受(或拒绝/忽略),与其他身份验证机制一样,将构建一个 Authentication 令牌并将其传递给 AuthenticationManager 以进行身份​​验证。我们现在可以查看 o.s.s.web.authentication.preauth.PreAuthenticatedAuthenticationProvider 处理身份验证令牌的非常简短的说明:

读书笔记《spring-security-third-edition》使用 TLS 的客户端证书身份验证

尽管我们不会详细讨论它们,但 Spring Security 还支持许多其他预身份验证机制。一些示例包括 Java EE 角色映射 (J2eePreAuthenticatedProcessingFilter)、WebSphere 集成 (WebSpherePreAuthenticatedProcessingFilter) 和 Site Minder 样式的身份验证 (RequestHeaderAuthenticationFilter)。如果您了解客户端证书身份验证的流程,那么了解这些其他身份验证类型会容易得多。

使用 AuthenticationEntryPoint 处理未经身份验证的请求

由于如果身份验证失败,X509AuthenticationFilter 将继续处理请求,因此我们需要处理用户未成功身份验证并请求受保护资源的情况。 Spring Security 允许开发人员自定义它的方式是插入自定义的 o.s.s.web.AuthenticationEntryPoint 实现。在默认的表单登录场景中,如果用户被拒绝访问受保护的资源并且未通过身份验证,则使用 LoginUrlAuthenticationEntryPoint 将用户重定向到登录页面。

相比之下,在典型的客户端证书身份验证环境中,根本不支持其他身份验证方法(请记住,Tomcat 在 Spring Security 表单登录发生之前就需要证书)。因此,保留重定向到表单登录页面的默认行为是没有意义的。相反,我们将修改入口点,使用 o.s.s.web.authentication.Http403ForbiddenEntryPoint 简单地返回 HTTP 403 Forbidden 消息。继续并在您的 SecurityConfig.java 文件中进行以下更新,如下所示:

    //src/main/java/com/packtpub/springsecurity/configuration/SecurityConfig.java

@Autowired
private Http403ForbiddenEntryPoint forbiddenEntryPoint;
http.exceptionHandling()
.authenticationEntryPoint(forbiddenEntryPoint)
.accessDeniedPage("/errors/403");
...
@Bean
public Http403ForbiddenEntryPoint forbiddenEntryPoint(){
return new Http403ForbiddenEntryPoint();
}

现在,如果用户尝试访问受保护的资源并且无法提供有效的证书,他们将看到以下页面,而不是被重定向到登录页面:

读书笔记《spring-security-third-edition》使用 TLS 的客户端证书身份验证
您的代码现在应该看起来像 chapter08.02-日历

通常使用客户端证书身份验证执行的其他配置或应用程序流程调整如下:

  • Removal of the form-based login page altogether
  • Removal of the logout link (as there's no reason to log out because the browser will always present the user's certificate)
  • Removal of the functionality to rename the user account and change the password
  • Removal of the user registration functionality (unless you are able to tie it into the issuance of a new certificate)

支持双模认证

某些环境也可能同时支持基于证书和基于表单的身份验证。如果您的环境是这种情况,也可以(并且很简单)使用 Spring Security 来支持它。我们可以简单地保留默认的 AuthenticationEntryPoint 界面(重定向到基于表单的登录页面)不变,并允许用户在不提供客户端证书的情况下使用标准登录表单登录。

如果您选择以这种方式配置您的应用程序,您需要调整 Tomcat SSL 设置(根据您的应用程序服务器进行更改)。只需将 clientAuth 指令更改为 want,而不是 true

   <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
sslProtocol="TLS"
keystoreFile="conf/tomcat.keystore"
keystorePass="password"
truststoreFile="conf/tomcat.truststore"
truststorePass="password"
clientAuth="want"
/>

我们还需要删除我们在上一个练习中配置的 authenticationEntryPoint() 方法,以便在用户无法提供有效证书时使用标准的基于表单的身份验证工作流程在第一次查询浏览器时。

虽然这很方便,但对于双模式(基于表单和基于证书)身份验证,有几点需要牢记,如下所示:

  • Most browsers will not reprompt the user for a certificate if they have failed certificate authentication once, so make sure that your users are aware that they may need to reenter the browser to present their certificate again.
  • Recall that a password is not required to authenticate users with certificates; however, if you are still using UserDetailsService to support your form-based authenticated users, this may be the same UserDetailsService object that you use to give the PreAuthenticatedAuthenticationProvider information about your users. This presents a potential security risk, as users who you intend to sign in only with certificates could potentially authenticate using form login credentials.

有几种方法可以解决这个问题,它们在以下列表中进行了描述:

  • Ensure that the users authenticating with certificates have an appropriately strong password in your user store.
  • Consider customizing your user store to clearly identify users who are enabled for form-based login. This can be tracked with an additional field in the table holding user account information, and with minor adjustments to the SQL queries used by the JpaDaoImpl object.
  • Configure a separate user details store altogether for users who are logging in as certificate-authenticated users, to completely segregate them from users that are allowed to use form-based login.
  • Dual-mode authentication can be a powerful addition to your site and can be deployed effectively and securely, provided that you keep in mind the situations under which users will be granted access to it.

使用 Spring bean 配置客户端证书身份验证

在本章前面,我们回顾了客户端证书身份验证中涉及的类的流程。因此,我们使用显式 bean 配置 JBCP 日历应该很简单。通过使用显式配置,我们可以使用其他配置选项。让我们看一下如何使用显式配置:

    //src/main/java/com/packtpub/springsecurity/configuration/SecurityConfig.java

@Bean
public X509AuthenticationFilter x509Filter(AuthenticationManager
authenticationManager){
return new X509AuthenticationFilter(){{
setAuthenticationManager(authenticationManager);
}};
}
@Bean
public PreAuthenticatedAuthenticationProvider
preauthAuthenticationProvider(AuthenticationUserDetailsService
authenticationUserDetailsService){
return new PreAuthenticatedAuthenticationProvider(){{
setPreAuthenticatedUserDetailsService(authenticationUserDetailsService);
}};
}
@Bean
public UserDetailsByNameServiceWrapper
authenticationUserDetailsService(UserDetailsService userDetailsService){
return new UserDetailsByNameServiceWrapper(){{
setUserDetailsService(userDetailsService);
}};
}

我们还需要删除 x509() 方法并将 x509Filter 添加到我们的过滤器链中,并将我们的 AuthenticationProvider 实现添加到 身份验证管理器

    //src/main/java/com/packtpub/springsecurity/configuration/SecurityConfig.java

@Override
protected void configure(HttpSecurity http) throws Exception {
http.x509()
//.userDetailsService(userDetailsService)
.x509AuthenticationFilter(x509Filter());
...
}
@Override
public void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth
.authenticationProvider(preAuthAuthenticationProvider)
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}

现在,试试这个应用程序。从用户的角度来看,没有什么太大的变化,但作为开发人员,我们已经打开了许多额外配置选项的大门。

您的代码现在应该看起来像 chapter08.03-日历

基于 bean 的配置的附加功能

Spring bean-based configuration 的使用通过暴露 bean 属性为我们提供了额外的功能,这些属性 通过 配置的安全命名空间样式暴露。

X509AuthenticationFilter 上可用的其他属性如下:

财产

说明

默认

continueFilterChainOn UnsuccessfulAuthentication

如果为 false,则失败的身份验证将引发异常,而不是允许请求继续。这通常在需要有效证书才能访问安全站点的情况下设置。如果为真,过滤器链将继续,即使身份验证失败。

checkForPrincipalChanges

如果为 true,过滤器将检查当前已验证的用户名是否与客户端证书中显示的用户名不同。如果是这样,将对新证书执行身份验证,并且 HTTP 会话将失效(可选,请参阅下一个属性)。如果为 false,则一旦用户通过身份验证,即使他们提供不同的凭据,他们仍将保持身份验证。

invalidateSessionOn PrincipalChange

如果为 true,并且请求中的主体发生更改,则用户的 HTTP 会话将在重新验证之前失效。如果为 false,则会话将保留 - 请注意,这可能会带来安全风险。

PreAuthenticatedAuthenticationProvider 实现有几个有趣的属性可供我们使用,如下表所示:

财产

说明

默认

preAuthenticatedUser
DetailsS​​ervice

此属性用于根据从证书中提取的用户名构建完整的 UserDetails 对象。

没有任何

throwExceptionWhen
TokenRejected

如果为 true,当令牌构造不正确(不包含用户名或证书)时,将引发 BadCredentialsException 异常。在专门使用证书的环境中,它通常设置为 true

没有任何

除了这些属性之外,还有许多其他机会可以实现接口或扩展证书身份验证中涉及的类,以进一步自定义您的实现。

实施客户端证书身份验证时的注意事项

客户端证书身份验证虽然高度安全,但并不适合所有人,也不适合所有情况。

列出了客户端证书认证的优点,如下所示:

  • Certificates establish a framework of mutual trust and verifiability that both parties (client and server) are who they say they are
  • Certificate-based authentication, if implemented properly, is much more difficult to spoof or tamper with than other forms of authentication
  • If a well-supported browser is used and configured correctly, client certificate authentication can effectively act as a single sign-on solution, enabling transparent login to all certificate-secured applications

列出客户端证书认证的缺点,如下:

  • The use of certificates typically requires the entire user population to have them. This can lead to both a user training burden and an administrative burden. Most organizations deploying certificate-based authentication on a large scale must have sufficient self-service and helpdesk support for certificate maintenance, expiration tracking, and user assistance.
  • The use of certificates is generally an all-or-nothing affair, meaning that mixed-mode authentication and offering support for non-certificated users is not provided due to the complexity of web server configuration, or poor application support.
  • The use of certificates may not be well supported by all users in your user population, including the ones who use mobile devices.
  • The correct configuration of the infrastructure required to support certificate-based authentication may require advanced IT knowledge.

如您所见,客户端证书身份验证既有优点也有缺点。如果实施得当,它可以为您的用户提供一种非常方便的访问模式,并且具有极具吸引力的安全性和不可否认性属性。您将需要确定您的特定情况,以查看这种类型的身份验证是否合适。

概括

在本章中,我们检查了基于证书的客户端身份验证的架构、流程和 Spring Security 支持。我们已经介绍了客户端证书(相互)身份验证的概念和整体流程。我们探讨了为自签名 SSL 和客户端证书方案配置 Apache Tomcat 所需的重要步骤。

我们还学习了配置 Spring Security 以了解客户端提供的基于证书的凭据。我们介绍了与证书身份验证相关的 Spring Security 类的体系结构。我们还知道如何配置 Spring bean 样式的客户端证书环境。我们还介绍了这种身份验证的优缺点。

对于不熟悉客户端证书的开发人员来说,这种环境的许多复杂性使他们感到困惑是很常见的。我们希望本章使这个复杂的主题更容易理解和实施!在下一章中,我们将讨论如何使用 OpenID 完成单点登录。