阅读笔记--互联网架构实践:给飞机换引擎和安全意识十原则

     在阅读文章以前,被文章标题所吸引,见过给车换引擎,还从没见过给飞机换引擎,因此对这篇文章很感兴趣,想了解飞机如何更换引擎。本身想象的飞机引擎应该很大很大,得几个成年人才抬得动,引擎上的器件必定特别坚固而精细,综合以上所想,给飞机更换引擎是个困难而复杂的工做。php

     经过阅读这篇文章得知换引擎要考虑不少事情:前端

所谓给飞行中的飞机(或飞驰的汽车)换引擎说的是咱们须要对一个正在飞速发展的系统进行大幅度的架构改造,好比把All-in-one的架构改形成微服务架构,尽量减小或消除停服的时间。通常而言,咱们能够这么来考虑方案,从重构的完全性来讲,分为这么几种:程序员

  • 完全从新作,直接从前到后抛弃老系统数据库

  • 大规模重构,保留对用户的这层皮,后面从服务到数据所有替换后端

  • 小规模重构,保留对用户的这层皮以及数据结构,逐一替换核心逻辑到微服务浏览器

在作换引擎方案选择和设计的时候须要考虑到这么几个现实的状况:缓存

  • 业务须要发展。意味着会不断有新需求须要开发,若是重构的时间拖的很长的话,咱们须要在这段很长的时间内为两套系统同时作新需求,新的系统还要不断开发新需求,会增长更多的时间,若是新系统的开发不够快的话,甚至一直上不了线。咱们最好在重构以前对新增业务有一条界限,新系统只是覆盖到这个版本作需求封板,而后和产品商量出一个妥协是否对于以后咱们留1周做为系统切换期,这段时间不上线新需求。这1周分红几个环节,须要2天的时间来作系统切换,而后须要5天的时间来观察新系统的稳定性,修复新系统的Bug,随后咱们才能认为系统正式切换成功,把时间精力放到新业务的开发上。安全

  • 数据须要迁移。咱们是为一个旧飞机在换引擎,没法抛弃飞机上的乘客。若是咱们更改数据结构的话,须要对数据进行迁移。咱们须要作下面的工做:网络

    • 准备迁移脚本数据结构

    • 准备缓存预热脚本

    • 使用既有的数据来测试这2个脚本,而后观察新系统的运行状况

    • 作反向数据迁移的脚本,咱们要考虑到切换到新系统后运行不流畅须要总体回滚的状况,这个时候咱们须要把数据重新的数据库迁移回老的数据库

这种方式的迁移是须要有短暂的停机的,两个脚本的执行和验证须要一段时间(数据量大的话导数据费时)。若是但愿尽量减小停机时间的话能够采用两段走的方式,先同步今天前的99.9%的数据到新数据库,在停机后再同步今天发生的那0.1%的数据。极端点但愿完全不停机的话,须要让业务同时走两套系统进行双写,这种方案大大增长复杂度,可是能够换来几乎0停机的时间,除非是须要24小时在线的金融系统,通常不会考虑新老系统双活的方案。

你可能会以为对于重构,咱们应该考虑不要改底层数据库,这会大大增长复杂性。这仍是取决于咱们但愿多完全进行重构,不少时候底层的数据库设计不够灵活这是最致命的,若是不切换到新的数据库,即便搞成了微服务架构数据仍是揉在一块儿,只是形态上是微服务,底层仍是乱七八糟,这堆业务代码最终仍是要进行一次重构。

  • 最好没有停机让用户没有感知。没有停机意味着老的系统一直在线上稳定运行,新的系统能够以独立的形态从新部署一套,用户对咱们新系统的开发没有感知。新老系统的面子能够长得如出一辙,可是底层的调用面目全非。因为两套系统都在线上运行,咱们能够在内部对新系统进行充分测试,还能够比较一样的业务流程在数据呈现上是否有差别。惋惜现实每每没有想象的这么简单,不少时候咱们会依赖各类三方数据,对于金融系统来讲每每对接了银行的系统,这不是依赖这么简单了,而是完彻底全的依赖。若是咱们依赖的第三方会受到咱们重构的影响,或是咱们就是在切换依赖方的话,是否停机就不是本身能够掌控的了,第三方须要有停机咱们就只能停机。这个时候咱们能作的是,让网站进行部分功能的停机而不是总体停机,用户能够以只读形式使用网站的全部功能,可是不能作写入操做,待三方系统切换完成后切换到新系统了才能使用全部功能,这样用户也会有安全感。

  • 万一迁移失败怎么办。以前说了咱们迁移数据须要考虑回滚方案,这里还会有一些比较恶心的点是若是新老系统有一些内部外部依赖是公用的话,尽可能要隔离清楚,让新老系统完全独立,这样才好回滚,若是迁移后新系统在跑了污染了老系统的数据,这个时候再要回滚会出现回不去的状况,由于老系统没法适应新的数据。内部要进行完全的隔离是比较简单,对于三方的数据(好比CDN)咱们也要考虑到数据在边缘节点和用户端缓存的状况,在设计方案的时候就要考虑到切换后回退的可能性,尽量让两套系统使用独立的数据不要产生数据覆盖的状况形成污染。

仍是要具体的事情具体来分析,要给飞行中的飞机换引擎,最重要的就是:

  • 获得产品方面的配合对需求作好锁定;

  • 在开发过程当中对新系统作好充分测试减小上线后修Bug的工做量;

  • 对迁移方案以及回滚方案作好自动化的脚本以及充分的验证。

安全知识十则

一、安全问题是木桶效应。整个系统的安全程度取决于木桶最短的那块板。不少时候咱们会召集安全专家和架构师和主站主流程主域名的系统进行安全分析和渗透测试,而黑客知道这点也每每喜欢找边缘化的子站点或非核心逻辑进行攻破,这些模块或站点每每是由初级程序员打造,有的甚至还不是主站统一的技术架构,整体上会防备薄弱。黑客可以攻破任意站点进去到内网,就有种种可能。针对这点,咱们须要作的是对于安全的排查,须要全面覆盖,除非子站在部署上用户体系上完全隔离。

二、开发层面:不要信任客户端的任何东西。对于HTTP协议,无论是头里面的东西(来源、客户端类型、Cookie)仍是正文里面的东西,任何数据都是能够伪造的。咱们每每会以为Get的东西暴露在浏览器地址上,里面的参数不安全,Post过来的数据由于不暴露就安全,而后会信任Cookie中的数据作一些权限控制,会用头里面的一些数据作一些安全性控制。这些不是说不能作,而是要从根子里面有这个意识全部客户端的东西能够用但不能不通过判断直接相信。有一个容易犯的错误是,在设计Controller的时候咱们可能会在参数里让客户端传过来UserID、Price等信息。这里的问题在于,登陆后的UserID应该是保存在服务端的,客户是谁不是客户本身说了算的,应该是咱们根据SessionID在服务端得到的,咱们须要全面排查代码,不容许在Controller的方法里存在相似于用户ID这样的字段。

对于Price也是同样的道理,若是这是一个购物的过程,那么订单的价格必定是在服务端计算的,咱们只能依靠客户端传过来的ItemID来计算价格,不能相信和直接使用客户端传过来的价格入库(仅仅做为呈现是能够的,客户端来的仍是呈如今客户端,可是不能用于计算)。其实更麻烦的是,不少时候咱们会用框架生成的Controller的CRUD接口的代码,框架会在参数内直接放上完整的Entity,而后代码里会使用这个Entity直接对接数据访问层入库,由于客户端和服务端用JSON在通信,虽然咱们看到客户端传给服务端的只是ItemID,可是你再传一个Price确实也是能够生效进入Update语句入库的(Entity某些字段为空那么就不会进入Update语句,不为空就会更新)。

三、开发层面:数据就是数据代码就是代码。无论是SQL注入也好XSS也好都是这个问题,把数据和代码混在了一块儿。对于客户端过来的任何信息应该都只是数据,应该不多会让客户端来告诉服务端执行的代码。因此这个事情咱们要从两方面来防范,第一客户端过来的数据须要让它当成数据来处理,无论是Encoding一下也好,SQL参数化(Mybatis的$和#问题)也好都是这个方面的措施(从前到后一路数据都以数据的身份在程序中流转),第二从数据库里出来的东西也只能是数据不能让它变为HTML或JS代码,也须要Encoding一次再在客户端上呈现。SQL注入的防范不少人喜欢用敏感字符替换的方式来作,这种作法实际上是会有遗留的,咱们不该该去考虑排除数据中有代码的可能性,而是应该从根源上去让数据只可能成为数据。

四、开发层面:用户看不到不等于黑客看不到。第一个方面想说的是,随着先后端的分离,如今不少请求都是AJAX请求,AJAX请求会有几方面的安全疏漏:

  • 逻辑分散而明确。对于服务端渲染,咱们会把各类逻辑整合在一块儿,用户看到的是一个完整的渲染后的页面不清楚里面有多少逻辑,对于AJAX请求,咱们会以良好的方法命名来命名各类API。这个时候会给黑客可乘之机,会更容易分析理解程序运行的流程,毕竟在寻找突破以前须要先理解程序的流程。

  • 容易以为AJAX请求是前端程序发起的而忽略权限问题。没错,AJAX的发起人也是咱们的代码,可是AJAX请求也是HTTP请求谁均可以发起。若是咱们对AJAX请求的参数设计有所松懈,犯了以前说的两个错的话那就很危险了。特别是先后端都是一我的来写的话,程序员在实现代码逻辑的时候每每只会考虑数据的传输简单通畅,后端给前端,前端再给后端放松安全意识。

五、开发层面:最小化接口权限设计复用性矛盾。在作设计的时候咱们会考虑到复用性的问题让方法尽量通用,可是对于对外的接口咱们要尽可能收缩功能。举一个以前看到的例子,咱们须要验证游戏的密保卡,须要用户告知三个坐标的密保数字,好比A1B2C3三个坐标,每个数字是0到99,三个数字同时猜对的可能性是百万分之一,可是接口的设计竟然是直接让用户传三个坐标,这里有两个严重的设计错误:

  • 第一,为何是容许客户端传过来三个密保的位置,合理的作法是服务端告知客户端这次校验的ID,而后客户端传过来ID,服务端在Session或缓存中去获取坐标位置。

  • 第二,接口容许传三个坐标也算了,还容许是相同的坐标,咱们彻底能够改造接口传A1A1A1而后依次暴力破解0到99,立刻就能够得出A1坐标的值,几秒的时间就能够把整个密保卡彻底暴破出来。

在设计服务端接口的时候,咱们最好针对某个功能设计最小的接口,而不是开放的通用的接口,对外的接口设计安全性须要大于重用性。

六、开发层面:一开始就要考虑安全,放出去了就没后悔药。比较无奈的是,不少项目咱们处于赶进度,一开始初版的时候并无对接口作加密和签名验证。若是作的是一个APP,那么咱们要考虑到APP用户不升级的状况,即便v2的版本的数据都是加密的,参数都是验签的,可是咱们还不能下架v1版本(强更会损失多少用户难以估计)。这个时候就比较无奈了,明知道v1版本的安全性有着很大的风险却不能升级。不只仅是接口的安全性,安卓客户端的代码也要考虑到反编译的可能性须要混淆。以前遇到过有一个App客户端里网络层直接使用了服务端的接口定义,致使客户端代码里能够对服务端全部接口一清二楚,还不乏一些不能对外使用的内部接口以及已经淘汰的老接口,加上接口的调用又没有签名数据传输又不加密,拿着这份网络协议什么均可以干。

七、产品层面:作好防刷和暴力破解控制。显性的功能当然重要,可是产品经理也须要在隐性功能和风控策略上下一些功夫,产品经理没有这方面意识的话开发每每更不太会作深刻考虑。包括:

  • 公开出去的短信验证码服务防刷控制(防止被刷子利用作短信轰炸),在用户体验和防刷上作平衡,好比到达必定的频次后出验证码,服务端对客户端的一些头作校验(刷子通常不知道这样的逻辑)等等。不只仅是短信验证码,公开出去的不须要受权就能够用的服务都须要防刷。

  • 登陆是用户从匿名进入受权的重要环节,对这一环节作一些策略。好比异地登陆提醒、错误登陆后出验证码、太屡次错误后禁用等等。

  • 涉及到积分、兑换、返现、抽奖这种和钱打交道的业务,要多考虑是否会有刷的可能,不只仅是程序逻辑方面的漏洞,惟一性的判断,还要考虑积分流通起来后是否会有撸羊毛小换大的可能。有利益的地方就有羊毛,若是一个业务都是羊毛在参与的话那么帐面数据可能挺好看,但实际上几乎带来不了忠实的有留存的用户。

重要的业务须要有风控方面的产品经理和业务产品经理一块儿来参与,共同讨论流程,防羊毛,防黑客, 防刷子。

八、产品层面:注意产品逻辑一体性。不少业务流程是受权-执行这样的两步,但有些时候这两步在产品设计的时候并不必定是同一个产品经理在设计,会出现受权和执行不一致的状况。见过一个修改绑定邮箱的产品逻辑,用户在页面X先进行短信验证码验证,而后就能够跳转到Y页面进行修改绑定邮箱,X页面是通用的短信验证页面,Y是新的修改绑定邮箱的需求,这里出现一个逻辑漏洞,就是在X页面验证完成后进入Y页面,若是这个时候利用另一个TAB退登登陆切换用户后,在Y页面仍是能够修改绑定邮箱的,这个时候程序从Session中读取的到用户并非以前那个经过短信验证的用户,而是后面登陆的新用户,至关于咱们就能够为任意用户修改绑定邮箱了。对于多步走的逻辑,咱们必定要做为一个总体来思考。黑客在寻找突破的时候特别喜欢寻找ABC几步走的逻辑,而后尝试最后一步C是否能够单独来作寻找逻辑方面的漏洞。

九、运维层面:作好异常数据监控报警。在运营层面,咱们须要对方方面面的数据有报表或监控,对于异常的数据徒增及时进行调查,业务量的增长若是不伴随活动或推广的话不必定是好事情。在运维层面,咱们一样也须要对网络磁盘的使用徒增以及服务的调用量上升查明缘由,看看这是业务致使的仍是多是安全性问题。对于各类三方服务(好比短信通道、CDN、文件存储等)的使用,最好也有日报级别的监控,以避免看到月度的帐单后再发现被刷的问题哭都来不及。

十、运维层面:对内的数据和权限问题。咱们说内部人是最难防的,内部系统繁杂,受权和审计作的可能不那么完善,内部人员若是有心的话获取一些数据作一些坏事形成的影响会比较大,咱们须要从几方面来作一些措施:

  • 线上的配置尽可能加密,配置信息和代码分离

  • 敏感数据(用户信息)在数据库中加密保存

  • 线上数据访问须要使用相似于phpmyadmin的Web网站,不容许使用客户端工具,这样能够作比较健全的受权,防止数据导出

  • 内部系统涉及到用户信息部分脱敏显示,显示完整的数据须要上级受权

  • 全部内部系统的登陆和使用须要有完整的日志,对日志进行分析和按期的审计

 总结:经过阅读这篇文章,我了解到安全性的重要性涉及到开发层面,产品层面,运维层面以及应对这些安全性问题得解决办法。让我在之后的产品开发过程当中更加的有经验,少范错误。

相关文章
相关标签/搜索