扫描代码来添加原始凭证扫描

人气:2785396
访问用户量:3548
笔记经验:3830
总积分:261644
级别:VIP5
搜索本笔记
ta的交流分类
ta的全部笔记
浏览(4818)|(0)
&&交流分类:|笔记分类:
你是否愿意在密码上添加点salt?
如果安全审计人员检查数据库中编码过的密码,在网站安全方面,他可能还会找到一些令其感到担心的地方。让我们查看一下存储的admin和guest用户的用户名和密码值:
7b2e9f54cdff413fcde01f330afe6cd
2ac15cab74cd4eb86c74bb35a4b4
这看起来很安全——加密后的密码与初始的密码看不出有任何相似性。但是如果我们添加一个新的用户,而他碰巧和admin用户拥有同样的密码时,又会怎样呢?
7b2e9f54cdff413fcde01f330afe6cd
现在,注意fakeadmin用户加密过后密码与admin用户完全一致。所以一个黑客如果能够读取到数据库中加密的密码,就能够对已知的密码加密结果和admin账号未知的密码进行对比,并发现它们是一样的。如果黑客能够使用自动化的工具来进行分析,他能够在几个小时内破坏管理员的账号。
【鉴于作者本人使用了一个数据库,它里面的密码使用了完全一致的加密方式,我和工程师团队决定进行一个小的实验并查看明文password的SHA-1加密值。当我们得到password的加密形式并进行数据库查询来查看有多少人使用这个相当不安全的密码。让我们感到非常吃惊的是,这样的人有很多甚至包括组织的一个副总。每个用户都收到了一封邮件提示他们选择难以猜到的密码有什么好处,另外开发人员迅速的使用了一种更安全的密码加密机制。】
请回忆一下我们在第三章中提到的彩虹表技术,恶意的用户如果能够访问到数据库就能使用这个技术来确定用户的密码。这些(以及其它的)黑客技术都是使用了哈希算法的结果都是确定的这一特点——即相同的输入必然会产生相同的输出,所以攻击者如果尝试足够的输入,他们可能会基于已知的输入匹配到未知的输出。
一种通用且高效的方法来添加安全层加密密码就是包含salt(这个单词就是盐的意思,但为了防止直译过来反而不好理解,这里直接使用这个单词——译者注)。Salt是第二个明文组件,它将与前面提到的明文密码一起进行加密以保证使用两个因素来生成(以及进行比较)加密的密码值。选择适当的salt能够保证两个密码不会有相同的编码值,因此可以打消安全审计人员的顾虑,同时能够避免很多常见类型的密码暴力破解技术。
比较好的使用salt的实践不外乎以下的两种类型:
& 使用与用户相关的数据按算法来生成——如,用户创建的时间;
& 随机生成的,并且与用户的密码一起按照某种形式进行存储(明文或者双向加密)。(所谓的双向加密two-way encrypte,指的是加密后还可以进行解密的方式——译者注)
如下图就展现了一个简单的例子,在例子中salt与用户的登录名一致:
&【需要记住的是salt被添加到明文的密码上,所以salt不能进行单向的加密,因为应用要查找用户对应的salt值以完成对用户的认证。】
Spring Security为我们提供了一个接口o.s.s.authentication.dao.SaltSource,它定义了一个方法根据UserDetails来返回salt值,并提供了两个内置的实现:
& SystemWideSaltSource为所有的密码定义了一个静态的salt值。这与不使用salt的密码相比并没有提高多少安全性;
& ReflectionSaltSource使用UserDetails对象的一个bean属性得到用户密码的salt值。
鉴于salt值应该能够根据用户数据得到或者与用户数据一起存储,ReflectionSaltSource作为内置的实现被广泛使用。
配置salted密码
与前面配置简单密码加密的练习类似,添加支持salted密码的功能也需要修改启动代码和DaoAuthenticationProvider。我们可以通过查看以下的图来了解salted密码的流程是如何改变启动和认证的,本书的前面章节中我们见过与之类似的图:
让我们通过配置ReflectionSaltSource实现salt密码,增加密码安全的等级。
声明SaltSource Spring bean
在dogstore-base.xml文件中,增加我们使用的SaltSource实现的bean声明:
java代码:
&bean class=&org.springframework.security.authentication.dao.ReflectionSaltSource& id=&saltSource&&
&property name=&userPropertyToUse& value=&username&/&
我们配置salt source使用了username属性,这只是一个暂时的实现,在后面的练习中将会进行修正。你能否想到这为什么不是一个好的salt值吗?
将SaltSource织入到PasswordEncoder中
我们需要将SaltSource织入到PasswordEncoder中,以使得用户在登录时提供的凭证信息能够在与存储值进行比较前,被适当的salted。这通过在dogstore-security.xml文件中添加一个新的声明来完成:
java代码:
&authentication-manager alias=&authenticationManager&&
&authentication-provider user-service-ref=&jdbcUserService&&
&password-encoder ref=&passwordEncoder&&
&salt-source ref=&saltSource&/&
&/password-encoder&
&/authentication-provider&
&/authentication-manager&
你如果在此时重启应用,你不能登录成功。正如在前面练习中的那样,数据库启动时的密码编码器需要进行修改以包含SaltSource。
增强DatabasePasswordSecurerBean
与UserDetailsService引用类似,我们需要为DatabasePasswordSecurerBean添加对另一个bean的引用(即SaltSource——译者注),这样我们就能够为用户得到合适的密码salt:
java代码:
public class DatabasePasswordSecurerBean extends JdbcDaoSupport {
@Autowired
private PasswordEncoder passwordE
@Autowired
private SaltSource saltS
@Autowired
private UserDetailsService userDetailsS
public void secureDatabase() {
getJdbcTemplate().query(&select username, password from users&,
new RowCallbackHandler(){
public void processRow(ResultSet rs) throws SQLException {
String username = rs.getString(1);
String password = rs.getString(2);
UserDetails user =
userDetailsService.loadUserByUsername(username);
String encodedPassword =
passwordEncoder.encodePassword(password,
saltSource.getSalt(user));
getJdbcTemplate().update(&update users set password = ?
where username = ?&,
encodedPassword,
username);
logger.debug(&Updating password for username:
&+username+& to: &+encodedPassword);
&回忆一下,SaltSource是要依赖UserDetails对象来生成salt值的。在这里,我们没有数据库行对应UserDetails对象,所以需要请求UserDetailsService(我们的CustomJdbcDaoImpl)的SQL查询以根据用户名查找UserDetails。
到这里,我们能够启动应用并正常登录系统了。如果你添加了一个新用户并使用相同的密码(如admin)到启动的数据库脚本中,你会发现为这个用户生成的密码是不一样的,因为我们使用用户名对密码进行了salt。即使恶意用户能够从数据库中访问密码,这也使得密码更加安全了。但是,你可能会想为什么使用用户名不是最安全的可选salt——我们将会在稍后的一个练习中进行介绍。
增强修改密码功能
我们要完成的另外一个很重要的变化是将修改密码功能也使用密码编码器。这与为CustomJdbcDaoImpl添加bean引用一样简单,并需要changePassword做一些代码修改:
java代码:
public class CustomJdbcDaoImpl extends JdbcDaoImpl {
@Autowired
private PasswordEncoder passwordE
@Autowired
private SaltSource saltS
public void changePassword(String username, String password) {
UserDetails user = loadUserByUsername(username);
String encodedPassword = passwordEncoder.encodePassword
(password, saltSource.getSalt(user));
getJdbcTemplate().update(
&UPDATE USERS SET PASSWORD = ? WHERE USERNAME = ?&,
encodedPassword, username);
这里对PasswordEncoder和SaltSource的使用保证了用户的密码在修改时,被适当的salt。比较奇怪的是,JdbcUserDetailsManager并不支持对PasswordEncoder和SaltSource的使用,所以如果你使用JdbcUserDetailsManager作为基础进行个性化,你需要重写一些代码。
配置自定义的salt source
我们在第一次配置密码salt的时候就提到作为密码salt,username是可行的但并不是一个特别合适的选择。原因在于username作为salt完全在用户的控制下。如果用户能够改变他们的用户名,这就使得恶意的用户可以不断的修改自己的用户名——这样就会重新salt他们的密码——从而可能确定如何构建一个伪造的加密密码。
更安全做法是使用UserDetails的一个属性,这个属性是系统确定的,用户不可见也不可以修改。我们会为UserDetails对象添加一个属性,这个属性在用户创立时被随机设置。这个属性将会作为用户的salt。
扩展数据库scheama
我们需要salt要与用户记录一起保存在数据库中,所以要在默认的Spring Security数据库schema文件security-schema.sql中添加一列:
java代码:
create table users(
username varchar_ignorecase(50) not null primary key,
password varchar_ignorecase(50) not null,
enabled boolean not null,
salt varchar_ignorecase(25) not null
接下来,添加启动的salt值到test-users-groups-data.sql脚本中:
java代码:
insert into users(username, password, enabled, salt) values ('admin','
admin',true,CAST(RAND()* AS varchar));
insert into users(username, password, enabled, salt) values ('guest','
guest',true,CAST(RAND()* AS varchar));
要注意的是,需要用这些新的语句替换原有的insert语句。我们选择的salt值基于随机数生成——你选择任何随机salt都是可以的。
修改CustomJdbcDaoImpl UserDetails service配置
与本章前面讲到的自定义数据库模式中的步骤类似,我们需要修改从数据库中查询用户的配置以保证能够获得添加的“salt”列的数据。我们需要修改dogstore-security.xml文件中CustomJdbcDaoImpl的配置:
java代码:
&beans:bean id=&jdbcUserService&
class=&com.packtpub.springsecurity.security.CustomJdbcDaoImpl&&
&beans:property name=&dataSource& ref=&dataSource&/&
&beans:property name=&enableGroups& value=&true&/&
&beans:property name=&enableAuthorities& value=&false&/&
&beans:property name=&usersByUsernameQuery&&
&beans:value&select username,password,enabled,
salt from users where username = ?
&/beans:value&
&/beans:property&
&/beans:bean&
重写基础的UserDetails实现
我们需要一个UserDetails的实现,它包含与用户记录一起存储在数据库中的salt值。对于我们的要求来说,简单重写Spring的标准User类就足够了。要记住的是为salt添加getter个setter方法,这样ReflectionSaltSource密码salter就能够找到正确的属性了。
java代码:
package com.packtpub.springsecurity.
// imports
public class SaltedUser extends User {
public SaltedUser(String username, String password,
boolean enabled,
boolean accountNonExpired, boolean credentialsNonExpired,
boolean accountNonLocked, List&GrantedAuthority&
authorities, String salt) {
super(username, password, enabled,
accountNonExpired, credentialsNonExpired,
accountNonLocked, authorities);
this.salt =
public String getSalt() {
public void setSalt(String salt) {
this.salt =
我们扩展了UserDetails使其包含一个salt域,如果希望在后台存储用户的额外信息其流程是一样的。扩展UserDetails对象与实现自定义的AuthenticationProvider时经常联合使用。我们将在第六章:高级配置和扩展讲解一个这样的例子。&
扩展CustomJdbcDaoImpl功能
我们需要重写JdbcDaoImpl的一些方法,这些方法负责实例化UserDetails对象、设置User的默认值。这发生在从数据库中加载User并复制User到UserDetailsService返回的实例中:
java代码:
public class CustomJdbcDaoImpl extends JdbcDaoImpl {
public void changePassword(String username, String password) {
getJdbcTemplate().update(
&UPDATE USERS SET PASSWORD = ? WHERE USERNAME = ?&
password, username);
protected UserDetails createUserDetails(String username,
UserDetails userFromUserQuery,
List&GrantedAuthority& combinedAuthorities) {
String returnUsername = userFromUserQuery.getUsername();
if (!isUsernameBasedPrimaryKey()) {
returnUsername =
return new SaltedUser(returnUsername,
userFromUserQuery.getPassword(),userFromUserQuery.isEnabled(),
true, true, true, combinedAuthorities,
((SaltedUser) userFromUserQuery).getSalt());
protected List&UserDetails& loadUsersByUsername(String username) {
return getJdbcTemplate().
query(getUsersByUsernameQuery(),
new String[] {username},
new RowMapper&UserDetails&() {
public UserDetails mapRow(ResultSet rs, int rowNum)
throws SQLException {
String username = rs.getString(1);
String password = rs.getString(2);
boolean enabled = rs.getBoolean(3);
String salt = rs.getString(4);
return new SaltedUser(username, password,
enabled, true, true, true,
AuthorityUtils.NO_AUTHORITIES, salt);
createUserDetails和loadUsersByUsername重写了父类的方法——与父类不同的地方在代码列表中已经着重强调出来了。添加了这些变化,你可以重启应用并拥有了更安全、随机的salt密码。你可能会愿意加一些日志和实验,以查看应用运行期间和启动时用户数据加载时的加密数据变化。
要记住的是,尽管在这个例子中说明的是为UserDetails添加一个简单域的实现,这种方式可以作为基础来实现高度个性化的UserDetails对象以满足应用的业务需要。对于JBCP Pets来说,审计人员会对数据库中的安全密码感到很满意——一项任务被完美完成。
感谢 &iteye &&。
他的博客地址:
他的新浪微博:
本书源代码的地址:
相关笔记推荐
精品视频课程推荐
创建规范的XML文档,DTD的作用,并且可以根据要求创建私用的DTD,通过JavaScript解析XML DOM
本视频课程是北京Java私塾原创精品书籍《研磨设计模式》一书的配套学习视频,由《研磨设计模式》的第一作者CC录制
课程目标:全面、系统的掌握GoF设计模式的知识,达到可以在实际项目开发中运用的能力
技术要点:如何实现可配置、如何实现缓存以及缓存的管理、如何实现用缓存来控制多实例的创建、如何实现参数化工厂、 如何实现可扩展工厂、如何实现原型管理器、如何实现Java的静态代理和动态代理、如何实现多线程处理队列请求、 如何实现命令的参数化配置、可撤销的操作、宏命令、队列请求和日志请求、如何实现翻页迭代、如何检测环状结构、 如何实现通用的增删改查、如何模拟工作流来处理流程、如何实现简单又通用的XML读取、如何实现模拟AOP的功能......
系统、完整的学习Spring Data JPA开发的知识。包括:Spring Data JPA入门;JpaRepository基本功能 ;JpaRepository的查询;客户化扩展JpaRepository;Specifications查询。
内容概述:本课程专注于构建:高可扩展性、高性能、大数据量、高并发、分布式的系统架构。
从零开始、全面系统、成体系的软件架构课程,循序渐进的讲述构建上述系统架构所需要的各种技术知识和技能。
技术要点:
1:构建基本的业务功能块,基于Maven+Git+Spring mvc+spring+mybatis+ehcache+mysql+X-gen代码生成
&2:高扩展性的分布式体系架构(基于Nginx+Varnish+Memcache+ActiveMQ)
&3:NoSQL的合理使用和架构优化(基于MongoDB)
&4:分布式文件存储和架构优化(基于MogileFS)
达到能综合使用Struts2+Spring3+Hibernate3+Jbpm4来进行实际项目开发的能力。
包括:ssh和jbpm的整合;数据字典;通用DAO(Spring+Hibernate+泛型+反射+SpEL+模板方法模式);自动生成UUID的加强版;分层开发、SSH联合的基本开发;翻页的示范真实值和表现值,数据参照的实现;文件上传下载;主子表操;登录验证码;登录控制的拦截器
浏览(4818)|(0)
&&交流分类:|笔记分类:
版权所有 Copyright(C) 私塾在线学习网

我要回帖

更多关于 原始凭证扫描 的文章

 

随机推荐