一 前言
团队使用 Bitwarden 管理密码,具有很多协作便利的优点,这里不再赘述。使用 Bitwarden 最担心的问题是安全性,如果这个系统不能保证自身安全性,那么它带来的风险将是巨大的。
Bitwarden 在各个密码管理工具中的评价是非常不错的,很多人使用它搭建自己的个人服务。但是要推广到公司内部使用,仅仅靠好评是不够的,还是要了解它的安全原理才能有足够的信心去推广。
Bitwarden 不同于 1Password 这种离线的服务,它是个 CS 架构,那么如何保证数据传输和服务端的安全性呢?它的核心机制就是:
- 客户端发送的一定是加密或者 Hash 后的数据
- 网络传输过程一定是加密的(HTTPS)
- 数据库存储的一定是加密或者 Hash 后的数据
二 核心概念
在讨论安全机制前,我们需要了解几个核心概念:
2.1 Hash
hash('我爱你') = 4f2016c6b934d55bd7120e5d0e62cce3
这个词你应该不陌生,通常还有 哈希、散列等叫法。
它可以生成某个字符串或者文件的唯一指纹,如果两个字符或者文件的 Hash 值一致,我们就可以认为它们是完全相同的。它还有一个特点:不可逆,仔细想想很容易理解,很大的一个文件, Hash 值就几十个字符,怎么可能逆推出原值?
2.2 加密
encrypt_encode('环球网', secret) = '人民网'
encrypt_decode('人民网', secret) = '环球网'
加密经常被用来数据交换,防止被中间人窃取,比如常见的 HTTPS 就是加密。有些人经常会把加密和 Hash 、编码混淆,有时候可以看到 md5 加密、base64 加密这种说法,其实都是不太严谨的,容易误导。加密有两个比较明显的特征:
- 可逆,加密后的数据一定是能解密的,md5 这种算是 Hash 算法,无法逆推,所以不算是加密。
- 需要密钥才能加解密,base64 只能算是编码算法,不是加密算法。
按照密钥类型,加密算法分为两类:
- 对称加密 ,所谓对称,就是加密解密用的同一个密钥,常见的对称加密算法比如 AES、DES
- 非对称加密,所谓非对称,就是加密解密用不同的密钥,一般称之为公钥和私钥,他们都能用来加密解密,一般公开出去的成为公钥,自己保留不公开的成为私钥。常见的非对称加密算法有 RSA、DSA
2.3 主密码
这个概念属于 Bitwarden 的范畴,密码管理工具可以让你不用再记忆众多繁杂的密码,但是工具本身的主密码是一定要牢记的,它非常重要,因为:
- 一旦被别人获取,您所有受它管理账户密码都将被获取;
- 一旦忘记将永远无法恢复。
所以主密码一定具备两个特征:难忘、强大。而且主密码也是数据加密、Hash 的基石。
2.4 加密密钥
加密密钥就是 2.2 中提到的 secret(加密密钥),我们知道加密一定是需要密钥的,Bitwarden 的数据大部分都是加密传输的,所以也必定需要密钥,它的密钥不止一个,但是都是基于主密码衍生的,所以主密码的重要性可见一斑。
三 Bitwarden 实现
Bitwarden 的实现比较复杂,我这里会简化这个过程,如果有兴趣可以在文章后面的参考链接查看具体实现。
3.1 Master key
首先,Bitwarden 客户端会对主密码和邮箱地址进行 Hash 算法(PBKDF2-SHA256)得到一个值,这个值称为 Master Key。
伪代码:hash(master_password + email) = Master key
3.2 Stretched Master Key
客户端继续对于上一步生成的 Master key 进行 Hash 算法(HKDF),得到另外一个值,称之为 Stretched Master Key。
伪代码:hash(master_key + master_password) = Stretched Master Key。
3.3 保存主密码到数据库
客户端在服务端的认证是通过密码校验的,但是密码在数据库存储一定是经过 Hash 算法处理后的,这样即使数据库被攻破也无法被人获取到密码,最多销毁数据(可以通过备份解决)。
3.1 生成的 Master key 会被发送到 Bitwarden 服务端,服务端在接受到 Master Key 之后,会再进行一次 Hash 算法(HKDF),然后保存到数据库。
伪代码:hash(master_key + 随机字符串) = 保存到数据库的主密码
可以看到整个传输、保存过程都是密码各种 Hash 后的值,完全无法逆推出原始主密码,即使服务端也是无法得知的,在校验密码的时候也不需要使用明文密码,使用 Hash 后的值对比匹配即可。
3.4 Encryption Key
这个就是 2.4 提到的加密密钥,它是在客户端利用 CSPRNG 算法生成的一个随机数,然后客户端利用 3.2 生成的 Stretched Master Key 和这里生成的 Encryption Key 进行加密算法(AES-256)生成 Protected Symmetric Key,然后把 Protected Symmetric Key 发送到服务端保存。
伪代码:
- CSPRNG() = Encryption Key
- encrypt(encryption_key, stretched_master_key) = Protected Symmetric Key
3.5 开始使用
我们在保存站点的密码时,都会用到 3.4 生成的 Encryption Key 进行加密算法,然后保存到数据库。
伪代码:encrypt_encode(original_password_app1, encryption_key) = encrypted_password_app1
获取密码的时候就是反向解密:
伪代码:encrypt_decode(encrypted_password_app1, encryption_key) = original_password_app1
3.6 关于组织共享的实现
Q:个人使用的时候都是使用自己的主密码以及衍生的 key 解密数据,组织成员之间是如何共享密码的呢?
A:组织下的密码都是使用共享的相同 Encryption Key 加密的数据
Q:组织共享的 Encryption Key 是如何保存和读取的?
A:这个 Encryption Key 和普通密码的保存方式是一样的,都是经过加密后保存到各自的数据空间当中的。
Q:这个 Encryption Key 是如何共享给成员的?
A:通过非对称加密算法(RSA-2048)共享的。
四 密码设置
即使 Bitwarden 做了这么多安全方案,但是因为木桶效应,安全性仍然取决于最弱的那一点,其中主密码尤为关键。关于主密码,有如下建议:
- 不要和任何一个站点的密码有重复,撞库十分常见,你在其他站点的密码泄露可能导致连带其他具有重复密码站点的账号也被黑。参考之前 12306 密码泄露事件,其实大部分都是在其他网站泄露的密码撞库获取的。
- 一定要有足够的强度,暴力破解也很常见,有很多弱密码都是被暴力破解获取的,不要低于 8 位,尽可能包含大写字母、小写字母、特殊符号、数字,比如:c2M#3h*y,不要使用:admin123456、password 这种。
- 一定要容易记忆,再强大的密码,如果你记不住也没什么用,尽量用自己容易记住的密码,如果实在不放心,请把密码写到纸条上放到保险箱。
对于在密码管理工具管理下的各个站点密码,推荐使用工具自动生成的强密码。