作为软件开发者,其中最重要的一个责任就是保护用户的个人信息,如果用户没有相关的技术知识,他们在使用我们的服务的时候别无选择只能信任我们。可惜的是,当我们调查关于密码的处理的时候,我们发现有各种不同的处理方式,而这些方式有很多都不安全。虽然构建一个完全安全的系统是不可能的,但是我们可以通过一些简单的步骤让我们的密码存储足够安全。
不应该:
首先让我们看看当我们构建一个需要用户认证的系统的时候不应该怎么做。
在不得已的时候不要自己存储用户的认证信息。我们可以考虑使用OAuth的提供者例如Google、Facebook。如果构建企业内部的应用,可以考虑使用已有的内部认证服务,例如企业LDAP或者Kerberos服务。无论是面向公众的还是面向内部的应用程序,用户会喜欢这个应用,因为他不需要多记住一个ID和密码,同时也少了受黑客攻击的危险。
如果你必须存储认证信息,不要存储明文密码。这句话就不解释了。
不要使用可逆的加密方式,除非你在某种状况下真的需要查出来明文密码。因为在进行用户身份验证的时候并不需要明文密码去比对。
不要使用过时的哈希算法,例如md5,在现在这个社会,有人可以通过构建一个超大的md5库来反向的查询出明文。换句话说md5哈希基本上没什么用,你要是不相信可以拿这个密文(569a70c2ccd0ac41c9d1637afe8cd932)去 http://www.md5hacker.com/ 上看看,几秒内就可以查出明文了。
应该:
说完了不应该做的,就说说应该做的:
选择一个单向(不可逆)的加密算法。就像我上面说的一样,仅仅存储加密后的用户密码,用户每次认证就使用相同的算法加密后比对就可以了。
选择一个你的应用可以承受的最慢的加密算法。任何现代的加密算法都支持在加密的时候接受参数从而使加密时间延长,而解密也自然就更难。(例如PBKDF2,可以通过制定迭代的次数来实现)。为什么慢了好呢?因为用户几乎不会关心他为了认证自己的账户额外的花销了100ms。但是黑客就不同了,当他进行上10亿次的尝试计算的时候,就有他喝一壶的了。
选择一个流行的算法。美国国家标准与技术研究院推荐使用PBKDF2加密密码。
PBKDF2
在我给出示例代码前,让我们先来看看PBKDF2算法。
美国国家标准与技术研究院推荐。
可以通过调整key来扩展,从而避免暴力破解。通过key扩展的基本思路是,在将密码哈希后,再使用key加上哈希值再使用相同的算法进行多次的哈希。如果黑客尝试去破解的话,他会因此多花费几十亿次计算的时间。前面提到过,越慢越好,PBKDF2可以通过指定迭代次数,你想让他多慢,他就有多慢。
通过加盐的方式预防彩虹表的破解方式。盐是一个添加到用户的密码哈希过程中的一段随机序列。这个机制能够防止通过预先计算结果的彩虹表破解。每个用户都有自己的盐,这样的结果就是即使用户的密码相同,通过加盐后哈希值也将不同。然而,在将盐与密文存储的位置上有很多矛盾的地方,有的时候将两者存在一起比较方便,有的时候为了安全考虑又不得不将两者分开存储。由于PBKDF2算法通过key的机制避免了暴力破解,我觉得没必要将盐隐藏起来,就跟密文存储在同一个位置。
不需要额外的库或者工具,这是一个开源的实现,在工作环境中能很方便的使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Arrays;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
public class PasswordEncryptionService {
public boolean authenticate(String attemptedPassword, byte [] encryptedPassword, byte [] salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
// Encrypt the clear-text password using the same salt that was used to
// encrypt the original password
byte [] encryptedAttemptedPassword = getEncryptedPassword(attemptedPassword, salt);
// Authentication succeeds if encrypted password that the user entered
// is equal to the stored hash
return Arrays.equals(encryptedPassword, encryptedAttemptedPassword);
}
public byte [] getEncryptedPassword(String password, byte [] salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
// PBKDF2 with SHA-1 as the hashing algorithm. Note that the NIST
// specifically names SHA-1 as an acceptable hashing algorithm for PBKDF2
String algorithm = "PBKDF2WithHmacSHA1" ;
// SHA-1 generates 160 bit hashes, so that's what makes sense here
int derivedKeyLength = 160 ;
// Pick an iteration count that works for you. The NIST recommends at
// least 1,000 iterations:
// http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf
// iOS 4.x reportedly uses 10,000:
// http://blog.crackpassword.com/2010/09/smartphone-forensics-cracking-blackberry-backup-passwords/
int iterations = 20000 ;
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, derivedKeyLength);
SecretKeyFactory f = SecretKeyFactory.getInstance(algorithm);
return f.generateSecret(spec).getEncoded();
}
public byte [] generateSalt() throws NoSuchAlgorithmException {
// VERY important to use SecureRandom instead of just Random
SecureRandom random = SecureRandom.getInstance( "SHA1PRNG" );
// Generate a 8 byte (64 bit) salt as recommended by RSA PKCS5
byte [] salt = new byte [ 8 ];
random.nextBytes(salt);
return salt;
}
} |
最后让我们来看一个例子
这里使用PBKDF2加密的Java代码,仅仅依赖Java SE 6.
-
流程是这样:
- 当增加一个用户的时候,调用generateSalt()生成盐,然后调用getEncryptedPassword(),同时存储盐和密文。再次强调,不要存储明文密码,不要存储明文密码,因为没必要!不要担心将盐和密文存储在同一张表中,上面已经说过了,这个无关紧要。
- 当认证用户的时候,从数据库中取出盐和密文,将他们和明文密码同时传给authenticate(),根据返回结果判断是否认证成功。
- 当用户修改密码的时候,仍然可以使用原来的盐,只需要调用getEncryptedPassword()方法重新生成密文就可以了。
参考文档:
- NIST:Special Publication 800-132
- 维基百科:PBKDF2
- 维基百科: Salt (cryptography)
- 维基百科: Rainbow Table Attacks
本人博客已搬家,新地址为:http://yidao620c.github.io/
相关推荐
6.用可还原的加密来存储密码:禁用;在桌面上按下Win键+R键,打开“运行”窗口:输入:gpedit.msc;4、打开“组策略”窗口 ;在“组策略”窗口中依次选择“计算机配置”>“Windows设置”>“安全设置”>“账户策略”>...
Heimdall-安全密码哈希 该库实现了安全且可升级的密码哈希机制。 有关详细信息,请参。为什么不只使用PBKDF2,scrypt,bcrypt等? 实际上,该库使用(某些)算法。 但这使您更轻松:无需担心迭代,盐生成等问题。 ...
像Dropbox一样安全地存储你的密码
secure-password 使密码存储更安全
即使对于较 高的安全层次,你还可以结合这两种方式。密码自身可以被进行组织并根据多种不同的排序/查找条件来表示、分组,或者进行层次式的安排。你可以导出密码列表,从CSV文件中导入密码,在程序的两个实例中传输...
KeePass 是一款管理密码的开源的免费软件,KeePass 将密码存储为一个数据库,而这个数据库由一个主密码或密码文件锁住,也就是说我们只需要记住一个主密码,或使用一个密码文件,就可以解开这个数据库,就可以获得...
USB安全存储专家(USSE)2005破解版(Build 308)
KeePass 是一款管理密码的开源的免费软件,KeePass 将密码存储为一个数据库,而这个数据库由一个主密码或密码文件锁住,也就是说我们只需要记住一个主密码,或使用一个密码文件,就可以解开这个数据库,就可以获得...
然后在安全设置中“启用指纹识别”,然后对没有指纹的USB存储设备设置过滤条件(阻止/只读)。 4, 内部保密功能,使你的USB存储设备不能正常使用,这样当你的U盘等丢失也不用担心里面的数据泄漏。 内部标志的功能是...
KeePass Password Safe 就是专门为了解决人类记不得众多密码的问题所产生的,它包含了一个强大的密码产生引擎与加密储存机能,能够提供一个安全的密码储存空间。当你开始使用 KeePass Password Safe 时,要先决定一...
KeePass 是一款管理密码的开源的免费软件,KeePass 将密码存储为一个数据库,而这个数据库由一个主密码或密码文件锁住,也就是说我们只需要记住一个主密码,或使用一个密码文件,就可以解开这个数据库,就可以获得...
KeePass是一个密码管理软件,专门为了解决人类记不得众多密码的问题所产生的,它包含了一个强大的密码产生引擎与加密储存机能,能够提供一个安全的密码储存空间。当你开始使用 KeePass Password Safe 时,要先决定一...
软件名:USB安全存储专家(USSE)2005(Build 308)破解版 简介: USB安全存储专家(以下简称USSE)是一套计算机USB端口屏蔽、USB端口控制、实时监视、实时监控于一体的计算机网络安全控制系统。它通过USB存储协议...
密码存储中MD5算法的安全性分析1
云计算中基于动态虚拟化电子流密码的安全存储.pdf
密码存储 3. 密码使用 在寻找好的密码解决方案时,我也做了调研,试用了大部分的现有密码管理软件,这些软件都是通过一个主密钥来登录到软件,然后将众多密码保存在软件里,虽然说是加密存储,但是心里感觉还是...
使用混合密码术存储文件的安全平台.zip
密码备忘录源码(密码本地存储软件源码)。之前用过几款同类手机端的APP,网络储存的存在安全隐患。PC端的也没找到适合的开源,不开源也心里总不敢用于是自己操刀干了一个PC本地数据库储存版。数据库用的易语言EDB...
【软件特点】: 1、有别于隐藏文件夹之类的伪加密,“文件密码箱”通过在磁盘上建立一个加密虚拟存储层——密码箱,实现文件的透明加密和安全隔离存储,并通过专门的虚拟文件系统对密码箱中内容进行管理。...
软件名:USB安全存储专家(USSE)2005(Build 308)破解版 简介: USB安全存储专家(以下简称USSE)是一套计算机USB端口屏蔽、 USB端口控制、实时监视、实时监控于一体的计算机网络安全控制系 统。它通过USB...