我的网络安全实践

序言

逛知乎的时候,看到一个问题“前端向后端提交用户名密码时如何加密?”看到这种问题,我脑子里首先想到的是"这样的设计,有过度设计之嫌。"工作近10年,大小网络安全事件也经历了几次,深刻感受到不同公司、不同业务场景,对网络安全的需求、投入差别之大,也超出很多外行的想象。
我想结合我所经历过的几个代表性网络安全场景,和大家聊一聊我的网络安全实践经验。

1、知己知彼有的放矢

回到文章开头所描述的问题。我并不是一锤子拍死所有这种设计,而是我曾多次见过这样的设计,通常无用。最常见的如在客户端将用户密码进行MD5 Hash,将Hash值进行传递。这样的设计就让我很迷惑,我很想问这样设计的程序员,做这样的“安全加固措施”究竟想防的是谁?我们回到问题的最初,如果不进行任何加密措施,实际面临的安全风险究竟在哪?
picture 1

由图可知问题中所提到的加密后传输主要想解决的问题是步骤1所面临的安全风险。这一步的安全风险在于用户名/密码在网络传输过程中被截获导致的安全问题,即中间人攻击。而我上文中所提到的密码Hash后再传输的方式解决了这一问题没有?

很显然,并没有!这样设计的本意在于即使被中间人劫持,也能避免中间人获取用户密码原文,仅能获取密码的Hash值。但对于攻击者而言,获取Hash值已然足够,因为后端验证的也是这个Hash值和用户信息中的Hash值是否匹配,对服务端而言,你的Hash值即密码本身。当攻击者截获到这一用户名/Hash值后,可以进行请求重放,从而顺利走通后续流程。我曾见过比这个复杂得多的请求加密手法,极少能通过防重放验证,导致最终加密工作几乎沦为无用功。退一步说,即使你做了很好的防重放机制,前端代码可是裸奔在浏览器的,“代码面前,了无秘密”。因为近两年工作需要面对大量模拟登录的场景,我也遇到过把防重放做得不错的站点,遇到这样的站点,我会打开开发者工具,定位到登录按钮点击事件代码,下个断点,慢慢跟踪,通常也就1个小时的工作量,就能摸清它的加密流程。我个人从不相信客户端安全,当你把你的代码交给用户后,用户总是有无数的办法摸清你的安全套路,年初我还通过逆向C++客户端拿到了某大厂坚决不给的数据库连接信息。反观一开始的问题,我也看到知乎上不少答主给出了我十分认同的答案:不用加密,上HTTPS即可。HTTPS近乎完美地解决了中间人攻击问题,比各种自定义加密真不知道高了多少个数量级。

而为什么会有很多人采用客户端加密这种方式来提升自以为的安全性?我觉得还是没有搞清楚自己所需要对抗的是什么。而这样的安全手段,往往无的放矢,大量开发资源投入到了毫无价值的工作当中去。说到这,我又不得不想起我曾遇到的另一个案例:密码如何保存。
现在稍微成熟的程序员都知道,密码不应该明文保存到数据库中,应该对密码进行Hash后再行存储,高阶一点的程序员会提出,不应该再用MD5进行Hash了,再高阶一点的会说,应该在Hash过程中进行加盐。这都很好,但是在这过程中,出现了一个分支:变形算法。很多人对其嗤之以鼻,我却对这一方法十分认可。

让我们利用第一性原理回溯问题:我们为什么不在数据库中保存明文密码呢?它所引发的安全风险究竟是什么?

我们担心被别有用心的人获取到我们的密码,并且通过这一密码获取到我们该站点账号甚至其他站点账号密码。那什么人算别有用心的人?

1) 系统入侵者

2) 缺乏职业操守的系统管理员

我们排除第二项,所谓“家贼难防”当内控机制失效,任何技术手段都很难规避风险。我们单讨论第一项:系统入侵者。前些年,SQL注入漏洞横行,大量系统被“脱裤”导致海量用户账号信息泄漏。当黑客获取到账号信息表后,便有可能获取到系统中的用户密码了。
那为什么说别再使用MD5进行Hash了呢?

1) 市面上存在巨量数据的MD5碰撞库

2) “王小云”博士证明了MD5的脆弱性

picture 2

可以看到,无论何种方法,都是基于MD5进行碰撞,而这也引出了我为什么认可“变形算法”,常见变形算法:MD5(MD5)打乱结果字符顺序(MD5),等等自由组合算法。从密码学的角度看,这确实没有加大密文的安全性,但是从工程的角度讲,我认为已经很大程度增加了安全性。

上图流程即用户密码写入数据库的流程,而攻击者拿到的是数据库中的数据,据我的经验来看,拿到数据较为容易,拿到程序代码的难度可一点都不小,这就导致获取变形算法的成本飙升。而根据上述Hash碰撞的方式看,如果在标准Hash算法下,第一种方法(也是市面上最常见的方法)获取相关碰撞数据成本低廉,但在Hash算法变形后,第一种方法几乎失效,就算获取到了程序代码,了解到了变形Hash算法,要重新构建那么巨大的密码库,成本也极其可观。反过来,就算你使用了标准安全的Hash算法,如SHA256,假如数据库数据泄漏,攻击者拥有对应的密码库后SHA256的安全性也并不比MD5的更高。

通过对攻击方式的了解,我们做出了相应的应对策略,这样有的放矢的系统安全构建行为,我认为是更可取的方法。

2、当下网络安全问题重灾区

在我长期工作经验来看,有一些网络安全重灾区是广泛存在的。多种因素共同作用下,造成行业内一些地方存在顽疾,很难根治。

2.1 服务器安全

服务器安全问题是一个很麻烦的存在。首先是职权问题,大多数小公司服务器都是让程序员兼职维护,程序员只需要保证系统平稳运行即可,据我观察大多数程序员是缺乏相关网络安全意识的。

另一方面是风险问题,我曾遇到过阿里云“一键修复漏洞”点击后,服务器拒绝服务,导致应用宕机。Windows服务器大多数安全补丁安装后,都要求重启服务器。很多小公司并没有相关容错冗余机制,这样的风险是难以承受的。

在缺少相关专业人员和技术保障的背景下,谁也不愿意去背负这样不可控的风险,所以我见过太多布满漏洞的服务器,这样的问题如需解决,需要机制保障,而这样的机制,是大多中小公司难以承受的成本之痛。

2.2 公众号、小程序安全

因为公众号、小程序相关应用通常都需要进行用户身份验证,而微信自带了相对完善的用户登录校验体系。导致很多人忽略了登陆后的用户数据安全问题。我曾见过通过微信登录后拿到用户OpenId,之后获取UserId,将UserId作为用户身份凭据进行进行业务开发。只需要简单抓包变更UserID参数即可模拟其他用户行为,获取其他用户数据。

也因为公众号、小程序隐藏了地址栏,浏览器访问通常也会被验证流程阻止,程序员设计时、测试人员测试时未多加关注,殊不知抓包工具面前,这些数据近乎“裸奔”。据我观察,前后端分离后,程序员对水平权限漏洞的关注程度更低,业务数据泄漏问题变得更加显著。

2.3 APP安全

随着Android 7以后,想要通过普通方法对APP进行抓包就变得越来越困难。导致很多程序员更加忽略接口安全这一问题。裸奔的APP接口何其多。殊不知,找一个低版本虚拟机或对系统进行部分Root后,各种APP的接口抓取即可变得十分简单便捷。由于这样的开发模式下,接口隐藏在APP操作逻辑后,普通测试很难找到接口安全验证操作入口,导致接口安全问题更加明显。

另外,随着前端开发能力日益强大,前端控制关键业务逻辑的问题也不再少见。随之而来的网络安全风险,大大增加,可谓增加了测试门槛却放纵了不安全接口的开发上线。

3、网络安全是一种意识

说了那么多网络安全问题,如何尽力保证我们产出的产品相对安全呢?我认为,网络安全是一种意识。

随着技术的演进,系统整体安全性比起过去有了很大的改善,危害性巨大的漏洞这些年也越来越少。但系统开发设计过程中出现的漏洞却变得越来越多。如我上面所说的安全漏洞,大多不是传统系统技术漏洞范畴,而是开发过程中,对业务逻辑、业务边界检查的缺失造成的漏洞。这样的漏洞具备特殊性,往往难以通过通用检测工具进行查找、识别。

面对这样的问题,需要对开发人员进行长期有针对性的教育,使其养成良好的网络安全意识习惯,在开发过程中有意识地对自己所设计的代码进行安全性核验。对基础设施(如各种中间件)的安全使用具备相关概念。
但这些工作,仔细想来,若要很好地开展起来,路漫漫其修远兮……

4、当下的网络安全困境

网络安全几乎是纯成本投入,对于大多数中小科技信息企业而言,网络安全投入是很难看见明显的收益的,产生增量收益更是近乎于天方夜谭。而对于个人而言,所谓善战者无赫赫之功,最好的安全构建即为没有任何安全事件发生,如何让领导感受到你的价值?这不是一个技术问题,所以曾有某网络安全大佬笑谈“白帽子黑客很容易做成绿帽子黑客”。

我见过很多领导,他们都说十分重视网络安全问题,甚至把网络安全问题放到头等重要的位置上。而落到行动上,顾及安全的系统研发,需要10天,不顾安全的系统研发,需要8天时,他们大多会毫不犹豫地选择后者。网络安全的成果,看不到,价值难以体现,造成了这一问题的整体困局。

如何推动网络安全?这是一个我无法回答的议题,每次和朋友聊到这个话题,我只能说等待行业慢慢交出足够多的学费吧。

我的微信公众号
我的公众号