“认证”是最容易理解的一种安全。如果一个系统缺乏认证手段,明眼人都能看出来这是“不安全”的。最常见的认证方式就是用户名与密码,但认证的手段却远远不止于此。
很多时候,人们会把“认证”和“授权”两个概念搞混,甚至有些安全工程师也是如此。实际上“认证”和“授权”是两件事情,认证的英文是 Authentication ,授权则是 Authorization 。分清楚这两个概念其实很简单,只需要记住下面这个事实:
认证的目的是为了认出用户是谁,而授权的母的是为了决定用户能够做什么。
认证实际上就是一个验证凭证的过程。
如果只有一个凭证被用于认证,则称为“单因素认证”;如果有两个或多个凭证被用于认证,则称为“双因素( Two Factors )认证”或“多因素认证”。一般来说,多因素认证的强度要高于单因素认证,但是在用户体验上,多因素认证或多或少都会带来一些不方便的地方。
密码是最常见的一种认证手段,持有正确密码的人被认为是可信任的。
密码的优点是使用成本低,认证过程实现起来很简单;缺点是密码认证是一种比较弱的安全方案,可能会被猜解,要实现一个足够安全的密码认证方案,也不是一件轻松的事情。
“密码强度”是设计密码认证方案时第一个需要考虑的问题。在用户密码强度的选择上,每个网站都有字节的策略。
一般在用户注册时,网站告知用户其所使用密码的复杂度。
目前并没有一个标准的密码策略,但是根据 OWASP( https://owasp.org/ )推荐的一些最佳实践,我们可以对密码策略稍作总结。
除了 OWASP 推荐的策略外,还需要注意,不要使用用户的公开数据,或者是与个人隐私相关的数据作为密码。
密码必须以不可逆的加密算法,或者是单向散列函数算法,加密后存储在数据库中。
将明文密码经过哈希后(比如 MD5 或者 SHA-1)再保存到数据库中,是目前业界比较普遍的做法----在用户注册时就已将密码哈希后保存在数据库中,登录时验证密码的过程仅仅是验证用户提交的“密码”哈希值,与保存在数据库中的“密码”哈希值是否一致。
目前黑客们广泛使用的一种破解 MD5 后密码的方法是 “彩虹表( Rainbow Table )”。
彩虹表的思路是收集尽可能多的密码明文和明文对应的 MD5 值。
为了避免密码哈希值泄露后,黑客能够直接通过彩虹表查询出密码明文,在计算密码明文的哈希值时,增加一个“ Salt ”
。“ Salt ” 是一个字符串,它的作用是为了增加明文的复杂度,并能使得彩虹表一类得攻击失效。
Salt 的使用如下:
MD5( Username + Password + Salt )
其中,Salt = abcddcba … (随机字符串)
Salt 应该保存在服务器端的配置文件中,并妥善保管。
多因素认证提高了攻击的门槛。
密码与证书等认证手段,一般仅仅用于登录( Login )的过程。当登录完成后,用户访问网站的页面,不可能每次浏览器请求页面时都再使用密码认证一次。因此,当认证成功后,就需要替换一个对用户透明的凭证。这个凭证,就是 SessionID 。
什么是 Session Fixation 呢?举一个形象的例子,假设 A 有一辆汽车,A 把骑车卖给了 B,但是 A 并没有把所有的车钥匙交给 B ,还自己藏下了一把。这时候如果 B 没有给车换锁的话,A 仍然是可以用藏下的钥匙使用骑车的。
这个没有换“锁”而导致的安全问题,就是 Session Fixation 问题。
在用户登录网站的过程中,如果登录前后用户的 SessionID 没有发生变化,则会存在 Session Fixation 问题。
解决 Session Fixation 的正确做法是,在 登录完成后,重写 SessionID 。
一般来说,Session 是有生命周期的,当用户长时间未活动后,或者用户点击退出后,服务器将销毁 Session 。Session 如果一直未能失效,会导致什么问题呢?前面的章节提到 Session 劫持攻击,是攻击者窃取了用户的 SessionID ,从而能够登录进用户的账户。
但如果攻击者能一直持有一个有效的 Session(比如间隔性的刷新页面,以告诉服务器这个用户仍然在活动),而服务器对于活动的 Session 也一直不销毁话,攻击者就能通过此有效 Session 一直使用用户的账户,成为一个永久的“后门”。
但是 Cookie 有失效时间,Session 也可能会过期,攻击者能永久的持有这个 Session 吗?
一般的应用都会给 Session 设置一个失效时间,当到达失效时间后,Session 将被销毁。但有一些系统,出于用户体验的考虑,只要这个用户还“活着”,就不会让这个用户的 Session 失效。从而攻击者可以 通过不停的发起访问请求,让 Session 一直 “活” 下去。
Cookie 是可以完全由客户端控制的,通过发送带有自定义 Cookie 头的 HTTP 包,也能实现同样的效果。
在 Web 开发中,网站访问量如果比较大,维护 Session 可能会给网站带来巨大的负担。因此,有一种做法,就是服务器端不维护 Session,而把 Session 放在 Cookie 中加密保存。当浏览器访问网站时,会自动带上 Cookie,服务器端只需要解密 Cookie 即可得到当前用户的 Session 了。这样的 Session 如何使其过期呢?很多应用都是利用 Cookie 的 Expire 标签来控制 Session 的失效时间,这就给了攻击者可乘之机。
Cookie 的 Expire 时间是完全可以由客户端控制的。篡改这个时间,并使之永久有效,就有可能获得一个永久有效的 Session,而服务器端是完全无法察觉的。
如何对抗这种 Session 保持攻击呢?
常见的的做法是在一定时间后,强制销毁 Session 。这个时间可以是从用户登录的时间算起,设定一个阀值,比如 3 天后就强制 Session 过期。
但强制销毁 Session 可能会影响到一些正常的用户,还可以选择的方法是当用户客户端发生变化时,要求用户重新登录。比如用户的 IP、UserAgent 等信息发生了变化,就可以强制销毁当前的 Session,并要求用户重新登录。
最后,还需要考虑的是统一用户可以同时拥有几个有效 Session 。若每个用户只允许拥有一个 Session ,则攻击者想要一直保持一个 Session 也是不太可能的。当用户再次登录时,攻击者所保持的 Session 将被“提出”。
单点登录的英文全称是 Single Sign On,简称 SSO。它希望用户只需要登录一次,就可以访问所有的系统。从用户体验的角度看,SSO 无疑让用户的使用更加的方便;从安全的角度看,SSO 把风险集中在单点上,这样做是有利有弊的。
目前互联网上最为开放和流行的单点登录系统是 OpenID。OpenID 是一个开放的单点扽牢固框架,它希望使用 URI 作为用户在互联网上的身份标识,每个用户( End User )将拥有一个唯一的 URI。