`

安全密码存储

 
阅读更多

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

 

不应该:

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

在不得已的时候不要自己存储用户的认证信息。我们可以考虑使用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.

  • 流程是这样:

    1. 当增加一个用户的时候,调用generateSalt()生成盐,然后调用getEncryptedPassword(),同时存储盐和密文。再次强调,不要存储明文密码,不要存储明文密码,因为没必要!不要担心将盐和密文存储在同一张表中,上面已经说过了,这个无关紧要。
    2. 当认证用户的时候,从数据库中取出盐和密文,将他们和明文密码同时传给authenticate(),根据返回结果判断是否认证成功。
    3. 当用户修改密码的时候,仍然可以使用原来的盐,只需要调用getEncryptedPassword()方法重新生成密文就可以了。

    参考文档:

 

本人博客已搬家,新地址为:http://yidao620c.github.io/

分享到:
评论

相关推荐

    Java中安全密码存储实践:加密、散列与最佳策略

    在Java中实现安全的密码存储需要考虑多种因素,包括使用强散列函数、盐值、密钥拉伸技术以及安全存储实践。本文将详细介绍如何在Java应用程序中安全地存储密码,包括密码散列、盐值生成、使用现代加密库和遵循安全...

    安全密码的C语言程序

    "安全密码的C语言程序"是一个典型的示例,它涉及到了密码学和C语言编程的基础知识。下面将详细阐述相关知识点。 1. **密码学基础**: - **密码安全**:密码安全是指确保密码不易被破解或预测。通常,安全密码应...

    2024高安全个人密码本程序源码 可生成随机密码/备忘录/二代密码

    除了密码之外,你还可以存储银行账号、信用卡信息、安全问题答案等敏感资料,并同样采用加密方式存储。这样一来,所有重要信息都在一个安全的地方,方便查找,无需担心遗忘或丢失。 最后,提到的二代密码(Two-...

    本地密码储存读取器本地密码储存读取器

    它的工作原理是通过解析操作系统或特定应用程序的密码存储格式,获取到加密后的密码数据,然后通过解密过程,以明文形式展示给用户。 在实际使用中,本地密码储存读取器可以帮助用户检查和审计他们的密码安全状况。...

    商用密码应用安全性评估FAQ

    该步骤包括了密码产品的认证资格、密码算法的选择、密钥生成和分配、密钥存储和管理、密钥使用和保护等方面的评估。 第四部分:物理和环境安全层面的测评对象识别和确定 物理和环境安全层面的测评对象识别和确定是...

    密码与网络安全试验报告

    2. 密钥管理:研究如何安全存储、分发和更新密钥,避免密钥泄露带来的风险。 3. 攻击与防御:分析常见的网络攻击手段,如中间人攻击、拒绝服务攻击和密码破解等,并提出相应的防御措施。 4. 数字签名与证书:解释...

    Go-像Dropbox一样安全地存储你的密码

    下面我们将深入探讨如何使用Go语言来创建一个类似Dropbox的密码存储系统,并关注其中的关键技术和安全实践。 一、Go语言基础 Go(又称Golang)是由Google开发的开源编程语言,以其简洁的语法、高效的性能和内置并发...

    密码存储工具测试版Beta

    标题中的“密码存储工具测试版Beta”表明这是一个用于安全存储密码的应用程序的早期版本,旨在帮助用户管理和保护他们的各种账号密码。在当前的网络安全环境中,密码管理器是至关重要的,因为人们往往需要记住多个...

    华为存储重置控制器管理密码.doc

    请注意,存储系统通常有安全策略限制,不允许过于简单的密码,所以在实际操作中,你需要选择符合安全策略的复杂密码。例如,在示例中,将admin用户的密码重置为123456(仅作演示,实际操作需遵循安全策略)。 密码...

    安全芯片密码检测准则

    ### 安全芯片密码检测准则知识点详述 #### 一、引言 本文档主要针对安全芯片的安全能力等级进行了划分,并明确了适用于不同安全等级的安全芯片密码检测要求。它旨在为安全芯片的设计、测试和评估提供指导,确保这些...

    自用密码储存器

    2. **密码储存安全**:密码储存器的核心在于安全地存储用户密码。通常,不应明文存储密码,而是使用加密算法如bcrypt或scrypt对密码进行哈希处理,然后存储哈希值。在用户登录时,将输入的密码进行同样的哈希处理,...

    密码存储中MD5算法的安全性分析1

    密码存储中MD5算法的安全性分析 摘要:本文分析了哈希算法MD5在密码存储中的安全隐患,并讨论了不同的解决方案,如盐和迭代散列。我们提出了一种新方法,在密码存储中使用MD5,使用外部信息,计算盐和随机密钥在MD5...

    VC++ MD5 加 数据库密码存储!

    这种技术常用于密码存储,因为它可以将原始密码转化为不可逆的形式,增加密码的安全性。 MFC(Microsoft Foundation Classes)是微软提供的C++类库,用于构建Windows应用程序。在这个项目中,MFC可能被用来创建图形...

    高安全等级密码模块安全技术设计.docx

    4. **存储单元**:包括双倍速率内存(DDR SDRAM)和闪存(FLASH),前者用于存储密码模块运行过程中产生的数据,后者则用来存储板载芯片的可执行程序。 5. **环境失效性检测(EFT)单元**:由电压和温度两个部分组成,负责...

    安全密码管家

    《安全密码管家:高效安全管理密码的利器》 在数字化时代,我们的生活充斥着各种在线账号,从社交媒体到银行账户,每个平台都需要一个独特的密码来确保安全性。然而,记忆如此多的复杂密码无疑是一项艰巨的任务。...

    密码编码学与网络安全第八版答案

    同时,也会探讨密码学在网络中的应用,比如电子邮件的安全、在线交易的安全保障以及云存储的数据保护。 "Crypto8e-Solutions"这个文件名表明这是该书第八版的解决方案集。通过研究这些答案,学习者不仅可以检查自己...

    代码中密码存储sskeychain

    在iOS开发中,安全地存储用户敏感信息,如密码、API密钥或证书,是至关重要的。`SSKeychain`是一个流行的开源库,它简化了与iOS内置的安全服务——钥匙串(Keychain)的交互。钥匙串是苹果操作系统提供的一种安全...

    商用密码应用安全性评估量化评估规则.pdf

    - **密钥管理安全**:检查密钥管理的全过程,包括密钥生成、存储、分发、使用、更新和销毁等,以及密码产品的安全性。 - **密码算法/技术安全**:确认使用的密码算法符合法规和标准,密码技术遵循相关国家标准和...

    易语言界面UI EXUI密码管理器

    总的来说,"易语言界面UI EXUI密码管理器"是一款利用易语言和EXUI库开发的安全密码存储解决方案,它结合了易语言的易用性和EXUI的界面设计优势,为用户提供了一个便捷且安全的密码管理工具。使用这样的密码管理器,...

Global site tag (gtag.js) - Google Analytics