OWASP
认证
密码维度
单因素认证、双因素认证、多因素认证(密码、手机动态口令、数字证书、指纹等各种凭证)。
密码强度
长度:普通应用6位以上;重要应用8位以上,考虑双因素;
复杂度:密码区分大小写;密码为大写字母、小写字母、数字、特殊符号中两种以上的组合;不要有(语义上)连续性的字符,比如123、abc;避免出现重复字符,比如 111;不要使用用户的公开数据,或与个人隐私相关的数据作为密码,比如 QQ 号、身份证、手机号、生日、昵称、英文名、公司名等。
密码保存
密码必须以不可逆的加密算法,或单项散列函数算法,加密后存储在数据库中。目前业界比较普遍的做法:在用户注册时就已经将密码哈希(MD5、SHA-1,不可逆,不冲突)后保存在数据库中,登录时验证密码仅仅是验证用户提交的密码哈希值是否与保存在数据库中的密码哈希值一致,即服务器不会保存密码原文。
破解 MD5 后密码的方法——彩虹表:收集尽可能多的明文密码和对应的 MD5 值,然后通过 MD5 值反查到该 MD5值对应的密码原文。防御方法:加盐,即 MD5(Username+Password+Salt),其中 Salt 为一个固定的随机字符串,应该保存在服务器端的配置文件中,妥善保管。
SessionID(会话编号)
当登录认证成功后,服务器分配一个唯一凭证 —— SessionID 作为后续访问的认证媒介。会话(Session)中会保存用户的状态和其他相关信息,当用户的浏览器发起一次访问请求时,将该用户持有的 SessionID 上传给服务器。常见做法是将 SessionID 加密后保存在 Cookie 中,因为 Cookie 会随着 HTTP 请求头发送,且受到浏览器同源策略的保护。生成的 SessionID 要足够随机,比较成熟的开发框架都会提供 Cookie 管理、Session 管理的函数,要善用这些函数和功能。
风险
一旦有效的 SessionID 泄露,则在其有效期内攻击者能够以对应用户的身份访问站点。泄露方式:Cookie 泄露(SessionID 保存在 Cookie 中的情况),Referer 的 URL 中泄露(URL 携带 SessionID 的情况)。
Session Fixation 攻击
SessionID 没有及时更替、销毁,导致旧的 SessionID 仍然有效,一旦激活便可以正常使用。防御方法:在用户登录完成后要重新设置 SessionID;用户更换访问设备的时候要求重新登录;使用 Cookie 代替 SessionID 的作用。
Session 保持攻击
Session 是有生命周期的,当用户长时间未活动,或用户点击退出后,服务器将销毁 Session。① 如果只依赖 Session 的生命周期来控制认证的有效期,Session 保持攻击可以通过脚本持续刷新页面(发送访问请求)来保持 Session 的活性。② 如果 SessionID 保存在 Cookie 中,依赖 Cookie 的定时失效机制来控制认证的有效期,那 Session 保存攻击可以手动地修改 Cookie 的失效时间,甚至将 Cookie 设置为永久有效的 Third-party Cookie,以此延长 Session 的活性(Cookie 是可以完全由客户端控制的)。防御方法:用户登录一定时间后强制销毁 Session;当用户的客户端(IP、UserAgent、device)发生变化的时候要求重新登录; 每个用户只允许拥有一个 Session。
SSO(Single Sign On,单点登录)
统一认证,缺点是风险集中,单点一旦被攻破,影响范围涉及所有用单点登录的系统,降低这种风险的办法是在一些敏感的系统里再单独实现一些额外的认证机制(比如网上支付平台,在付款前要求用户输入支付密码,或通过手机短信验证用户身份)。
目前业内最为开放和流行的单点登录系统是 OpenID —— 一个开放的单点登录框架,使用 URI 作为用户在互联网上的身份标识。每个用户将拥有一个唯一的 URI。在用户登录网站时,只需提交他的 OpenID(URI)以及 OpenID 的提供者,网站就会将用户重定向到 OpenID 的提供者进行认证,认证完成后重定向回网站。
例如用户 Ricky 在 OpenID 服务的提供者 openidprovider.com 拥有一个 URI,ricky.openidprovider.com;此时他准备访问某网站的一个页面(www.xxx.com/yyy.html),在xxx网站的登录界面会提示请用 OpenID 登录;于是 Ricky 输入他的 OpenID(URI),即 ricky.openidprovider.com,然后点击登录;页面将跳转到 openidprovider.com 站点,进入认证阶段;当认证成功后页面自动跳转到 www.xxx.com/yyy.html,如果认证失败则不会跳转。
授权
Web 应用中,根据访问客体的不同,常见的访问控制可分为 基于 URL 的访问控制(常用),基于方法(method)的访问控制(基于 Java 的 Web 应用中) 和 基于数据的访问控制。
垂直权限管理
定义角色,建立角色与权限的对应关系——基于角色的访问控制(Role-Based Access Control,RBAC)。用户→角色→权限。例如 Spring Security 中的权限管理(功能强大,但缺乏一个管理界面可供用户灵活配置,每次调整权限都要重新修改配置文件或代码);PHP 框架 Zend Framework 中使用 Zend ACL 做权限管理。使用 RBAC 模型管理权限时应当使用 “最小权限原则”,“默认拒绝”。
水平权限管理
水平权限问题出现在 RBAC 模型中的同一种角色的权限控制上,系统只验证了能访问数据的角色,但没有反过来再对用户与数据的权限关系做细分。此时需要基于数据的访问控制。
OAuth
OAuth 是一个在不提供用户名和密码的情况下,授权第三方应用访问 Web 资源的安全协议。三个角色:用户(User)、服务提供方(Server)、资源持有者(Resource Owner)。现在的版本是 OAuth2.0。
没必要自己完全实现一个 OAuth 协议,使用第三方实现的 OAuth 库是个不错的选择:
ActionScript/Flash,C/C++,clojure,.NET,Erlang,Java,JavaScript,Perl,PHP,Python,Qt,Ruby,Scala 都有。