Spring Security:DB 和 applicationContext 中的密码编码

Posted

技术标签:

【中文标题】Spring Security:DB 和 applicationContext 中的密码编码【英文标题】:Spring Security:password encoding in DB and in applicationContext 【发布时间】:2012-01-21 05:13:08 【问题描述】:

有配置(applicationContext-security.xml):

<authentication-manager alias="authenticationManager">
    <authentication-provider>
    <password-encoder hash="sha"/>
        <jdbc-user-service data-source-ref="dataSource"/>
    </authentication-provider>
</authentication-manager>

从另一边有我的dataSource(它是JdbcDaoImpl)的SQL:

...
    public static final String DEF_USERS_BY_USERNAME_QUERY =
            "select username,password,enabled " +
            "from users " +
            "where username = ?";
...

此代码中现在有关于sha 的字样,因此从标准 Spring Security users 表中选择的密码未编码。

也许,我应该在我的休眠映射配置中为password 列提供一些sha 属性:

<class name="model.UserDetails" table="users">
    <id name="id">
        <generator class="increment"/>
    </id>
    <property name="username" column="username"/>
    <property name="password" column="password"/>
    <property name="enabled" column="enabled"/>
    <property name="mail" column="mail"/>
    <property name="city" column="city"/>
    <property name="confirmed" column="confirmed"/>
    <property name="confirmationCode" column="confirmation_code"/>

    <set name="authorities" cascade="all" inverse="true">
        <key column="id" not-null="true"/>
        <one-to-many class="model.Authority"/>
    </set>

</class>

现在密码按原样保存到数据库,但应该进行编码。

如何将好友applicationContext config 和 DB 查询设为相同的密码编码?

【问题讨论】:

【参考方案1】:

如果您自己选择散列系统,而不是使用已经包含散列密码的现有数据库构建应用程序,那么您应该确保您的散列算法也使用盐。不要只使用简单的摘要。

一个不错的选择是 bcrypt,我们现在通过 BCryptPasswordEncoder(使用 jBCrypt 实现)在 Spring Security 3.1 中直接支持它。这会自动生成一个盐并将其与单个字符串中的哈希值连接起来。

一些数据库内置了对散列的支持(例如Postgres)。否则,您需要在将密码传递给 JDBC 之前自己对密码进行哈希处理:

String password = "plaintextPassword";
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String hashedPassword = passwordEncoder.encode(password);

这就是您在创建用户时对密码进行编码所需要做的一切。

对于身份验证,您可以使用以下内容:

<bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

<bean id="authProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
  <property name="userDetailsService" ref="yourJdbcUserService" />
  <property name="passwordEncoder" ref="encoder" />
</bean>

【讨论】:

关于盐,我知道,这是我安全挑战的下一阶段)) 如果您使用 bcrypt 之类的东西,它会自动为您处理,因此没有任何挑战 :-)。您不必自己处理盐。 @LukeTaylor 你能展示一下它是如何在 applicationContext-security.xml 中配置的吗? 我想知道 BCryptPasswordEncoder 是如何工作的。它是为所有密码生成一个盐还是为每个密码生成一个单独的盐?如果是这样,它将用户盐存储在哪里? BCrypt 不是加密算法,盐存储在同一个字符串中。也许Wikipedia article on Bcrypt 会有所帮助。【参考方案2】:

关于接受的答案的更多解释。希望它可以帮助某人。

在将密码放入数据库之前自己对密码进行哈希处理:

String password = "plaintextPassword";
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String hashedPassword = passwordEncoder.encode(password);

将 BCryptPasswordEncoder bean 添加到您的 security-config.xml

将 passwordEncoder 作为属性添加到 Authentication Provider 类。自动装配它或提供 setter 和 getter 方法。

@AutoWired
private BCryptPasswordEncoder passwordEncoder;

在验证用户登录时获取属性

<bean id="dbAuthenticationProvider" class="mypackage.auth.spring.DBAuthenticationProvider" >
    <property name="dataSource" ref="routingDataSource"></property>
    <property name="passwordEncoder" ref="encoder" />
    <property name="passwordQuery"
        value="select password as password from tbl where username=:username">
    </property> 
</bean>

并且在认证类中匹配两个密码

 new BCryptPasswordEncoder().matches(plainTextPasswdFromUserInput, hashedPasswdFromDb)

【讨论】:

matches 方法是我正在寻找的。​​span> 【参考方案3】:

你可以用一种简单的方式在 applicationContext-security.xml 中做类似的事情

<authentication-manager alias="authenticationManager">
   <authentication-provider>
    <password-encoder ref="encoder"/>
    <jdbc-user-service data-source-ref="dataSource"
       users-by-username-query="
          select username,password, enabled 
          from principal where username=?" 
       authorities-by-username-query="
          select p.username, a.authority from principal p, authority a
          where p.id = a.principal_id and p.username=?" 
    />
   </authentication-provider>
</authentication-manager> 

  <beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

在 Java 中

public static String encodePasswordWithBCrypt(String plainPassword)
    return new BCryptPasswordEncoder().encode(plainPassword);

然后测试一下

System.out.println(encodePasswordWithBCrypt("fsdfd"));

【讨论】:

【参考方案4】:

使用 Spring Security 3.1,试试这个:

<authentication-manager alias="authenticationManager">
    <authentication-provider user-service-ref="service">
        <password-encoder hash="sha"/>
        <jdbc-user-service data-source-ref="dataSource"/>
    </authentication-provider>
</authentication-manager>

<beans:bean id="dataSource" ...>
    ...
</beans:bean>

<beans:bean id="service" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
        <beans:property name="dataSource" ref="dataSource"/>
        ...
</beans:bean>

新增功能:authentication-provider 指向 serviceservice 指向 datasource

编辑:在 Java 中,您必须使用以下代码对密码进行编码:

DigestUtils.sha(request.getParameter("password"));

警告:小心!不要将 SHAMD5 混用!

如果将authentication-providerpassword-encoder 设置为SHA,则需要在Java 中以相同的方式进行编码以保持一致。但是,如果您在 Java 中编码为 MD5,就像您找到的示例一样,请不要忘记将 hash 设置为“md5”。 DigestUtils还提供md5编码器:

DigestUtils.md5(request.getParameter("password"));

【讨论】:

是的,我知道,但你没有问我的问题如何提供,用户密码已编码保存到数据库 好吧,我不知道你说的提供是什么意思,但为了坚持,我使用了DigestUtils。 @sergionni:抱歉,但我不知道 applicationContext 的配置来自动保存编码的密码,正如我所说,我使用了来自 Apache commons 的 DigestUtils。 谢谢您的指点,从来没有听说过摘要。那么,我应该提供摘要以便加密我的密码吗?这个例子:static.springsource.org/spring-security/site/docs/3.0.x/… 啊哈,看来我明白了,我应该在 Java DAO 类中编码我的密码,当我坚持我的 UserDetails 实体时,如下:MessageDigest messageDigest = MessageDigest.getInstance("MD5"); ...这里是完整的解释:***.com/questions/1821082/spring-security-encypt-md5【参考方案5】:

只是使用注释的提示

@Configuration
@EnableWebSecurity
@PropertySource("classpath://configs.properties")
public class SecurityContextConfig extends WebSecurityConfigurerAdapter 


@Autowired
@Qualifier("userDetailsService")
private UserDetailsService userDetailsService;

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception 
    auth.userDetailsService(userDetailsService).passwordEncoder(getPasswordEncoder());



@Bean(name = "passwordEncoder")
public PasswordEncoder getPasswordEncoder()
    return new BCryptPasswordEncoder();     
 


【讨论】:

【参考方案6】:

接受的答案是正确的。 我用 spring 3.1BCrypt 编码算法对其进行了测试。

创建用户时。

PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
userEntity.setPassword(passwordEncoder.encode(userEntity.getPassword()));
userDao.save(userEntity);

当用户登录时,请记住,使用纯密码(未散列)。就像:

Authentication request = new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());
Authentication result = authenticationManager.authenticate(request);
SecurityContextHolder.getContext().setAuthentication(result);

这里是安全配置:

    <bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
        <property name="userDetailsService" ref="userService" />
        <property name="hideUserNotFoundExceptions" value="false" />
        <property name="passwordEncoder" ref="encoder" />
    </bean>

希望它对某人有所帮助!

【讨论】:

【参考方案7】:

对于 3.1.x,此映射不适用于身份验证。 工作方式是:

<beans:bean id='bCryptPasswordEncoder' class='org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder'></beans:bean>

<authentication-manager>
  <authentication-provider user-service-ref="userDetailsService">
          <password-encoder ref="bCryptPasswordEncoder"/>
  </authentication-provider>
</authentication-manager>

【讨论】:

以上是关于Spring Security:DB 和 applicationContext 中的密码编码的主要内容,如果未能解决你的问题,请参考以下文章

带有休眠和散列密码的 Spring Security DB 身份验证?

添加了 Spring Security CORS 过滤器 - 从 DB 检索的日期显示在数值中

添加了 Spring Security CORS 过滤器 - 从 DB 检索的日期显示在数值中

spring-boot Actuator 连同 Spring Security 和 Form Basic Auth

Spring Security - LDAP 身份验证和数据库授权

来自服务的 Grails Spring Security 身份验证