安全密码存储,该怎么做,不该怎么做?

标签: IT技术 安全 密码 | 发表时间:2012-07-12 08:14 | 作者:齐哲
出处:http://blog.jobbole.com

作为软件开发者,其中最重要的一个责任就是保护用户的个人信息,如果用户没有相关的技术知识,他们在使用我们的服务的时候别无选择只能信任我们。可惜的是,当我们调查关于密码的处理的时候,我们发现有各种不同的处理方式,而这些方式有很多都不安全。虽然构建一个完全安全的系统是不可能的,但是我们可以通过一些简单的步骤让我们的密码存储足够安全。


password

不应该:

首先让我们看看当我们构建一个需要用户认证的系统的时候不应该怎么做。

●在不得已的时候不要自己存储用户的认证信息。我们可以考虑使用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的机制避免了暴力破解,我觉得没必要将盐隐藏起来,就跟密文存储在同一个位置。

●不需要额外的库或者工具,这是一个开源的实现,在工作环境中能很方便的使用。

最后让我们来看一个例子

这里使用PBKDF2加密的Java代码,仅仅依赖Java SE 6.

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;

 }

}

流程是这样:

1、当增加一个用户的时候,调用generateSalt()生成盐,然后调用getEncryptedPassword(),同时存储盐和密文。再次强调,不要存储明文密码,不要存储明文密码,因为没必要!不要担心将盐和密文存储在同一张表中,上面已经说过了,这个无关紧要。

2、当认证用户的时候,从数据库中取出盐和密文,将他们和明文密码同时传给authenticate(),根据返回结果判断是否认证成功。

3、当用户修改密码的时候,仍然可以使用原来的盐,只需要调用getEncryptedPassword()方法重新生成密文就可以了。

参考文档:

●NIST: Special Publication 800-132

●维基百科: PBKDF2

●维基百科:  Salt (cryptography)

●维基百科:  Rainbow Table Attacks

原文链接

相关文章

相关 [安全 密码] 推荐:

个人密码安全策略

- owen - 月光博客
  我们现在处于网络时代,时常要登录各种网站、论坛、邮箱、网上银行等等,这些访问常需要帐户+密码的身份认证,因此我们不断地注册用户,就有了数不清的网络帐户和密码. 大多数人为了便于记忆,习惯只用一个常用的网络用户名、邮箱和密码,这是非常危险的. 那么,网上的密码我们应该怎么设置,才能相对安全一些呢.

如何安全地存储密码

- - CSDN博客推荐文章
无论是开发App还是网站,只要有用户登录环节,就会牵涉到如何存储用户的密码的问题. 如果采用的存储密码的技术不够安全,一旦黑客闯入存储密码的数据库,他就能获取用户的密码从而可能给用户带来重大损失. 这种情形任何公司都不希望发生在自己身上,因此选择安全地存储密码的策略显得十分必要. 不一定非要自己存储用户的密码.

你的密码安全吗?来用 GPU 暴力破解密码

- 小筱 - Engadget 中国版
[作者:Fox Mulder]. 这是一个相当有趣的小工具,能够让你用 GPU 暴力破解密码,从新闻中的描述,Radeon HD 5770 每秒可以进行33亿次的运算. Radeon HD 5770能够在一秒钟之内破解一个五位数的密码 "fjR8n" ....... 引用来源 | 引用来源 | 此文章网址 | 转寄此文章 | 回应.

【为何信用卡设了密码更安全及不设密码如何做更安全】

- - 非正常人类研究中心 – Mtime时光网
《无密码盗刷不赔付 银行章程隐藏霸王条款》http://finance..cn/money/bank/credit/20120419/082511864442.shtml. 《银行卡遭克隆盗刷法院判银行赔偿》  http://bank.hexun.com/2012-07-06/143264473.html.

你的密码安全吗?小心那些隐藏的陷阱

- 疯擎羊 - 死理性派 - 果壳网
美国国家安全局(NSA)为了破译恐怖组织的密码以挫败其阴谋,斥巨资建造了一台可以破解一切密码的机器:万能解密机. 这是美国作家丹•布朗在其小说《数字城堡》中虚构的情节. 以人类今日之科技实力,打造这样一台无坚不摧的“神器”还只是个遥远的梦想,但如何在网络社会中保护自己的个人隐私一直是个现实的问题. 20多年来,现代人已经掌握了“数字城堡”——密码的构造方法,自认为可以高枕无忧,但事实远非如此.

安全密码存储,该怎么做,不该怎么做?

- - 博客 - 伯乐在线
作为软件开发者,其中最重要的一个责任就是保护用户的个人信息,如果用户没有相关的技术知识,他们在使用我们的服务的时候别无选择只能信任我们. 可惜的是,当我们调查关于密码的处理的时候,我们发现有各种不同的处理方式,而这些方式有很多都不安全. 虽然构建一个完全安全的系统是不可能的,但是我们可以通过一些简单的步骤让我们的密码存储足够安全.

银行方面证实信用卡无密码更安全

- - 国内要闻-新浪新闻
  本报讯 (记者苏曼丽)近日有自称银行工作人员的网友爆料,信用卡不设置密码更安全. 记者昨天从银行方面证实了这种说法,设置密码的信用卡被盗刷由持卡人承担全部责任,不设密码则有机会让银行承担部分责任. 但调查发现,事实上要获得银行的赔偿也并非易事.

[技术分享]用户密码安全存储建议

- - CSDN博客推荐文章
       安全小测验:存储机密信息最安全的办法是什么.               a)利用 256 位密钥的强对称加密算法(例如 AES)进行加密.               b)利用 4096 位密钥的非对称强加密算法(例如 RSA)进行加密.               c)利用平台内置的加密系统进行加密,例如 Windows 的数据保护 API (DPAPI).

你的密码安全吗?小心那些隐藏的陷阱

- tossking - 科学松鼠会
美国国家安全局(NSA)为了破译恐怖组织的密码以挫败其阴谋,斥巨资建造了一台可以破解一切密码的机器:万能解密机. 这是美国作家丹•布朗在其小说《数字城堡》中虚构的情节. 以人类今日之科技实力,打造这样一台无坚不摧的“神器”还只是个遥远的梦想,但如何在网络社会中保护自己的个人隐私一直是个现实的问题. 20多年来,现代人已经掌握了“数字城堡”——密码的构造方法,自认为可以高枕无忧,但事实远非如此.