架构师训练营第十一周总结
本周的课程内容中, 老师在两次直播课程中分享了安全架构和高可用架构的知识。
关键知识点
安全架构
常见的系统攻击方法
XSS 攻击
XSS 攻击即跨站点脚本攻击,攻击者构造恶意的浏览器脚本文件,使其在其他用户的浏览器上运行,进而进行攻击
XSS 攻击防御的主要手段是消毒,检查用户提交的请求中是否含有可执行的脚本,因为大部分的攻击请求都包含 JS 等脚本语法,所以可以通过 HTML 转义的方式,对比较有危险的脚本语法关键字进行转义。比如把“>”转义为“>”,HTML 显示的时候还是正常的“>”,但是这样的脚本无法在浏览器上执行,也就无法达到攻击的目的。由于 HTTP 攻击必须以 HTTP 请求的方式提交到服务器,因此可以在服务器的入口统一进行拦截,对含有危险信息的请求,比如 drop table,JS 脚本等,进行消毒转义,或者直接拒绝请求。即设置一个 Web 应用防火墙,将危险请求隔离。
SQL 注入攻击
SQL 注入攻击就是攻击者在提交的请求参数里面,包含有恶意的 SQL 脚本。
SQL 注入最有效的防攻击手段是 SQL 预编译。Java 开发的话最好使用 PrepareStatement 提交 SQL,而 MyBatis 等 ORM 框架主要的 SQL 提交方式就是用 PrepareStatement。
CSRF 攻击
CSRF 是跨站请求伪造(Cross-site request forgery)的简写。 CSRF 攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。
CSRF 攻击的防御手段:
表单 Token: CSRF 是一个伪造用户请求的操作, 所以需要构造用户请求的所有参数才可以。表单 Token 就是阻止攻击者获取所有请求参数的可能,在页面表单中增加一个随机数 Token,每次请求的 Token 都不同,客户端将表单中的信息提交到服务端通过校验 Token 的合法性来验证请求是否合法。
验证码:相对来说,验证码的方式更加简单高效,即请求提交时,需要用户输入验证码,以避免用户在不知情的情况下被攻击者伪造请求。但是输入验证码是一个糟糕的用户体验,所以必要的时候才使用,如支付交易等关键页面。
Referer Check: HTTP 请求头中的 referer 域中记录着请求来源, 可通过检查请求来源校验其是否合法。但是该方法有一些局限性,referer 也并不一定总能得到。
其他需要关注的攻击和漏洞
Error Code: 也称做错误回显, 许多 Web 服务器默认是打开异常信息输出的, 即服务器端未处理的异常堆栈信息会直接输出到客户端浏览器,这种方式虽然对程序调试和错误报告有好处,但是同时也给了黑客可乘之机。通过故意制造非法输入,使系统运行时出错,获得异常信息,从而寻找系统漏洞进行攻击。
防御手段也很简单,通过配置 Web 服务器参数,跳转到特定的异常页面即可。
HTML 注释:为了程序调试方便或其他不恰当的原因,有的时候程序开发人员会在 PHP、JSP 等服务器页面程序中适用 HTML 注释语法进行程序注释,这些 HTML 注释会显示在客户端浏览器,给黑客造成攻击便利。程序最终发布前需要进行代码 Review 或自动扫描,避免 HTML 注释漏洞。
文件上传:一般网站都会有文件上传功能,设置头像、分享视频、上传附件等。如果上传的是可执行程序,并通过该程序获得服务器端命令执行能力,那么攻击者几乎可以在服务器上为所欲为, 并以此为跳板攻击集群环境的其他机器。最有效的防御手段是设置上传文件白名单,只允许上传可靠的文件类型。此外还可以修改文件名、适用专门储存等手段,保护服务器免受上传文件攻击。
路径遍历:攻击者在请求的 URL 中使用相对路径,遍历系统未开放的目录和文件。防御方法主要是将 JavaScript、css 等资源文件独立服务器存储、独立域名访问,其他文件不使用静态 URL 访问,动态参数不包含文件路径信息。
安全防护的手段
Web 应用防火墙
Web应用防护墙(Web Application Firewall,简称WAF)是通过执行一系列针对HTTP/HTTPS的安全策略来专门为Web应用提供保护的一款产品,主要用于防御针对网络应用层的攻击,像SQL注入、跨站脚本攻击、参数篡改、应用平台漏洞攻击、拒绝服务攻击等。
ModSecurity 是一个开源的 Web 应用防火墙, 探测攻击并保护 Web 应用程序, 既可以嵌入到 Web 应用服务器中, 也可以作为一个独立的应用启动。ModSecurity 最早只是 Apache 的一个模块, 现在已经有 Java、.Net 等多个版本, 并且支持 Nginx。ModSecurity 采用处理逻辑与规则集合分离的架构模式。处理逻辑负责请求和响应的拦截过滤,规则加载执行等功能。而规则集合则负责对具体的攻击规则定义、模式识别、防御策略等功能。处理逻辑比较稳定,规则集合需要不断针对漏洞进行升级,这是一种可扩展的架构设计。
网站安全漏洞扫描
和电脑安全漏洞扫描一样,网站也需要安全漏洞扫描。网站安全漏洞扫描工具是根据内置规则,模拟黑客攻击行为,用以发现网站安全漏洞的工具。
信息加密
为了保护网站的敏感信息,防止这些关键信息被黑客 "拖库", 应用系统需要对敏感信息进行加密处理, 信息加密可以分为三类: 单向散列加密, 对称加密, 非对称加密。
单向散列加密
单向散列加密是指对一串明文信息进行散列(hash)加密,得到的密文信息是不可以被解密的,也就是说给定一个密文,即使是加密者也无法知道它的明文是什么的,加密是单向的,不支持解密。
单向散列加密事实上是一种 hash 算法。MD5 算法就是一种单向散列加密算法,单向散列算法虽然无法通过对密文进行解密计算,还原得到原始明文。但是,如果知道了算法,就可以通过彩虹表的方法进行破解。彩虹表是常用明文和密文的映射表,很多人喜欢用生日做密码,其实生日的组合是非常有限的,轻易就可以建一个生日和密文的映射表。如果黑客得到了密文,可以通过查表的办法得到密码明文。因此在实践中,使用单向散列算法加密,还需要在计算过程中加点“盐”salt,如果黑客不知道加的“盐”是什么,就无法建立彩虹表,还原得到明文。单向散列加密的主要应用场景就是应用到用户密码加密上。用户在注册的时候需要输入密码,应用服务器得到密码以后,调用单向散列加密算法,对密码进行加密,然后将加密后的密文存储到数据库中去。用户下一次登录的时候,在客户端依然需要输入密码,而用户输入的密码发送到 Web 服务器以后,Web 服务器对输入的密码再进行一次单向散列加密,得到密文,然后和从数据库中取出来的密文进行对比,如果两个密文是相同的,那么用户的登录验证就是成功的。通过这种手段,可以保证用户密码的安全性,即使数据库被黑客拖库,也不会泄漏用户密码。密码加密的时候也需要加点“盐”,这种场景下,每个用户加密的“盐”都可以不同,比如用用户的 ID 作为盐,这样可以增加破解的难度。
对称加密
对称加密,顾名思义,就是使用一个加密算法和一个密钥,对一段明文进行加密以后得到密文,然后使用相同的密钥和对应的解密算法,对密文进行解密,就可以计算得到明文。对称加密主要用于加密一些敏感信息,对密文进行信息传输和存储,但是在使用的时候,必须要解密得到明文信息的一些场景。
非对称加密
所谓的非对称加密是指在加密的时候使用一个加密算法和一个加密密钥进行加密,得到一个密文。在解密的时候,必须使用解密算法和解密密钥进行解密才能够还原得到明文,加密密钥和解密密钥完全不同。通常加密密钥被称作公钥,解密密钥被称作私钥。非对称加密的典型应用场景,就是我们常见的 HTTPS。用户在客户端进行网络通讯的时候,对数据使用加密密钥即公钥和加密算法进行加密,得到密文。到了数据中心的服务器以后,使用解密密钥即私钥和解密算法进行解密,得到明文。由于非对称加密需要消耗的计算资源比较多,效率也比较差,HTTPS 并不是每次请求响应都用非对称加密,而是先利用非对称加密,在客户端和服务器之间交换一个对称加密的密钥,然后每次请求响应都用对称加密。这样,用非对称加密保证对称加密密钥的安全,再用对称加密密钥保证请求响应数据的安全。
电子商务风险控制
电子商务网站在给人们代理购物交易的极大便利的同时, 也将风险带给了网络安全一无所知的人们。由于买卖双方的信息不对等,交易本来就存在风险,而当交易在网上发生的时候,买卖双方彼此一无所知,交易风险也就更加难以控制。
电子商务具有多种形式,B2B,B2C, C2C 每种交易的场景都不相同, 风险也各有特点, 大致可分为以下几种:
账户风险: 包括账户被黑客盗用, 恶意注册账号等几种情形。
买家风险:买家恶意下单占用库存进行不正当竞争;黄牛利用促销规则抢购低价商品;此外还有良品拒收,欺诈退款以及常见于 B2B 交易的虚假询盘等。
卖家风险:不良卖家进行恶意欺诈的行为,例如货不对板,虚假发货,炒作信用等,此外还有发布违禁商品、侵权产品等。
交易风险:信用卡盗刷,支付欺诈,洗钱套现等。
大型电商网站都配备有专门的风控团队进行风险控制,风控的手段也包括自动和人工两种方式。机器自动识别为高风险的交易和信息会发送给风险审核人员进行人工审核,机器自动风控的技术和方法也不断通过人工发现的新风险类型进行逐步完善。机器自动风控的技术手段主要有规则引擎和机器学习。
高可用架构
可用性指标
业界通常用多少个 9 来说明互联网应用的可用性。
网站年度可用性指标 = ( 1 - 网站不可用时间/年度总时间 ) x 100%
网站不可用时间(故障时间) = 故障修复时间点 - 故障发现 (报告) 时间点
对可用性的定性描述, 两个 9 是基本可用, 年度停机时间小于 88 小时; 3 个 9 较高可用, 年度停机时间小于 9 小时; 4 个 9 是具有自动恢复能力的高可用, 年度停机时间小于 53 分钟; 5 个 9 是极高可用性, 年度停机时间小于 5 分钟。由于可用性影响因素很多,对于网站整体而言,达到 4 个 9,乃至 5 个 9 的可用性,除了过硬的技术、大量的设备资金投入和工程师的责任心,还要有个好运气。
引起故障的原因
硬件故障
软件 BUG
系统发布
并发压力
网络攻击
外部灾害
解耦
高内聚、低耦合的组件设计原则
面向对象基本设计原则
面向对象设计模式
领域驱动设计建模
隔离
业务与子系统隔离
微服务与中台架构
生产者消费者隔离
虚拟机与容器隔离
异步
多线程编程
反应式编程
异步通信网络编程
事件驱动异步模型
备份
集群设计
数据库复制
CAP 原理
BASE 理论
Failover (失效转移)
失效转移包括数据库主主失效转移, 负载均衡失效转移
如何确认失效, 需要转移?
数据库主主失效转移, 引入 Zookeeper 进行应用操作主库的选举
负载均衡失效转移, 设置负载均衡器的健康检查机制, 当服务不正常时, 将服务从负载均衡集群中移除
幂等
应用调用服务失败后, 会将调用请求重新发送到其他服务器, 但是这个失败可能时虚假的失败。比如服务已经处理成功,但是因为网络故障应用没有收到响应,这是应用重新提交请求就导致服务重复调用,如果这个服务是一个转账操作,就会产生严重的后果。
服务重复调用有时候是无法避免的,必须保证服务重复调用和调用一次产生的结果相同,即服务具有幂等性。有些服务天然具有幂等性,比如将用户性别设置为男性,不关设置多少次,结果都一样。但是对于交易等操作,问题就会比较复杂,需要通过交易编号等信息进行服务调用有效性校验,只有有效的操作才继续执行。
事务补偿
传统事务的 ACID:原子性(Atomic)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)
分布式事务的 BASE: 基本可用 (Basic Availability)、软状态(Soft-state)、最终一致性(Eventual consistency)
事务补偿:通过执行业务逻辑逆操作,使事务回滚到事务前状态
重试
远程服务可能会由于线程阻塞、垃圾回收或者网络抖动,而无法及时返回响应,调用者可以通过重试的方式修复单次调用的故障。
上游调用者超时时间要大于下游调用者超时时间之和。
熔断
当某个服务出现故障时, 响应延迟或者失败率增加, 继续调用这个服务会导致调用者请求阻塞, 资源消耗增加, 进而出现服务级联失效, 这种情况下使用断路器阻断对故障服务的调用。
断路器三种状态: 关闭, 打开, 半开
Spring Cloud 断路器实现: Hystrix
限流
在高并发场景下, 如果系统的访问量超过了系统的承受能力, 可以通过限流对系统进行保护。限流是指对进入系统的用户请求进行流量限制,如果访问量超过了系统的最大处理能力,就会丢弃一部分的用户请求,保证整个系统可用,保证大部分用户是可以访问系统的。这样虽然有一部分用户的请求被丢弃,产生了部分不可用,但还是好过整个系统崩溃,所有的用户都不可用要好。
限流的几种算法:
计数器算法(固定窗口,滑动窗口)
计数器(固定窗口)算法使用计算器在周期内累加访问次数,当达到设定的限流阈值时,触发限流策略。下一个周期开始时,进行清零,重新计数。
固定窗口算法的临界点问题:假设 1min 内服务器的负载能力为 100, 因此一个周期的访问量限制在 100, 然而在第一个周期的最后 5 秒和下一个周期的开始 5 秒时间段内, 分别涌入 100 的访问量, 虽然没有超过每个周期的限制量, 但是整体上 10 秒内已到达 200 的访问量, 已远远超过服务器的负载能力。
计数器(滑动窗口)算法将时间周期分为 N 个小周期,分别记录每个小周期内访问次数,并且根据时间滑动删除过期的小周期。这个算法也有周期临界点问题。
令牌桶算法
以固定的速度向令牌桶中增加令牌,直到令牌桶满,请求到达时向令牌桶请求令牌,如获取到令牌则通过请求,否则出发限流策略。
漏桶算法
访问请求到达时直接放入漏桶,如当前容量已达到限流值,则进行丢弃。漏桶以固定的速率进行释放访问请求,直到漏桶为空。
自适应限流
实时自动评估系统的 QPS, 根据系统的负载限流进行限流阈值的调整。
降级
有一些系统功能时非核心的,但是它也给系统产生了非常大的压力,比如说在电商系统中有确认收货这个功能,即便我们不去确认收货,系统也会超时自动确认收货。但实际上确认收货这个操作是一个非常重的操作,因为它会对数据库产生很大的压力:它要更改订单状态,完成支付确认,并进行评价等一系列操作。如果在系统高并发的时候去完成这些操作,那么会对已经高负荷运行的系统继续加压。解决办法就是在系统高并发的时候将非核心的功能降级,将宝贵的系统资源留给核心的功能。
异地多活
如果整个数据中心都不可用,比如说数据中心所在的城市遭遇了地震,机房遭遇了火灾或者停电,这样的话不管我们的设计和系统多么的高可用,系统依然是不可用的。
为了解决这个问题,同时也为了提高系统的处理能力和改善用户体验,很多大型互联网应用都采用了异地多机房架构策略,也就是说将数据中心分布在多个不同地点的机房里,这些机房都可以对外提供服务,用户可以连接任何一个机房进行访问,这样每个机房就可以提供完整的系统服务,即时某一个机房不可使用,系统也不会宕机,依然保持可用。异地多活架构的难点是数据一致性问题。
总结
这周的课程内容主要在分布式系统设计的可用性和安全性方面的知识做了讲解,和前面几周课程讲解的分布式系统设计相关的知识点相关,进一步加深了对分布式系统设计的理解。
评论