6

安全的身份验证系统的设计

 3 years ago
source link: https://sexywp.com/user-authenticate-system-design.htm
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

公司大了,内网系统多了,关键性信息和商业秘密也多了以后,内网信息安全就成了很重要的命题,使用各种框架默认带有的类库,直接弄一个简单的用户名密码校验就已经不满足需求了。

设计一个身份验证解决方案就势在必行,当然了,设计一个解决方案,不一定非要自己撸代码,可以对接、购买,关键是看你的需求是什么。当然,我们还是选择了自己实现一个,这可能不是一个很好的选择,要在此声明这一点。

为什么要自己做?

自己实现有很多的原因了,比如三方的帐号不够安全(腹诽:其实微信的帐号身份验证已经足够安全了,相比大多数自己撸的系统来说,一个被无数人动脑子攻击的系统,其帐号验证的安全性经得起挑战),又比如,三方帐号不够让人信任,假设,你接入了微信,但是微信把你的账密给到一个攻击者,(腹诽:一般不可能,谁能做到这一点,大家心里有数),还比如,在实施三方帐号对接的时候,出现了疏忽和不可避免的错误,这倒是极其可能,比如你用了一个不靠谱的类库代码,这个代码在网上开源广为人知,会导致在衔接处被攻击,而且攻击很有针对性。

不过,列举了这么多自己做的理由,我可是没有自信自己实现一个,就能规避上面的全部问题,比如你的研发管理是否足够规范和安全?来自内部的攻击是否能够被极大的防范?君不见删库跑路的刚刚判刑。可能绝大多数公司的管理水平,这一点都保证不了,你的完美设计,基本都建立在沙滩上。你的设计是否全面完美,也是值得被挑战的地方。

面临些什么问题?

说了那么多,还是不得不自己做了,有些“你懂的”原因,我就不解释了,硬着头皮也得做,这不算牢骚,能自己设计系统,还是蛮高兴的,主要是反思一下是否“与人谋而不忠乎?”。

首先,公司肯定不止一个系统,很多的系统,肯定也不止一个开发团队,各做各的业务,你第一个就必须考虑到接入的问题,一定是 SSO 了,不然的话,每个团队各自做身份验证和授权,这么一扩散,你的安全就不好管控了。

那么 SSO 本身就带来很多的问题,用哪种协议呢?OAuth,SAML等等吧(其实我只了解过这俩,但是真的有很多)最简单易用的可能是 OAuth,这也是个个人判断,因为我用的 PHP 真的很多类库的。不过,就我所知,OAuth 其实在安全专家眼里是脆弱不堪的东西,将绝大多数安全的宝压在了 SSL 上面,一个心脏滴血就可以搞死一片。更不要提 OAuth 的实施,一般都很不规范,极容易弄出问题来。

因为,想弄这个 OAuth,毕竟省力,但是不够安全,就想到了 2FA,再给你叠加一道,应该就好点了吧,比如使用 Google Authenticator,或者使用企业微信钉钉的消息推送,发一个 OTP,当然,用短信发送也行,就是有点短信成本而已。

不过,验证码这种,真的很烦人的,我们选用了一种讨巧的方法,就是客户端证书验证。给每个需要访问内部系统的客户端,颁发一个客户端证书,安装了证书后,在访问内部系统的时候,必须首先向服务器出示,然后再提供密码才能进入。

在公司发展的早期,我们使用运维手动分配客户端证书的方式,反正人少,入职也少,无所谓,后来人越来越多,就不得不自动化这个过程。那么到底使用怎样的方式去分发这个证书,需要非常小心的思考,比如,一个很蠢的设计是,用户先用密码登录证书系统,然后申请证书,就直接发放,这么一来,其实你只要攻破了一个员工的密码,等于证书也可以轻松拿到了,那么还双因素个屁啊?

登录态管理

使用 SSO 后,你有个麻烦就是登录态管理的问题。比如,你要登录 A 系统,你肯定要先登录通行证,然后跳入 A 系统,这没什么问题,但是 A 系统退出的时候,是否要退出通行证呢?问题就来了。

如果在一个可信的电脑上,这是个无所谓的问题,最好不要退出,这样,你登录别的系统,跳通行证的时候,不用反复输入密码,然后授权就可以跳入了。

但是在一个不可信的电脑上,比如网吧里,如果你退出某个业务系统的时候,忘记退出通行证了。那么你的登录态留在了不可信设备上,被冒用的概率是很高的,至少暴露了攻击点出去。

关键原理设计

考虑到上面这些个问题,我们确立了一些比较关键的原理性的设计。

统一的帐号管理,但是只负责身份的验证,不负责权限管理,各个业务系统管理各自的业务权限。也比较符合事实。帐号管理部分,只能管理帐号的基本信息,名字邮箱手机等信息。

各个业务都要使用 SSO 登录,使用最简单的 OAuth 协议来对接。但是,大量敏感系统,必须至于企业内网,统一网关的保护之下,不允许在外网进行访问。对于外网可以进行访问的系统,如无例外,必须校验客户端证书。必须部署在统一网关的后面,就是便于统一的证书验证的部署,避免部署出现疏漏,收敛到少数安全运维的手里。减少部署环节的风险。

证书作为一般来说的第二个因素,实现双因素验证,这样不必太过麻烦,每次输入 OTP 之类的事情。但是证书的颁发,不能仅凭用户密码就颁发,证书的颁发应该来自密码之外的另一个因素。我们想到的是,使用员工预留手机的验证码来申请证书,但是预留手机号如何变更呢?不能是使用用户名密码简单变更。一个简单的处理是,必须使用原预留手机的验证码,才能更换新手机号码。如果,原手机遗失不可用,则不允许更换,只允许立刻冻结,无法走验证更换。必须通过管理员当面审核后手动设置新手机。

那么可以用邮箱来收取 OTP 么?其实并无不可,但是考虑到一般人的差劲的习惯,极有可能把工作邮箱的密码和 OA 系统的密码设为同一个,那等于又是形同虚设了,邮箱我们用的 GMail 的服务,不能检验员工是否使用了相同的密码,所以,就无法信任邮箱的安全性了,员工 OA 密码的泄漏在很大概率上邮箱也泄漏了。

另外,可以考虑其他一些 OTP 方案,比如 Google Authenticator 的绑定,那么绑定的过程,也必须是用另一个因素来验证过身份。以此类推。

我就想到了,比如一些孤立系统,比如 Twitter,GMail 也好,他们的双因素是怎么实现的呢?因为用户首次注册的时候,系统只知道用户名密码,怎么实现第二个因素的绑定呢?我现在猜测,这是一个安全升级的单向过程。

如果你原来只有用户名密码,那么你申请绑定手机,这时候只能信任你,但是你一旦绑定了,就有了第二个因素了,这时候,你想换绑,就不能只验证密码了,这取决于系统对手机这个因素的重要性认证。总之意思就是,你可以提高你帐号的安全级别,但是一旦提高了,就没法降级了(我没验证过这一点)。所以一个空帐号的安全等级很低,随着更多的信息被绑定,因素之间出现互保,你总是要取得两个因素才能攻破。单向升级,互相钳制,就是这么一个过程。

如果一个已经被提高了等级的帐号,你想用单个因素攻破就不可能了。因为单个因素不能给一个帐号的安全降级。我们自己的系统设计,就没有这个冷启动的问题,因为在企业的内部,我们可以直接就通过当面验证的方式把安全等级拉倒高级位置。然后一直锁定在这个位置。

帐号生命周期管理

帐号是怎么产生和回收的呢?因为我们有 OA 系统,必须通过 HR 当面验证,走入职流程来产生内网帐号,通过离职流程来注销帐号,也可以通过紧急报备来冻结特定帐号,或者解冻某个帐号。

不是总结的总结

目前想到了这些东西,我就先记录一下,分享给大家,当然真的做过这种系统的人,可能一眼看出来漏洞百出,还望不吝赐教,写出来也就是跟大家交流和学习的。谢谢了。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK