你的密码真的安全么?

主页

引言

微软(MicroSoft)竟然在近三年的时间里泄露了高达38TB的内部数据,包括密钥、员工个人备份和三万条内部消息,而原因竟然是一个微不足道的设置失误!
9月18日,云安全公司Wiz爆出微软AI研究团队在Github上的开源数据发布中的惊人漏洞。事件起因是微软的AI开发人员在Github上提供了一个链接,用于下载开源代码和AI模型,但因为一个过于宽松的共享访问签名(SAS)令牌,链接不仅授权任何人访问存储账户的全部内容,而且权限竟然是“完全控制”,让任何人都可以删除、替换或添加恶意内容!

image

这次泄露的数据包括两名微软员工的个人备份、用于微软服务的密码和秘钥,以及来自359名微软员工的三万条内部群聊消息。令人震惊的是,这个泄露问题已经存在自2020年,直到今年6月Wiz才揭示了这一严重漏洞,微软才在两天后撤销了问题的SAS令牌。这起事件也再次引发了对数据安全的关切

数据安全是一个系统性的工程,涉及到数据生命周期的各个环节、以及用户的数据安全保护意识

用户密码作为一种特殊的用户数据,一旦泄露可能对用户隐私信息、用户财产带来重大损失。
在《2FA双因素认证 - 原理和应用》一文中我们已简单介绍过用用户密码, 但着重介绍了第二个因素。本文我们将从”用户密码攻击模型“开始,并使用技术手段对”用户密码生命周期“的安全保护进行展开介绍。

本文内容组织:

  • 用户密码生命周期
  • 用户密码攻击模型
  • 用户密码安全保护&实践
  • 参考资料

用户密码生命周期

用户密码(或口令) 作为用户登录网站、主机、手机APP的用户凭证被广泛使用,如:

  • 用户需要登录淘宝App,才能购物
  • 用户需要登录微信,才能与好友进行聊天、发朋友圈
  • 开发&运维人员需要通过密码才能登录到远程主机,进行服务运维等。

在以上场景中,用户都需要输入自己的密码登录服务,才能进行敏感操作。而密码泄露将会导致攻击者伪装成合法用户,进而窃取用户敏感信息、盗走用户个人财产。因此保证用户密码的安全至关重要。

要保护用户密码,我们首先要了解用户密码的整个生命周期,如下:
image

用户密码生命周期主要包含:

  • 生成密码、使用密码、修改密码、删除密码(用户操作)
  • 重置密码(管理员操作)
  • 存储密码、校验密码(服务端程序自动执行)

在业务上一般涉及“注册”和“登录”两个流程:

  • 用户注册
    image

    用户首次使用APP或首次访问网站时,一般需要注册,注册过程中需要用户设置密码。这里涉及到用户密码的安全生成安全传输安全存储

    注:在企业级应用中,用户注册可能由管理员协助完成,用户密码由管理员提供给普通用户

  • 用户登录
    image
    用户注册后,需要进行登录才能正常进行APP或网站操作。这里涉及到用户密码的安全传输校验

注:由于修改密码、重置密码比较简单,且与生成密码和存储密码类似,后文不做过多赘述;同时删除密码场景较少,也不做赘述。

用户密码攻击模型

针对用户密码生命周期,密码安全主要涉及以下几个方面:

  • 密码生成
  • 密码传输
  • 密码存储
  • 密码校验

在介绍具体密码安全措施前,我们首先要了解用户密码攻击模型,只有了解了该模型,我们才知道我们要面对的攻击者到底是谁,也才能对症下药的制定防护措施。用户密码攻击模型,如下:
image

  • 【01】暴力破解者。暴力破解者一般指攻击者通过不断尝试密码进行登录,从而找到合法用户密码。此类方式一般配合社会工程学,在已知用户部分信息的前提下来实施。
  • 【02】网络窃听者。在用户登录和注册时,都需要将密码传输给服务端,在传输过程中网络窃听者可以使用网络嗅探工具,如wireshark获取网络数据,从而窃取用户密码
  • 【03】内部泄密者。当服务端收到用户密码时,内部泄密者可以通过服务日志或直接从数据库窃取用户密码,并将密码私下售卖给攻击者。

易受攻击模型(简单密码&明文传输&明文存储):

image

安全模型(复杂密码&安全通道&密文存储):

image

用户密码安全保护&实践

密码生成安全

密码生成安全一般用来防止暴力破解者, 生成的密码越复杂(长度越长,字符种类越多等),攻击者暴力破解的可能性越小。常见的密码生成安全规则:

  • 长度: 密码应该足够长,一般至少包含 12 个字符。较长的密码更难被破解。
  • 复杂性: 密码应该包含不同类型的字符,包括大写字母、小写字母、数字和特殊符号(如!、@、#、$等)。这样的密码更难以猜测或破解。
  • 避免常见单词: 避免使用常见的词语、短语、名字或日期作为密码。犯罪分子通常会使用字典攻击来尝试这些常见的密码。
  • 不要使用个人信息: 避免使用与您相关的个人信息,如生日、家庭地址、电话号码等。这些信息容易被猜测或通过社交工程攻击获取。
  • 不要重复密码: 不要在多个账户中重复使用相同的密码。如果一个账户被破解,其他账户也会受到威胁。

假设密码生成规则为:至少包含数字、大写字母、小写字母以及特殊字符种类中的minClasses个,并且密码长度为length,则密码生成的代码,如下:

// 生成指定长度的用户密码
func GenerateRandomPassword(length int, minClasses int) (string, error) {
	// 定义密码字符集
	digits := "0123456789"
	upperLetters := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	lowerLetters := "abcdefghijklmnopqrstuvwxyz"
	specialChars := "!@#$%^&*()_+[]{}|;:,.<>?`~"

	charSets := []string{digits, upperLetters, lowerLetters, specialChars}
	selectedSets := make([]byte, 0, minClasses)

	// 设置随机数种子
	rand.Seed(time.Now().UnixNano())

	// 从每个字符集中随机选择一个字符
	charSetsUsedFlag := make(map[int]bool)
	for i := 0; i < minClasses; i++ {
		charSetsIndex := rand.Intn(len(charSets))
		if charSetsUsedFlag[charSetsIndex] {
			i--
			continue
		} else {
			charSetsUsedFlag[charSetsIndex] = true
		}
		charSet := charSets[charSetsIndex]
		selectedSets = append(selectedSets, charSet[rand.Intn(len(charSet))])
	}
	
	// 剩余字符随机选择
	for i := 0; i < length-minClasses; i++ {
		charSet := charSets[rand.Intn(len(charSets))]
		selectedSets = append(selectedSets, charSet[rand.Intn(len(charSet))])
	}

	return string(selectedSets), nil
}

密码传输安全

密码传输安全用来保护通信数据的安全,防止密码在从客户端 -> 服务端过程中被网络窃听者获取。传输安全比较成熟,一般借助TLS来实现。TLS原理&实践我们在之前的文章已经介绍过,这里不在赘述。
详情见:

密码存储安全&校验

密码存储安全一般用来保护用户密码不被网站提供者内部人员窃取,一般的数据安全是很难做到防护内部人员的,因为数据已经存储在服务端,网站提供网络服务必须使用明文数据,但是密码作为一种特殊数据,可以做到在不泄露明文密码的前提下,实现对用户身份的校验
相信很多人已经听过类似技术或算法,我们通常称作为密码哈希函数。如:pbkdf2scryptbcrypt等。

密码哈希函数 用途 安全性 广泛性 性能 易用性
pbkdf2 密钥派生/密码保护 相对较低。PBKDF2的安全性依赖于迭代次数,如果迭代次数设置得不够高,它容易受到暴力破解攻击 相对广泛应用,因为它是一个老牌的密码哈希函数 相对较高,因为它使用的是标准的哈希算法,如SHA-256 易于使用和实现
bcrypt 密钥保护 高。bcrypt使用了适应性哈希算法,它自动增加计算时间,使得暴力破解更加困难 在 Web 开发中相当常见 相对较低,因为它被设计成计算缓慢,以防止暴力破解 易于使用,但需要正确配置工作因子以平衡性能和安全性
scrypt 密钥派生/密码保护 较高。scrypt类似于bcrypt,但比其更耗费内存,增加了抵抗硬件攻击的能力 逐渐变得更流行,尤其在密码管理和身份验证中 较低,因为它需要大量的内存 相对较易使用,但也需要正确配置参数以平衡性能和安全性
argon2 密钥派生/密码保护 最高。Argon2是最新的密码哈希函数,被认为是目前最安全的选项,它抵抗各种攻击,包括时间攻击和侧信道攻击 逐渐被接受,尤其在密码学领域中,但在一些旧系统中可能不常见 相对较低,因为它旨在增加计算时间 相对较易使用,但需要正确配置参数以平衡性能和安全性

注意:

  • 除了bcrypt外,其他密码哈希函数,也用于基于密码的密钥派生,派生出来的密钥,一般用于数据加密。(密钥派生不是本文关注的内容)
  • 密码哈希函数在生成密文密码过程中,使用了哈希函数,由于哈希函数具有不可逆性,内部人员无法通过密文密码还原用户明文密码,因此即使密文密码泄露,也不会对用户其他信息(非本网站数据)进行非法访问。(据不完全统计,绝大部分用户会在多个APP或网站上使用相同的密码)

使用demo程序生成随机密码&校验

由于密码哈希函数在使用过程中,基本都需要配置各种参数,并且这些参数需要在服务端进行保存,以便于进行后续用户登录验证,在实现上并不是特别灵活。

因此本人在业余时间通过github开源了集成所有主流密码哈希函数并进行了易用性封装的实现代码(golang语言),代码仓库为github.com/warm3snow/practical-crypto

下面我们使用该仓库进行demo演示:

  1. 打开终端并执行:
# 下载代码库&切换到工作目录
➜ git clone https://github.com/warm3snow/practical-crypto.git
➜ cd practical-crypto/kdf
  1. 查看代码结构
➜  kdf git:(master) ✗ tree                        
.
├── argon2impl  	# argon2的kdf接口实现
│   ├── argon2impl.go
│   └── argon2impl_test.go
├── bcryptimpl		# bcrypt的kdf接口实现
│   ├── bcryptimpl.go
│   └── bcryptimpl_test.go
├── kdf.go		# 密码哈希函数通用接口
├── kdf_test.go		# kdf单元测试
├── pbkdf2impl		# pbkdf2的kdf接口实现
│   ├── pbkdf2impl.go
│   └── pbkdf2impl_test.go
└── scryptimpl		# scrypt的kdf接口实现
    ├── scryptimpl.go
    └── scryptimpl_test.go
  1. 执行测试程序
➜  kdf git:(master) ✗ go test -test.run=TestKDF
明文密码: 0%B+&[J]
密文密码: $bcrypt$2a$10$EBXiMyoZeuO/POjuXHNAyeIPRanE0YaJyLrEddTFbywlNiCXDPLrq
验证密文密码: true
密文密码: $pbkdf2$GClZdx8hyy3iqC4hQZkCTw==$zATpvtegzY0Q49te5vmpSgiJtQ+6B4Ub55oQbYaZaOI=$4096:32
验证密文密码: true
密文密码: $scrypt$rQRKOR9lOxcDHLP+G97Uew==$VtS1Vx2ayCbx6lPhqmrRGDbi/ILceonDR+Kp+F3lJ5Q=$32768:8:1:32
验证密文密码: true
密文密码: $argon2$TQ6r/snRqrrfbC4r352S5g==$XkH5p9EqEq10IQomLhzeu8T6dPN4O8vUu0fO3BmjgBc=$3:32768:4:32
验证密文密码: true
PASS
ok      github.com/warm3snow/practical-crypto/kdf       1.295s

从执行结果上看:

  • 测试程序首先生成了明文密码0%B+&[J],该密码生成规则请参考本章节#密码生成安全
  • 基于明文密码密码哈希函数,我们生成了密文密码, 格式为$<kdfName>$<salt>$<key>$<others>,其中kdfName表示密码哈希函数;salt表示随机盐值,用于增强安全性,抵御彩虹攻击;key: 表示密文密码;others: 密码哈希函数需要用到的其他安全参数,不同算法使用的参数不同、参数个数也可能不一样,多个参数使用:隔开
  • 所有的密码校验全部成功

总结

本文主要介绍了用户密码在生成、使用、传输和存储整个生命周期的安全风险,并针对不同环节提出了应对措施&最佳实践。安全是个大问题,不仅需要通过技术来降低风险,也需要各个环节参与者能够切实考虑到安全风险。 最近微软数据泄漏事件表明,即使是这种国际化大公司也有做的不到位的地方,因此在程序编码、服务搭建以及人员安全培训上都需要不断加强,本文仅从用户密码角度进行了探讨,而密码安全是数据安全的重要一环,也需要重视,希望读着通过本文可以有个初步的认识。

注:本文未对kdf接口定义&实现进行详细介绍,感兴趣的读着可以参考开源代码。

参考资料

posted @ 2023-09-20 17:25  warm3snow  阅读(28)  评论(0编辑  收藏  举报