想写无Bug的安全代码?看防御性编程的艺术

为什么开发者不编写安全的代码?我们在这并不是要再一次讨论「整洁代码」。我们要从纯粹的实用观点出发,讨论软件的安全性和保密性。是的,因为不安全的软件不仅无用,而且还可怕。我们来看看什么是不安全的软件。 1996年6月4日,欧洲航天局的 Ariane 5 Flight 501 在起飞后 40 秒被引爆。因为导航软件里的一个 bug,这个价值 10 亿美金的运载火箭不得不自毁。 1991年2月25日,MIM-104 Patriot(爱国者)里的一个软件错误使它的系统每一百小时有三分之一秒的时钟偏移,导致定位拦截入侵导弹失败。结果伊拉克的飞毛腿导弹击中宰赫兰(沙特阿拉伯东北部城市)的一个美军军营,28 人死亡,100 多人受伤。 其他案例,请参见《Bug 引发的 18 次重大事故》。 这应该能够说明编写安全软件的重要性了,尤其在特定的环境中。当然也包括其他用例中,我们也应该意识到我们的软件 bug 会导致什么后果。 防御性编程初窥 为什么我认为在特定种类的工程中,防御性编程是解决这些问题好办法? 抵御那些不可能的事,因为看似不可能的事也会发生。 防御性编程中有很多防御方式,这也取决于你的软件项目所需的「安全」级别和资源级别。 防御性编程是防御式设计的一种形式,用来确保软件在未知的环境中能继续运行。防御性编程的实践往往用于需要高可用性、安全性、保密性的地方。—— 维基百科 我个人相信这种方法适合很多人参与的大型、长期的项目。例如,一个需要大量维护的开源项目。 我们来探索一下我提出的关键点,来完成一个防御性编程的实现。 永远不要相信用户输入 设想你总是获取到你不想要的东西。因为像我们说过的,我们预期的是异常情况的出现,(所以)要时刻防备用户输入以及通常会传入你系统的东西,这是你成为一个防御性程序员的方法。试着做到尽可能的严格,确保输入的值就是你所期望的值。 进攻是最好的防守 设置白名单而不是黑名单。举个例子,当你验证图像扩展名时,不要检查非法的类型,而是检查合法的类型并排除其他类型。在 PHP 有无数的开源校验库可以让你的工作变简单。 进攻是最好的防守。共勉 数据库抽象化 在 OWASP Top 10 Security Vulnerabilities 排首位的是注入攻击。这意味着有些人(很多人)还没有使用安全的工具来查询数据库。请使用数据库抽象包或库。在 PHP 里你可以使用 PDO 来确保基本的注入攻击防范。 不要重复发明轮子 你不用框架(或微框架)吗?好吧恭喜你,你喜欢毫无理由地做额外的工作。这并不仅跟框架有关,也意味着你可以方便地使用已经存在的、经过测试的、受万千开发者信任的、稳定的新特性,而不是你只为了自己从中受益而制作的东西。你自己创建方法的唯一原因是你需要的东西不存在,或存在但不符合你的需求(性能差、缺失特性等等)。 这就是所谓的智能代码重用。拥抱它吧。 不要相信开发者 防御性编程与防御性驾驶相关联。在防御性驾驶中,我们假设周围的每个人都可能犯错。所以我们要留意别人的行为。相同概念也适用于防御性编程,我们作为开发者不要相信其他开发者的代码。我们同样也不要相信我们的代码。… Continue reading 想写无Bug的安全代码?看防御性编程的艺术

百亿互金平台救火故事

多年前,又是周六客服打电话过来,平台官网不能访问,app完全无法打开,客户在QQ群和微信群中各种反馈,说平台是不是跑路了?客服的多条400热线完全被打爆,电话已经接不过来… 前言 一直以来总是想以什么方式去记录下自己在互金行业的这段经历,趁着自己还记得清楚,还能找到一些资料原型,一方面可以分享出来供大家参考,但是更重要就是多年以后我可以根据这些文章回忆起来自己的那段激情岁月。 想了很久但一直没有实施,后来觉得应该从架构的角度来梳理一篇文章,就写《从零到百亿互联网金融架构发展史》这篇文章;最后认为只有实战出来的东西以及解决问题的过程,才是工作中最宝贵的经验,应该把它分享出来,在梳理的过程中觉得有三起事故比较有代表性就整理出了下面这三篇文章,本篇文章从整体来回忆一下一路走过来所经历过的救火故事。 一次生产事故的优化经历 一次 DNS 缓存引发的惨案 一个脚本引发的血案 作为一个互联网金融平台,涉及到用户资金,任何的服务(资金)差错用户都是不可容忍的,用户不懂什么是数据库,不知道什么网络不通,就是一会看不到钱在app里面展示都会觉得不安。在已经有很多P2P公司跑路的前提下,用户个个已经被锻炼成为福尔摩斯侦探,每天打开app查看收益,监控着平台一切,甚至半夜升级断网十分钟,也会被用户察觉,直接就发到群里面,更有甚者直接在QQ群或者微信群中你们的技术行不行! 我们常说的互联网工作经验,一方面是开发经验,但其实更重要的是处理问题的能力。那么处理问题的能力怎么来呢,就是不断的去解决问题,不断的去总结经验,其中处理生产环境中问题的经验更甚,因为在处理生产环境中对个人的压力和临危应变的能力要求最高,你不但需要面临千万个用户反馈,客服不时得催促而且旁边可能就站了N个领导在看着你,一副你行不行的样子要求立刻马上解决问题!这个时候你的操作就非常重要,稍有不慎便会引发二次生产事故。 说了这么多,只是想说明,生产事故对技术综合能力要求颇高,更是锻炼处理问题能力最佳时机!下面给大家介绍我们从零开发到现在百亿交易量所遇到的几次关键事故,有大有小挑出一些比较有代表性的事件来分享。 并发满标 公司系统刚上线的时候,其实没有经历过什么大量用户并发的考验,结果公司做了一个大的推广,涌入了一批用户来抢标,共1000万的标的几乎都在10秒之内搞定,大概会有上万左右的用户会同时去抢标,平均每秒大概有千人左右的并发,满标控制这块没有经过大的并发测试,上来之后就被打垮了,导致得结果是什么呢,1000万的标的,有可能到一千零几万满标,也有可能会九百多万就满标,也就说要不就是多了一些,要不就是少了一些,就满标了。 这就会很尴尬,因为借款用户就借款一千万整,那么多出来的钱既不能给用户退回了,因为用户好不容易才抢上了,无端退了用户也闹;少了也是问题,用户借款一千万,少了几十万也不行,如果短得少了可以想办法找一些有钱的客户直接给买了,多了就必须重新放出来让用户投资,非常影响士气,这个问题困扰了我们有一段时间。 购买标的流程图,不知道大家是否能根据此图发现问题呢? 超募 为何会产生超募?在最早前的版本中没有使用乐观锁来控制,如果在最后购买的用户一单出现并发,就会出现超募,比如最后剩余30000份的购买份额,因为并发量特别大,可能同时会有十几个用户拿到了剩余30000份余额的可购买额度,有的买1000份、有的买上3000份、有的买上20000份都会驱动满标,所以最后导致了超募。 针对这个问题,主要是引入了memcached乐观锁的概念(底层主要是cas、gets两个命令),在发标的时候存入标的总份额,当用户购买的时候首先去锁定用户购买的份额,因为乐观锁的原因,如果同时有两个用户拿到份额的时候保证只有一个最后可以更新成功(锁定份额),(锁定份额)失败直接返回,这样就保证了在入口的时候就直接屏蔽了部分并发的请求。 少募 为何产生少募?少募是可能1000万的标的突然到980万就给满标了,这是因为在超募情况下我们完善了代码,用户一进来首先就是锁定购买份额,只有锁定购买份额才能进行下面的流程,如果锁定购买份额失败直接返回,这样虽然保证了在1000万份额在购买初期必须每一个用户只能锁定一份,但是在高并发的情况下,因为购买流程中有十几个分支,每一个分支失败就会退回锁定的份额,这样就会导致这样的现象,就是可能是并发一上来,马上就满标了,过了一会进度就回退回来了。 少募主要是因为分支失败回退导致的,一方面我们分析了容易导致回退热点,因为在用户抢标的时候会给用户实时的展示标的进度,在很早的版本中直接就是存入到一个标的进度表里面,并且采用了乐观锁,如果并发一高就频繁的更新失败导致回退,因此优化了标的进度这块,直接去掉了标的进度表,实时根据查询来展示标的进度(可以有延迟,有缓存);另一方面在回退份额的时候在次判断试下memcached的份额和标的的状态,如果份额不为零并且标的状态是满标,马上自动更新状态保证后续用户可以立即购买再次驱动满标。 做了以上的两种优化后,我们还遇到了其它的一些小问题,在不断的优化过程中,终于稳定下来;在后期版本中将考虑使用MQ队列或者redis队列来处理抢标更合理对用户也更公平一些。 黑客攻击 2015年应该是互联网行业受黑客攻击最多的一年吧,各互金公司都深受其害,其中我就记得网贷之家有一段时间被黑客攻击的太厉害,连续几天网站都无法打开。当然了我们也未能幸免,什么DDOS攻击、SQL注入、寻找系统漏洞等都几乎都经历过了,有的黑客还比较好,应该是出于善意或者展示自己,将漏洞放到乌云上面或者漏洞盒子里面让厂商来修复。但更多的是一些黑产完全就是威胁、敲诈想捞一笔钱,先看看下面这位吧: 这个家伙潜伏到我们公司的客户群里面,冒充我们的客户代表将头像和资料替换成一样,然后给群里所有的客服让他们发送我们内部的后台地址,想通过这种方式来寻找突破口,当然了这个算是里面的小菜鸟吧。 DDOS攻击 DDOS攻击我们也是遇到了很多次,确实也没有比较好办法,最后都是通过一些笨办法来尽量的避免,先说说我们的经历吧。有一次我正在敲代码,客服QQ又闪烁了起来,还没来得及打开查看信息,客服的经理电话就直接打了过来,我立刻就有一种不祥的预感,说官网打不开了,后台也登录不了。 挂了电话,我在本机进行了测试果然不行,立刻准备登录VPN查看服务器各项指标,结果登录不上去,马上上楼找运维经理,他也登录不上,刚准备给机房打电话的时候,机房来电话了,说我们的一个IP正经历着1G多的流量访问,问我们是否正在做什么活动,刚话没有说完就说流量已经到5G,不到一分钟之后流量已经到达18G之多。因为我们的机房和集团公用了一个宽带入口,结果陆续的集团上面反馈他们的网站、服务也都出现了问题,机房方面害怕引起更大的冲击,直接把我们官网对外的IP封掉,集团的其它业务也才慢慢都恢复了过来,我们也紧急的更换了外网IP,重新切换了域名解析才恢复。 事后我们根据apache分析了日志,流量来自N多个不同的IP地址根本无法应对,也正式因为这次攻击也才让我们领导重视了起来,将我们公司的机房网络层和公司集团彻底分离,这样的话不管那方受到大流量攻击都不会相互影响,我们也想了一些笨办法,因为上次我们更换了外网IP之后攻击也就停止了,那么我们认为肯定是针对我们外网来攻击的,所有我们就多准备了6个外网IP,当监控到对某一个外网进行攻击的时候马上切换到另一个外网地址,就这样跟他们玩,可以起到非常有限的一点作用,如果黑客真的想跟我们玩,这个办法就像是小孩子捉迷藏。 周年庆的DDOS攻击 还有一次我们正在做周年庆活动,突然有人在QQ群里面给我们客服说了一句,叫你们的技术负责人来找我,然后我们的网站就挂了,我还保留了当时的一个截图如下: 完了之后客服就来找我,然后按照往常的策略处理完之后,我根据客服给我的QQ号码加上了那个人,开口就来吓我,我依稀记当年的对话如下: 黑客:你是平台的技术负责人吗? 我:算是吧 黑客:你信不信我可以让你们官网在5秒之内挂掉? 我:…(沉默,还真害怕又把官网搞挂了) 黑客:你们的官网漏洞很大 我:如果有好的建议请您赐教 黑客:你们的服务器是不是什么防护软件都没有装? 我:…(继续沉默,这会在想不会是那个安全厂商来推广产品的吧,当然我们基础的防护肯定有) 黑客:我们有非常多的肉鸡,想攻击谁,几秒之内肯定搞定 我:… 黑客:我们已经给很多互联网金融行业做了渗透测试,花点钱帮买你们平安,保证以后不会在出事情 我:… 黑客:免费的策略也有很多,比如360、百度云的安全产品可以免费低档10G左右的流量 ……(中间省略) 黑客:我说了这多,你们也是不是给包烟钱,表示表示。 …… 后来也和领导进行了商议,坚决不能给他们钱,不能助涨这种嚣张气焰,实在不行就报警! 曝光一下当年使用的假QQ号,刚查了下变了个头像和描述,如下: 后来我一直在想为什么DDOS攻击总是喜欢根据外网IP来攻击呢,慢慢好像是理解了如果针对域名来攻击的话,那不就是攻击到域名商的服务器了吗,一般域名商比较强大,黑客不太搞的定,也确实没有必要。当然记的前一段时间,某著名域名服务商被攻击,导致国外twitter等著名的互联网公司访问不断到达半天以上,还是很严重的。但是对于我们这些小公司,倒不至于搞这么大的动作。 到底如何正确的防止DDOS攻击: 第一种方案,隐藏服务器外网地址,服务器前端加CDN中转,免费的有百度云加速、360网站卫士、加速乐、安全宝等,如果资金充裕的话,可以购买高防的盾机,用于隐藏服务器真实IP,域名解析使用CDN的IP,所有解析的子域名都使用CDN的IP地址。此外,服务器上部署的其他域名也不能使用真实IP解析,全部都使用CDN来解析。 第二种方案,买一些安全产品来进行流量清洗,主要是阿里云、腾讯云这种大厂商提供的一种服务。… Continue reading 百亿互金平台救火故事