X.509 证书认证最常见的用途是在使用 SSL 时验证服务器的身份,最常见的是在从浏览器使用 HTTPS 时。浏览器将自动检查服务器提供的证书是否由它所维护的可信证书颁发机构列表之一颁发(即数字签名)。 你还可以使用 "mutual authentication" 的SSL;然后,服务器将请求来自客户端的有效证书作为 SSL 握手的一部分。服务器将通过检查其证书由可接受的权限签名来验证客户端。如果已提供有效证书,则可以通过应用程序中的 servlet API 获得。Spring Security X.509 模块使用过滤器提取证书。它将证书映射到应用程序用户,并加载该用户的授权权限集,以便与标准 Spring Security 基础设施一起使用。 在尝试将 servlet 容器与 Spring Security 一起使用之前,你应该熟悉使用证书并为其设置客户端认证。大部分工作是创建和安装合适的证书和密钥。例如,如果使用 Tomcat,则在这里阅读 http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html 的说明。重要的是你要先做这个工作然后再试用 Spring Security
启用 X.509 客户端认证非常简单。只需将 <http> ... <x509 subject-principal-regex="CN=(.*?)," user-service-ref="userService"/>; </http> 这个元素有两个可选属性:
Spring Security 项目中的
要运行使用 SSL 支持的 tomcat,请将 <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" scheme="https" secure="true" clientAuth="true" sslProtocol="TLS" keystoreFile="${catalina.home}/conf/server.jks" keystoreType="JKS" keystorePass="password" truststoreFile="${catalina.home}/conf/server.jks" truststoreType="JKS" truststorePass="password" />
如果你仍然希望 SSL 连接成功,即使客户端不提供证书,也可以将
通过在安全对象回调阶段临时替换
Authentication buildRunAs(Authentication authentication, Object object, List<ConfigAttribute> config); boolean supports(ConfigAttribute attribute); boolean supports(Class clazz);
第一个方法返回
替换
为了确保恶意代码不创建 <bean id="runAsManager" class="org.springframework.security.access.intercept.RunAsManagerImpl"> <property name="key" value="my_run_as_password"/> </bean> <bean id="runAsAuthenticationProvider" class="org.springframework.security.access.intercept.RunAsImplAuthenticationProvider"> <property name="key" value="my_run_as_password"/> </bean>
通过使用相同的密钥,每个 Spring Security Crypto 模块为对称加密、密钥生成和密码编码提供支持。该代码作为核心模块的一部分分发,但不依赖于任何其他 Spring Security(或 Spring)代码。 Encryptors 类提供了用于构建对称加密器的工厂方法。使用这个类,你可以创建 ByteEncryptors 来加密原始 byte[] 表单中的数据。还可以构造 TextEncryptors 来加密文本字符串。Encryptors 是线程安全的。 使用 Encryptors.standard 工厂方法来构造一个标准 BytesEncryptor: Encryptors.standard("password", "salt"); 标准加密方法是使用 PKCS #5 的 PBKDF2(基于密码的密钥推导函数 #2)的 256-bit AES。此方法需要 Java 6。用于生成密钥的密码应该保持在安全的位置,而不是共享的。如果你的加密数据被破坏,则使用盐来防止对密钥的字典攻击。还应用了 16-byte 的随机初始化向量,因此每个加密的消息都是唯一的。 所提供的盐应该是十六进制编码的字符串形式,是随机的,并且长度至少为8字节。可以使用密钥生成器生成这样的盐: String salt = KeyGenerators.string().generateKey(); // generates a random 8-byte salt that is then hex-encoded
使用 Encryptors.text 工厂方法构建标准 TextEncryptor: Encryptors.text("password", "salt"); TextEncryptor 使用标准的字节加密器来加密文本数据。加密结果作为十六进制编码字符串返回,以便于文件系统或数据库中的存储。 使用 Encryptors.queryableText 工厂方法构造一个可查询的 TextEncryptor: Encryptors.queryableText("password", "salt"); 可查询 TextEncryptor 和标准 TextEncryptor 之间的差异与初始化向量(iv)处理有关。在可查询 TextEncryptor#encrypt 操作中使用的 iv 是共享的或不变的,并且不是随机生成的。这意味着多次加密相同的文本总是产生相同的加密结果。这是不太安全的,但是对于需要被查询的加密数据来说是必要的。可查询加密文本的一个例子是 OAuth apiKey。 KeyGenerators 类为构建不同类型的密钥生成器提供了许多便利的工厂方法。使用这个类,你可以创建 BytesKeyGenerator 来生成 byte[] 密钥。还可以构造 StringKeyGenerator 来生成 string 密钥。KeyGenerators 是线程安全的。 使用 KeyGenerators.secureRandom 工厂方法生成一个由 SecureRandom 实例支持的 BytesKeyGenerator: BytesKeyGenerator generator = KeyGenerators.secureRandom();
byte[] key = generator.generateKey();
默认密钥长度为8字节。还有一个 KeyGenerators.secureRandom 变量,提供对密钥长度的控制: KeyGenerators.secureRandom(16);
使用 KeyGenerators.shared 工厂方法构造一个 BytesKeyGenerator,它总是在每次调用时返回相同的密钥: KeyGenerators.shared(16);
spring-security-crypto 模块的密码包提供了对密码进行编码的支持。 public interface PasswordEncoder { String encode(String rawPassword); boolean matches(String rawPassword, String encodedPassword); } 如果 rawPassword 一旦编码,等于编码密码,则匹配方法返回 true。该方法被设计为支持基于口令的认证模式。
// Create an encoder with strength 16 BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16); String result = encoder.encode("myPassword"); assertTrue(encoder.matches("myPassword", result));
// Create an encoder with all the defaults Pbkdf2PasswordEncoder encoder = new Pbkdf2PasswordEncoder(); String result = encoder.encode("myPassword"); assertTrue(encoder.matches("myPassword", result)); |