这两天有点空,多写一些吧,上篇文章当中涉及到的【故事】其实还有太多太多,我就不记流水帐了,只挑对于多数人来说容易看懂的说说,抛砖引玉吧。

【本文背景】

近几年,国内一些企业的后台用户信息被黑客公布,相信大家都有耳闻,这只是公布了的,没公布的呢?还有多少,你想想诸多中国互联网企业保存了多少用户的数据,它们往往都是黑客们的“余粮”,这些事件导致的损失咱就不耸人听闻了,在类似事件当中,有诸多的用户隐私信息,其中最敏感的莫过于密码本身了,今天就讲讲对于企业应用来说,如何保护用户的密码才安全。

使用“安全思维”一词,源于我认为这些原则不需要背诵,而是你应用安全思维形成后的信手拈来。

【密码保护的原则】

1. 永远不要在数据库、会话及本文当中保存明码密码,中间临时的变量存储用完后要及时清空

2. 在正式的产品线上运行的产品,任何人不应该有渠道获取到用户密码的明码,包括但不限于产品开发人员、产品维运人员及技术支持人员

3. 用户密码只采用sha2-256或者更高版本更多数位的算法进行哈希,而不是用诸如AES算法进行加密

4. 任何用户的密码在哈希时必需包括但不限于:1)可配置长串Key 2)用户设置密码时动态随机生成随机串 3)用户密码本身

5. 永远不要以任何形式log用户的密码,无论你是想做问题的调试还是用户信息的收集,密码的明码都是不能碰的

6. 不要认为以上1-5 block你的业务逻辑实现,那是你的实现方法不对,以上的原则是正确的

7. 企业应用系统必需严格的log任何人的对用户敏感信息的操作

可能有人会问“帐户泄漏不是因为以下可能的原因导致的吗“?

1)应用层的漏洞,诸如:SQL Injection导致非授权数据被查询出来

2 ) HTTP 伺服器(e.g. Apache\Tomcat...)实现时用的程序语言导致缓冲区溢出、业务逻辑导致的缓冲区溢出等导致远程代码注入与执行从而进入后台直接拧取数据库内容

3)网络操作系统实现时用的程序语言导致缓冲区溢出、业务逻辑导致的缓冲区溢出等导致远程代码注入与执行从而进入后台直接拧取数据库内容

4)数据库伺服器(e.g. MySql)实现时用的程序语言导致缓冲区溢出、业务逻辑导致的缓冲区溢出等导致远程代码注入与执行从而进入后台直接拧取数据库内容

......

是的,以上往往是爆库的直接原因,但是在这里我建议您想想这三个概念:攻击者、受害者、责任者,对于以上的原因,只有原因1)本身的责任者是产品的主人,而各种服务端软件提供者、操作系统往往并不被企业直接进行代码级维护,你是可以通过安全设置与配置进行安全设置,但是它的体系何止你了解的那么一丁点儿? 对于做产品应用的企业来说,最佳的原则是:即便一整套系统被人搬走了,我也能最大限度的保护用户的隐私及敏感信息!

OK,我们继续解读以上7原则。

原则1. 这一条很容易理解,明码意味着总有人有渠道去获取,这个人现在可能是朋友,将来也可能是敌人,所以有明码密码的地方就是孽源,呵呵

原则2. 如刚才所说,哈希后的密码也不应该通过简单的反向算法就可以恢复到原文,如果这样,对于企业的开发人员来说等于没有加密,还是那句话:在保护用户敏感信息上,没有可以相信的人,只有正确的方法。

原则3. 我一直在避免说“加密”二字,这两个字容易让人联想到能加就能解的事儿,所以容易习惯性的使用加密算法对密码进行加密存储,这样产品的实现者比较容易通过逆向的方法获取到用户密码

原则4. 可配置的Key可以有效的避免产品的开发与测试人员用同样的方法在正式产品线上通过逆向的方式破解用户敏感信息,随机Key的目的是让正式产品线上的维护者也较难通过逆向的方法来破解用户信息,更重要的是避免在用户信息表里具有相同密码的用户们拥有相同的哈希值! 具体如何实现嘛,办法肯定有,需要智慧哟~_~

原则5. 许多公司的通病,就是开发与测试人员为了自己的方便常把诸多信息写到LOG里,以方便自己的调试与问题跟踪,有了这个口子,一切安全措施都变成徒劳了,千万不要这么做!

原则6. 说这一条就是为了堵住具体实现人员的嘴,呵呵,没有实现不了的,只有你没想到的。原则有了,实现方法一定会有,没有直线的方法,可以有曲线的方法,总之一定有。具体产品具体业务逻辑具体对待,没有统一的方法,能统一的,我就告诉你了~_~,但是整体思想是一致的。

原则7. 记录企业产品的管理员、维运人员、技术支持人员的敏感操作(包括但不限于),对于一些重大安全事件的追踪相当有意义,最终有一种“锁”机制,如果敏感log不能写成功,那操作就不能执行,敏感操作的log最好放在相对独立的服务器上,以防止被毁尸灭迹~_~。本人就有一个大胆的猜想:诸多企业的爆库事件,至少有一种可能就是来自企业内部,而并非一定来自“真正意义上的黑客”,大家千万别攻击我,我只是说至少有一种可能。

做应用安全的过程就如你从刚接触自行车到最终可以熟练的驾驭的过程。当你首次接触自行车的时候,通常有一种困惑就是:两个轮子为什么不会倒?甚至因此质疑自己到底能不能学会。当你学会了以后,你就不需要再考虑它倒不倒的事儿了,任何一个要倒的倾向,你都会在不经意间化险为夷,这就是你已经领会它的神了,植入了你的潜意识。应用安全的思维也是这么形成的,只是过程要漫长的多。我们学任何知识,最终能终身受益的往往不是知识本身,而是它的思维方式,比如:数学让你有推理的思维习惯,历史让你有反思的思维习惯,哲学让你有透过现象看本质的思维习惯等等,大学毕业数年了,如果你不从事相关职业,让你去考试,你能考几分?但这并不表明你学的东西都忘记了,其实最有价值的东西还保存着呢,那就是:思维方式。应用安全也一样。祝您早日驾驭应用安全!

[原文地址]

相关讨论:

jiayzhan (5级) 硅谷某知名IT企业中国区高级应用安全工程师 2013-07-15 1楼

解释一下文中的一小段描述:【哈希后的密码也不应该通过简单的反向算法就可以恢复到原文】,此处并不是想表达哈希值可以直接解密,就算是最垃圾的MD5,直接解密它也是异常困难的,我主要指:哈希值的生成时的构成元素,比如:SHA2-256(strPwd),如果是如此简单的构成元素,问题就大大的了,比如:用户使用了一个简单的密码:12345,此时SHA2-256(“12345″)将是一个固定的值了,如此,我就可以利用SHA2-256攻击字典(map of value and hashValue)进行尝试,将会非常容易的测试出简单的密码值。所以,即便用户使用了简单的密码,我们也要确保用户名与密码不易被字典攻击,比如可以使用:SHA2-256(strPwd+configurableRandomString+randomString+…)来进行hash,可能有人会有疑问,这玩意如何验证,自己考虑吧,实在不明白,私下再讨论。

Justin (1级) 2013-07-15

@jiayzhan 如果没有理解错的话,这个是salt加密?只是一直搞不清楚randomstring的salt,最终应该怎么验证,大神有相关资料可以查询下?

jn61129052 (1级) 2013-07-15

@Justin salt要做到randomstring,最简单的就是使用用户名,某种特殊的变换(比如加上注册时间)以后变成salt,这样数据库中存的全都是随机的salt,,并且可以很简单的进行验证。除非得到真正的加密算法,不然脱裤也无法登陆

jiayzhan (5级) 硅谷某知名IT企业中国区高级应用安全工程师 2013-07-15

@jn61129052 使用不使用用户ID依据业务逻辑需要决定,主要是要带上:唯一的、随机的值。它的意义在文中有述,验证方法嘛,应该不止一种吧,各公司玩法不一样,我不大方便透漏我们的玩法。可以提示一下:如果产品线上的维护者与开发人员合作,是有办法知道这个salt的。我文中提到更重要的是防止同密码同值的情况出现。

目前国外有一些超级大公司的要求更严格,他们要求服务提供者永远不可能有任何渠道查询用户的明文数据,那只有唯一的办法了:客户端加密及客户端解密,脱离此办法的,是不可能做到服务提供者永远不可能看到用户的明文信息的目的的。还有一些公司使用自己的“加解密代理”,就是在自己公司与云服务提供商之间,加一个代理,自动加解密用户数据,以达到云服务提供者永远不能看到明文的用户数据的目的。之所以说这么多,是因为我认为大家的困惑在这里,希望我蒙对了~_~

fake 2013-07-15

@jiayzhan 请教楼主两个问题1.configurableRandomString是啥意思?

2.如果salt随机的意义在哪?是为了防止salt被拿到吗?

3.楼主的意思是每个用户都有一个专属salt吗?还有,如果salt随机了,如何避免hash后不会重复?

jiayzhan (5级) 硅谷某知名IT企业中国区高级应用安全工程师 2013-07-15

@fake

1. configurableRandomString也是盐,目的:增加复杂度,同时之所以叫:configurable目的是让它在测试环境里使用一个,正式上产品线的时候,通过简单的修改就可以使用新的,从而避免测试环境与产品线上的盐一样。

2. 随机盐的主要目的:防止同密码同hash值。不是为了防止salt被拿到。

3. 是的,必需有专门盐。随机+唯一,所以可以带时间戳。如果随机+唯一都会重复,那就是sha2-256的空间问题了,俗语叫:碰撞。如果你碰上了,你当天就去买彩票,不中奖也开心,呵呵。

不知道我的回答是否完整。

逍龙 (1级) 2013-07-15

@jiayzhan configurableRandomString對於所有用戶都是一樣的嗎

jiayzhan (5级) 硅谷某知名IT企业中国区高级应用安全工程师 2013-07-15

@逍龙 是的,一样的,所以需要后面一个randomStr以确保同密码不同哈希值

xiao_hen (1级) 矮穷挫小分队。 2013-07-15

@jiayzhan 想解开的话,完全就是数学难题。理论上是不可以的,不知道将来可不可以实现。

jiayzhan (5级) 硅谷某知名IT企业中国区高级应用安全工程师 2013-07-15

@xiao_hen 理论上可以,实现上 难 到不可以程度,呵呵。

cd 2013-07-15 2楼

那如果应用采用了HTTP digest或者CHAP协议的话,密码该怎么保存呢

jiayzhan (5级) 硅谷某知名IT企业中国区高级应用安全工程师 2013-07-15

@cd 你的问题是涉及的是:传输的安全性问题,不是本文的范围。关于传输安全,涉及两个阶段:非对称加密的密钥协商及传输过程,及对称加密的数据传输过程。将来有机会我细写一篇文章来描述。

xxoo 2013-07-15 3楼

有钱的主,买加密机

没钱的主,自己做一个加密接口,类似于SSO的东东。算法可以采取变异非对称算法

phper 2013-07-15

@xxoo lz公司用加密机吗

jiayzhan (5级) 硅谷某知名IT企业中国区高级应用安全工程师 2013-07-15

@phper LZ是我,呵呵,你是问楼上吗?

pher 2013-07-15

@jiayzhan 是问您哦,您公司用加密机了吗?你们用加密机主要解决什么问题?

jiayzhan (5级) 硅谷某知名IT企业中国区高级应用安全工程师 2013-07-15

@pher 不用,加密代理用起来会有诸多不方便

xiao_hen (1级) 矮穷挫小分队。 2013-07-15

@xxoo 公司用加密机。那也太奢侈了吧?

jiayzhan (5级) 硅谷某知名IT企业中国区高级应用安全工程师 2013-07-15

@xxoo 呵呵,与本文不完全匹配。但确实是应用安全当中需要解决的一类问题。

cd 2013-07-15 4楼

我理解我的问题还不只是传输问题,也与服务器如何保存密码相关。比如服务器如果采用SHA256(password+salt+blabla)方式存密码的话,就很难支持CHAP了,因为CHAP协议中请求方会计算MD5(password+rand),这样服务器没法验证请求方送上来的响应值。HTTP digest也存在同样的问题。

jiayzhan (5级) 硅谷某知名IT企业中国区高级应用安全工程师 2013-07-15

@cd 协议是协议,数据是数据,如果协议的设计需要要求数据是什么形式,那一定是协议出了问题。两者之间应该不矛盾的,我觉得应该是我没了解你的疑问在哪里。你可以更详细的描述一个work flow,方便我可以更好的了解你的疑问。

cd 2013-07-15 5楼

“如果协议的设计需要要求数据是什么形式,那一定是协议出了问题” 这个我觉得有点绝对了。

CHAP协议或者HTTP Digest协议,都需要认证双方根据临时的随机数rand、密码 psw、用户身份id以及其他一些参数计算摘要HASH(rand|psw|id|…)。但如果服务器只有Hash(psw|salt),就没法验证HASH(rand|psw|id|…)的正确性。这两个协议可以看一下RFC 1994和RFC 2617.

所以密码如何保存是会影响协议的支持性的,如果需要支持很多种认证协议,那可能xxoo说的加密机是个靠谱的办法。而且说实话加密机也没多贵。

jiayzhan (5级) 硅谷某知名IT企业中国区高级应用安全工程师 2013-07-15

@cd 呵呵,谢谢批评,任何时候都不应该把话说的绝对了。好,进入正题。

你说的与我说的是两类问题了:

1. 本文所述的问题是:基于通用协议的安全存储与使用的问题

2. 你的问题是的基于 【验证的协议】。OK,就来说说这个 【基于认证、验证的协议】—-【CHAP】 吧.

这个问题很好解决,协议依然是协议,数据依然是数据,过程可以如下:

假设服务端的密码被带我上述的方法给sha2-256了,注意,此时使用我上述方法时,不要直接使用明文密码参与hash了,而使用与CHAP协议一致的HASH算法hash之后,再参加我的算法,然后开始进行CHAP的过程:

【A】—-请求访问—> 【B】

【B】–接受请求,要求对A进行身份确认 CHAP认证 –>【A】

【A】–接受身份认证,–A的密码hash+自己的用户名 —>【B】

【B】–取得A的密码hash后,用sha2-256也就是我上述的算法,得到一个sha2-256的哈希值,B再通过用户名找到用户A的存储的我上述的方法得到的sha2-256的哈希值,进行比对,得到验证结果。

不矛盾的吧?呵呵。数据依然是数据,协议依然是协议,这个小原则理论上任何时候不会错的,可以称之为协议的东西,得有这方面的考虑,那就是:独立性及自成一个小体系。

kevinf (1级) 2013-07-15

@jiayzhan 你对CHAP协议的理解有误。 在第二步B需要发一个random给A,要求A计算出至少包含了A的Password 和random 的字符串的哈希值。 这里的Random就是所谓的Challenge (C)。没有了随机性,就算不上挑战-响应了。

jiayzhan (5级) 硅谷某知名IT企业中国区高级应用安全工程师 2013-07-15

@kevinf 嗯,握手过程我说的不够细,CHAP握手是标准的的握手过程的简化版,比SSL握手过程简略一些,但不影响我所阐述的solution。

kevinf (1级) 2013-07-15

@jiayzhan 由于必须用到随机的Challenge,在Server端必须要能够恢复出Password的原文,只能用可逆的加密算法来处理Password,不能使用SHA256等哈希算法.

jiayzhan (5级) 硅谷某知名IT企业中国区高级应用安全工程师 2013-07-15

@kevinf 没完全理解我阐述的solution,是我描述的不易懂,呵呵,你再看几遍,还不理解的话,我换一个方法再说一次。先看一下。把任何协议理解为一个黑箱子,两头是接口,所以,中间的协议是什么,理论上不可能影响到你的具体实现的。还是那句话,如果真的影响了,那一定是协议设计的有问题了,古老的协议也不排除这种可能。

cd 2013-07-15

@jiayzhan 多谢回复。 可能还需要对协议讨论一下。以CHAP为例,流程是这样的:

1. Client –用户的ID–>Server

2. Client<–Challenge– Server

3. Client –MD5(ID,password, Challenge) –>Server

4. Client<– Accept/refuse–Server

第二步的Challenge必须是每次随机生成,不然恶意终端就可以重放攻击了。

假设服务器保存密码是SHA256(password, salt,..)保存的。到第3步收到终端发上来的请求后怎么能通过SHA256(MD5(ID,password,Challenge))验证呢。

jiayzhan (5级) 硅谷某知名IT企业中国区高级应用安全工程师 2013-07-15

@cd @kevinf 不好意思,下班刚回到家。OK,以CD所述为蓝本,继续讨论:

这里确实是个矛盾了,我大概猜测到了你们的使用场景了。貌似CHAP协议本身在设计的时候没有考虑到致服务端不可逆加密存储的情况,如果是这样,如果我是你们的安全主管,我的决定是:

1. 为什么要使用CHAP协议,SSL+自实现的认证模式足以解决此问题

2. 一定要使用CHAP协议,那就想法改造它,比如:走SSL通道,去除挑战码

我简单查了一下资料,表明CHAP协议不支持与不可逆加密存储一起使用,先天性的问题了,可以看一下:

http://technet.microsoft.com/zh-cn/library/dd197594(v=ws.10).aspx

若要启用基于 CHAP 身份验证,必须执行以下操作:

作为网络访问服务器上的身份验证协议启用 CHAP。

在 NPS 中适当的网络策略上启用 CHAP。

启用用户密码是可逆加密形式的存储。

可以启用的每个用户帐户的用户密码的可逆加密形式存储,也可以使存储能够用于在域中的所有帐户。

强制重置用户密码,以便新的密码是可逆加密形式。

逍龙 (1级) 2013-07-15 6楼

salt是應該存在數據庫中還是根據其他的例如用戶名和時間根據設定的算法等用的時候再計算出來

jiayzhan (5级) 硅谷某知名IT企业中国区高级应用安全工程师 2013-07-15

@逍龙 你讲到点子上了,哈哈,好好想想吧,过两天再说:-)

anlfi (1级) ??????????????????????????... 2013-07-15 7楼

还有一种加密叫对等加密 密匙就是加密代码的一部分

想要解码就必须把源代码填充完整使之有效 在进行RSA动态加密验证

其实md5-128 即md5的128位加密算是不弱了相比普通MD5 可以说非常难解了

(这里就有了建模建模关系 32的储存空间与CPU计算 假如是彩虹表那么128就会比普通MD5大)

加密只是一个环节 至于密码明文未必需要或者可以劫持获得

或者可以利用一些逻辑漏洞直接使用hash登入

然而 令牌 usbkey 之类的 就像SSH信任 这些无需密码的威胁也是很重要的 不仅仅是在那个层面

这里有点牵涉密码学 然而还有算法攻击 在服务端加密的过程产生错误

SSL的算法攻击 只要一台笔记本就可以让公司瘫痪 密码也属于一种可输入区域

现在dz 可以用腾讯的API 绑定登入 这里密码安全就直接转交第3方了

然而安全还不在这里 假如Api出现漏洞依然可以绕过密码验证

密码不是绝对安全的 想要安全 怎样的强大加密的密匙hash 都是不够的 而是验证体制这个整体

anlfi (1级) ??????????????????????????... 2013-07-15 8楼

显然有点片面 期待下一篇吧 如果能构成一个系统模式才算是成功哦呵呵~

jiayzhan (5级) 硅谷某知名IT企业中国区高级应用安全工程师 2013-07-15

@anlfi 欢迎阐明“不片面”是什么样子,呵呵,符合本文主题的不片面的部分,我可以委托编辑补充进来。本文不是在说密码学,也不是有说密码安全的完整体系,至少还没谈到密码的传输安全。一步一步来吧。

打酱油 2013-07-16 9楼

什么时候我们的密码才是中文的呢????????????

jiayzhan (5级) 硅谷某知名IT企业中国区高级应用安全工程师 2013-07-16

@打酱油 密码通常本就可以是中文的,只是应用实现时候限制了它的范围,原因有多种了,其中比较重要的原因就是避免输入设备无法输入问题,比如银行柜台输入终端。

打酱油 2013-07-16 10楼

来个MD5的,http://www.cngrayhat.org/archives/81