加密技术的未来:从服务端密码存储到⽤户数据加密⽅案
本⽂主要讲常见场景的数据加密⽅案,以及对未来加密技术的展望,先看⼏条新闻:
Facebook 明⽂存储⽤户密码:
Hundreds of millions of Facebook users had their account passwords stored in plain text and searchable by thousands of
Facebook employees — in some cases going back to 2012, KrebsOnSecurity has learned. Facebook says an ongoing
investigation has so far found no indication that employees have abused access to this data.
早在 2012 年,Facebook 明⽂存储数亿⽤户的账户密码,成千上万的 Facebook 的员⼯可以随意进⾏搜索......
原⽂:
CSDN 600万⽤户账号密码泄露:
北京时间12⽉21⽇晚间消息,中国开发者技术在线社区CSDN今晚发表声明,就“600万⽤户账号密码泄露”⼀事公开道歉,承认部分⽤户账号⾯临风险,将临时关闭⽤户登录,并要求“2009年4⽉以前注册的帐号,且2010年9⽉之后没有修改过密码”的⽤户⽴即修改密码。
原⽂:
为什么不能明⽂存储密码
很多新⼿程序员都是这样存储密码的:
username phone password
⼩明188********asd123456
⼤明17777777777123abc!@#
为什么这样做是不安全的?
⾸先,如果遇到数据泄露事件,明⽂密码直接将⽤户隐私暴露在空中,任何⼈可以登陆暴露密码的账号,随意更改。其次,即使不会泄露,内部员⼯也可以轻易访问⽤户的明⽂密码,当公司上了规模,
你⽆法保证公司内部没有坏⼈,他们是否会搜索某些⽤户的密码,侵犯⽤户隐私。所以明⽂存储密码是绝对不安全的。
即使你⽤了这样的密码:ppnn13%dkstFeb.1st(娉娉袅袅⼗三余,⾖蔻梢头⼆⽉初),明⽂存储,安全性也是⽊有的。
再复杂的密码,也敌不过CSDN的明⽂
来⾃知乎⽤户:
题外话:
密码含义
FLZX3000cY4yhx9day飞流直下三千尺,疑似银河下九天
锦荣微博hanshansi.location()!∈[gusucity]姑苏城外寒⼭寺
hold?fish:palm鱼和熊掌不可兼得
Tree_0f0=sprintf("2_Bird_ff0/a")两个黄鹂鸣翠柳
csbt34.ydhl12s池上碧苔三四点,叶底黄鹂⼀两声
for_$n(@ RenSheng)_$n+="die"⼈⽣⾃古谁⽆死
while(1)Ape1Cry&&Ape2Cry两岸猿声啼不住
doWhile(1){LeavesFly();YangtzeRiverFlows()};⽆边落⽊萧萧下,不尽长江滚滚来
dig?F*ckDang5锄⽲⽇当午
如何存储 & 检查密码
既然密码不能明⽂存储,那怎么存储才是安全的?我如何检查⽤户输⼊的密码是正确的?
存储相关信息⽤于校验是必须的,有没有⼀种机制能够只保存密码的部分信息,也能⽤于密码校验?这样即使数据库泄露,攻击者也⽆法通过这些信息反推⽤户的密码,进⽽保护⽤户账号安全。
(hash function)可以解决这个问题。
潘虹的老公哈希函数是单向不可逆的,从上图很好理解,经过 hash 函数都会被丢弃⼀部分信息,就如同这个算法:
算法:存储⽤户名时丢弃⽤户姓⽒然后随机打乱顺序,输⼊赵⽇天,输出天⽇。
即使知道这个算法和天⽇这个数据,也⽆法推断出赵⽇天这个名字,因为部分信息丢失了。
$$
h = hash(p)
$$
h 为最终存储到数据库的值,p 为⽤户原始密码,在⽤户登陆时,输⼊密码 p1,我们通过计算 $h_1 = hash(p_1)$,判断 h1 是否与数据库中的记录 h 相同,确定⽤户输⼊的密码是否正确。
所有哈希函数都有⼀个性质:如果两个 h 值是不⼀致的,那么输⼊ p 值也不⼀样(单向散列函数),但另⼀⽅⾯输⼊和输出并⾮⼀⼀对应的关系,⽐如存在不同的 h 值,使得经过 hash 函数计算后的 p 值是⼀样的。
哈希函数就安全了吗?
没有,由于上述哈希函数的性质,如果两个⽤户都⽤了123456abc,这样的密码,那么数据库存储的
h 值都是⼀样的,⽽且不同密码可能计算出来的 h 值是⼀样的(碰撞攻击),那么攻击者就可以根据 hash 函数,暴⼒计算所有可能性,做成⼀张表格,这样拿到 h 值的时候就可以推断出密码是 123456abc 了。这种做法叫攻击。
⽐如以前常⽤的哈希函数,由于计算⼒逐步增强,现在已经是不安全的了:
MD5 1996年后被证实存在弱点,可以被加以破解,对于需要⾼度安全性的资料,专家⼀般建议改⽤其他算法,如SHA-2。2004年,证实MD5算法⽆法防⽌碰撞攻击,因此不适⽤于安全性认证,如SSL公开密钥认证或是数字签名等⽤途
安全加固:加盐
对付彩虹表可以⽤ Sated Hash 的⽅式,⽐如对于每个⽤户密码存储时都记录⼀个随机的 salt 值(盐值),⽤这个盐值和密码 p,计算出 h 值:
$$
h = hash(salt, p)
$$
数据库同样存储了 salt 值和 h 值,这样攻击者想获取⼀个⽤户的密码,就得建⽴⼀个对应的彩虹表,增⼤攻击者的成本。
但即使这样,使⽤ SHA-2 再加盐也不是安全的,因为计算⼒逐年提升,攻击成本下降,有财⼒的攻击集团还是能够建⽴这些彩虹表,进⽽窃取⽤户密码。
安全加固:提⾼计算强度
加盐的⽅式只是多了独⽴的彩虹表,如果我们可以利⽤硬件控制每次 hash 计算的时间⽐如1秒,且⽆论⽤什么机器,什么⾼性能的CPU计算,每次都要1秒的时间,攻击者要计算这个彩虹表,1000万个组合就得115天(hash 空间远远超过 1000万),那这种⽅式就很难破解了。
是⼀个由Niels Provos以及David Mazières根据Blowfish加密算法所设计的密码散列函数,于1999年在USENIX中展⽰[1]。实现中bcrypt会使⽤⼀个加盐的流程以防御彩虹表攻击,同时bcrypt还是适应性函数,它可以借由增加迭代之次数来抵御⽇益增进的电脑运算能⼒透过暴⼒法破解。
除了对您的数据进⾏加密,默认情况下,bcrypt在删除数据之前将使⽤随机数据三次覆盖原始输⼊⽂件,以阻挠可能会获得您的计算机数据的⼈恢复数据的尝试。如果您不想使⽤此功能,可设置禁⽤此功能。
除了 bcrypt 这种调整计算强度,抵御⽇益增长的CPU 计算⼒带来攻击风险的算法,scrypt 算法还利⽤了内存空间,每次计算都要占⽤⼀定内容,不过 bcrypt 算法由于有成熟的实现,实际使⽤较多,spring boot security 的密码加密就⽤的这个算法。
⽐如某个密码经过 bcrypt 加密后变成这样:男神标准
$2a$07$woshiyigesaltzhi$$$$$.lrU488y7E1Xw.JA4uizIu.PBSSe7t4y
2a 表⽰ bcrypt 算法的版本,07代表迭代次数,次数越⾼,每次计算所需的时间越长,后⾯的woshiyigesaltzhi$$$$$ 代表加密⽤的 salt 值,数据库可以直接存储这个字段,⽐如:
name phone pwd_hash
⼩明1234$2a$07$woshiyigesaltzhi$$$$$.lrU488y7E1Xw.JA4uizIu.PBSSe7t4y
这种也是本⽂推荐的密码存储⽅式,hash + salt + 计算强度,可以较好保护⽤户密码安全,由于登陆不是频繁的操作,每次登陆时⽤户等待1 秒也没有太⼤关系。
⽤户数据密码加密⽅案:双重 hash
密码信息可以 hash,达到不可逆的⽬的,但是⼀些⽤户数据是可逆的,⽽且要求加密,怎么办?⽐如⽤户在线⽂档,通过⽤户⾃定义的密码加解密。
很容易想到的就是之类的对称加密技术:
$$
e = AES256(salt, text)
$$
通过拿⽤户的密码作为 salt 值加解密⽂档,服务端存储⽤户密码。
还是前⾯的问题,明⽂存储密码是不安全的⾏为,这⾥可以⽤双重 hash 的⽅法保证⼀定的安全性(这⾥的双重 hash 不是连续计算两次hash 的意思):
实现⽅案:
⽤户密码存储仍然采⽤前⾯提到的⽅案,可以⽤ bcrypt 算法,这⾥记存储的值为 h1,当⽤户请求加密数据时,提供了加密密码,我们通过h1 检验⽤户密码的正确性,同时⽤⽤户的密码计算出另⼀个 h
ash 值,记为 h2,h2 的计算⽅式与 h1 不同,只是简单的 hash,不能加盐,这时我们使⽤ h2 加解密⽤户⽂档:
$$
e = AES256(h2, text)
$$
记住,h2 的值是不能存储的(不能保存于数据库中),⽤于加解密数据。由于 h2 的值⽤完就丢掉。h2 的 hash 函数可以是私有的,进⼀步保障安全性。
为什么需要 h2 这个参数?⾸先⽤户密码长度不⼀致,像 AES 之类的对称加密算法需要有⼀个固定长度的加密参数,其次经过 hash 之后能够进⼀步保障数据安全性,如果数据库泄露,攻击者即使知道⽤户密码,不知道私有 hash 函数也⽆法进⾏解密。
其他⽤户数据的加密
上述提到的加密⽅案是⽤户密码控制的,数据安全性⾮常⾼(只有⽤户知道密码,且密码丢失后数据不可恢复),但是这种做法很多场景不适合,⽐如常规的⽤户数据:⼿机号、社交账号、地址、姓名,⾼频访问的数据不适合⽤密码加密,效率太低,那如何保护⽤户这类数据的安全性呢?
理解这个问题,需要知道⽤户数据是怎样传输的:
⽤户在客户端软件上产⽣数据(⽐如浏览器上),经过 https 加密传输到后端服务器,有服务端软件处理(⽐如 java),之后经过调⽤数据库接⼝通过数据库软件(⽐如 mysql)存储到存储设备中(⽐如硬盘)。
有 4 个阶段可以进⾏数据加密,加密的过程越靠近⽤户越安全(客户端加密后⾯说):
服务端软件加密:数据到达服务端后⽴马加密存储(内存中执⾏),⽐如 java 执⾏ AES256
数据库软件加密:调⽤数据库API实现数据库加密,⽐如 mysql 的 AES 加密
存储端落盘加密:使⽤硬件加密技术进⾏加密存储,⽐如云服务商提供的云盘加密功能
加密⽅式防⽌内部泄露防⽌数据库泄露防⽌物理机丢失泄露
服务端软件加密√(⼤部分场景)√√
数据库软件加密√√
存储端落盘加密√
前两者加密⽅式都可以保证即使是数据库管理员也⽆法查看⽤户数据,最后⼀种通常意义不⼤,但⼀些国家、地区的法律要求,或者⽤户要求有硬盘加密措施,仍然需要使⽤。数据库软件加密仍然存在内部泄露的风险,⽐如 mysql 的 binlog,即使你使⽤了 AES256,数据同步时密钥也会存储在 binlog 中,存在泄露的途径。
如果相关⽤户数据没有搜索的需求(只有常规读写需求),可以使⽤服务端加密或者数据库加密的⼿段保护⽤户数据。但如果相关数据需要⽀持搜索功能,这个问题就很棘⼿了。
可搜索加密技术
这篇论⽂发表于 2000 年,开创了⼀个新的研究⽅向,提出了第⼀个实⽤的可搜索加密⽅案 SWP,实现思路⼤概是:通过加密每个单词,然后将⼀个 hash 值嵌⼊密⽂中,服务器通过提取改 hash 值,检查密⽂中是否有类似的特殊格式,确认是否匹配搜索。
上⽂想法很理想,但是落地时会有很多困难,⽐如必须使⽤固定⼤⼩的单词,但搜索系统最重要的就是其分词引擎,如何对多种语⾔进⾏良好的分词直接决定了搜索的效果,不少搜索系统任然采⽤如下结构:
将 mysql 的数据单向同步到 elasticsearch 中,完成相关搜索功能的⽀持。20 多年过去了,今天,可搜索加密技术依然⽆法落地使⽤,甚⾄
可以这么说,如果软件商提供了搜索功能,该数据存储的时候就是没有加密的(硬盘加密对软件层不可见),已加密的数据是⽆法⽀持搜索功能的。
阴谋实现的前提
假如我是⼀个坏⼈,要实现某个阴谋,很重要的前提就是操作⾜够简单,知道的⼈⾜够少,当复杂度太⼤或者需要的⼈很多的时候就不可能实现这个阴谋。
知道这⼀点我们可以很轻松地判断:“美国登⽉是假的”,这个阴谋猜想是错的。因为登⽉⼯程涉及的⼈很多、⼯程复杂,⽆法实现这个阴谋。
这个结论是下⽂内容的基础。
⼀些软件声明的安全说的是什么?
上述提到的可搜索加密技术⽆法落地,⼀些软件⼚商(包括⼀些⼤⼚)提供了搜索功能,仍然声称他们对⽤户数据进⾏了加密,很安全,他们到底在说什么?
第⼀,他们可能说的是硬盘加密,⽽不是软件层的加密(只能防御硬盘盗窃风险,不能防御数据泄露风险、内部风险);第⼆,他们可能说的是传输过程的加密,⽐如 https 或私有通讯加密协议;第三,他们可能有完善内部管理流程,控制内外部风险。
利⽤上⾯阴谋论的前提,只要增加⼀些流程,公开透明出来,提⾼使坏的成本,在技术不可实现的情况下,也能保障⽤户数据的安全,⽐如:
数据库操作⽇志审查:由其他⼈审核 DBA 数据库操作是否合规,是否偷偷查看某⽤户数据等
多重密码:由多⼈掌握密码,只有统⼀输⼊密码才能解密数据,提⾼操作复杂度,如多⼈审核
公开透明的流程:涉密操作流程记录,⽐如某某由于开发测试原因,需解密数据
拥有完善的流程也能让⽤户放⼼存储隐私数据。
加密技术的未来:不⽤加密
前⾯没有提到的客户端加密放这⾥说。加密点越靠近⽤户,就越安全,如果⽤户发出来的数据就是经过加密的(⾮ https 类传输加密),并且⾃⾏控制密码,这样服务提供商也⽆需进⼀步做加密处理了,标题提到的不⽤加密指的就是这个,服务商不⽤再花费⼤量精⼒、成本在数据安全上⾯,将数据所有权交给⽤户。奶茶妹疑情变
上⾯客户端加密所需的⼀个技术就是:,这是密码学领域的⼀个重要课题,在 2009 年 9 ⽉,IBM 的博⼠克雷格·⾦特⾥发表了⼀篇论⽂:,提出了⼀个可⾏⽅法,⾃此解决了密码学的⼀⼤难题。全同态加密可以简单理解如下:
普通话考试
$$
f(data) = DE(\ f(\ E(data)\ ))
$$
其中 f 是任意操作函数,E 是加密函数,DE 是解密函数,也就是说对密⽂的任意计算操作等同于对明⽂做同样的操作。
这就很⽜逼了⽐如我⼿上有⼀些财务数据,需要第三⽅机构进⾏统计分析,但是我⼜不想直接给他们数据,他们告诉我可以提供全同态加密服务,那么我可以在给他们数据之前将数据加密⼀遍,他们给我统计计算后的结果,我解密相关结果即可,真实的数据只有我看得到。
全同态加密的这些特性能够很好解决数据安全,信任的问题,克雷格·⾦特⾥给出了⼀个实现,之后很多密码学者也给出其他实现⽅法,但⽬前的⾓度来说该技术还不成熟,⽐如⼀个密钥就得 100 MB ⼤⼩,对于当下⽹络环境来说⽆法实际使⽤。
结语
没有绝对的安全,只有相对的安全。期待全同态加密技术在商⽤领域取得突破性进展。
庞晓戈近况经作者授权转载,,作者: