极客大学架构师训练营 组件设计原则 安全架构 防火墙 ModSecurity 第 21 课 听课总结

用户头像
John(易筋)
关注
发布于: 2020 年 08 月 13 日

说明

讲师:李智慧



组件设计原则

在没有编程语言的时候就已经有了软件组件。

软件的复杂度和它的规模成指数关系

一个复杂度为 100 的软件系统,如果能拆分成两个互不相关、同等规模的子系统,那么每个子系统的复杂度应该是25,而不是50.软件开发这个行业很久之前就形成了一个共识,应该将复杂的软件系统进行拆分,拆成多个更低复杂度的子系统,子系统还可以继续拆分成更小粒度的组件。也就是说,软件需要进行模块化、组件化设计。



组件内聚原则

组件内聚原则主要讨论哪些类应该聚合在同一个组件中,以便组件既能提供相对完整的功能,又不至于太过庞大。



  • 复用发布等同原则;

  • 共同封闭原则;

  • 共同复用原则。



复用发布等同原则

复用发布等同原则是说,软件复用的最小粒度应该等同于其发布的最小粒度。也就是说,如果你希望别人以怎样的粒度复用你的软件,你就应该以怎样的粒度发布你的软件。这其实就是组件的定义了,组件是软件复用和发布的最小粒度软件单元。这个粒度既是复用的粒度,也是发布的粒度。



版本号约定建议:

  • 版本号格式:主版本号.次版本号.修订号。比如 1.3.12,在这个版本号中,主版本号是1, 次版本号是3, 修订号是 12.

  • 主版本号升级,表示组件发生了不向前兼容的重大修订;

  • 次版本号升级,表示组件进行了重要的功能修订或者 bug 修复,但是组件是向前兼容的;

  • 修订号升级,表示组件进行了不重要的功能修订或者 bug 修复。



共同封闭原则

共同封闭原则是说,我们应该将那些会同时修改,并且为了相同目的而修改的类放到同一个组件中。而将不会同时修改,并且不会为了相同目的而修改的类放到不同的组件中。



组件的目的虽然是为了复用,然而开发中常常引发问题的,恰恰在于组件本身的可维护性。如果组件在自己的生命周期中必须经历各种变更,那么最好不要涉及其它组件,相关的变更都在同一个组件中。这样,当变更发生的时候,只需要重新发布这个组件就可以了,而不是一大堆组件都受到牵连。



共同复用原则

共同复用原则是说,不要强迫一个组件的用户依赖他们不需要的东西。



这个原则一方面是说,我们应该互相依赖,共同复用的类放在一个组件中。比如说,一个数据结构容器组件,提供数组、Hash 表等各种数据结构容器,那么对数据结构遍历的类、排序的类也应该放在这个组件中,以使这个组件中的类共同对外提供服务。



另一方面,这个原则也说明,如果不是被共同依赖的类,就不应该放在一个组件中。如果不被依赖的类发生变更,就会引起组件变更,进而引起使用组件的程序发生变更。这样就会导致组件的使用者产生不必要的困扰,甚至讨厌使用这样的组件,也造成了组件复用的困难。

组件耦合原则 (强原则,架构师必须要守住)

组件内聚原则讨论的是组件应该包含哪些功能和类,而组件耦合原则讨论组件之间的耦合关系应该如何设计。



  • 无循环依赖原则;

  • 稳定依赖原则;

  • 稳定抽象原则。

无循环依赖原则

无循环依赖原则说,组件依赖关系中不应该出现环。如果组件 A 依赖组件 B,组件 B 依赖组件 C,组件 C 又依赖组件 A,就形成了循环依赖。



很多时候,循环依赖是在组件的变更过程中逐渐形成的,组件 A 版本 1.0 依赖组件 B 版本 1.0,后来组件 B 升级到 1.1, 升级的某个功能依赖组件 A 的 1.0 版本,于是形成了循环依赖。如果组件设计的边界不清晰,组件开发设计缺乏评审,开发者只关注自己开发的组件,整个项目对组件依赖管理没有统一的规则,很有可能出现循环依赖。



稳定依赖原则

稳定依赖原则是说,组件依赖关系必须指向更稳定的方向。较少变更的组件是稳定的,也就是说,经常变更的组件是不稳定的。根据稳定依赖原则,不稳定的组件应该依赖稳定的组件,而不是反过来。



反过来说,如果一个组件被更多组件依赖,那么它需要相对是稳定的,因为想要变更一个被很多组件依赖的组件,本身就是一件困难的事。相对应的,如果一个组件依赖了很多的组件,那么它相对也是不稳定的,因为它依赖的任何组件变更,都可能导致自己的变更。



稳定依赖原则通俗地说就是,组件不应该依赖一个比自己还不稳定的组件。



稳定抽象原则

稳定抽象原则是说,一个组件的抽象化程度应该与其稳定性程度一致。也就是说,一个稳定的组件应该是抽象的,而不稳定的组件应该是具体的。



这个原则对具体开发的指导意义就是:如果你设计的组件是具体的、不稳定的,那么可以为这个组件对外提供服务的类设计一组接口,并把这组接口封装在一个专门的组件中,那么这个组件相对就比较抽象、稳定。



Java 中的 JDBC 就是这样一个例子,我们开发应用程序的时候只需要使用 JDBC 的接口编程就可以了。而发布应用的时候,我们制定具体的实现组件,可以是 MySQL 实现的 JDBC 组件,也可以是 Oracle 实现的 JDBC 组件。



组件的边界与依赖关系,不仅仅是技术问题

组件的边界与依赖关系划分,不仅需要考虑技术问题,也要考虑业务场景问题。易变与稳定,依赖与被依赖,都需要放在业务场景中去考察。有的时候,甚至不只是技术业务的问题,还需要考虑人的问题,在一个复杂的组织中,组件的依赖与设计需要考虑人的因素。如果组件的功能划分涉及部门的职责边界,甚至会和公司内的政治关联起来。



安全架构

XSS Cross Site Scripting 跨站脚本攻击

新浪微博曾经遇到的攻击。一个用户发布微博,TA的好友看到了,转发微博后,用户的好友也发起了攻击。

查看微博的时候,从服务器获取到恶意脚本,在浏览器上会再次执行。

解决方案:用户不能发脚本文件给服务器。

XSS 攻击防御手段

消毒:XSS 攻击装一般都是通过在请求中嵌入恶意脚本达到攻击目的,这些脚本是一般用户输入中不适用的,如果进行过滤和消毒处理,即对这个某些 HTML 危险字符转义,如“>” 转义为 “&gt”、“”<转义为 “&lt” 等,就可以防止大部分攻击。为了避免对不必要的内容错误转义,如 “3<5” 中的 “<”,需要进行文本匹配后再转义。如 “<img src=” 这样的上下文中 “<” 才转义。事实上,消毒几乎是所有网站最必备 XSS 防攻击手段。



SQL 注入攻击

效果:删除users表。

注入攻击防御手段1

消毒:和防 XSS 攻击一样,请求参数消毒是一种比较简单粗暴又有效的手段。通过正则匹配,过滤请求数据中可能注入的 SQL 文。



如 “drop table”、“\b(?:update\b.*?\bsetldelete\b\W*?\bfrom)\b” 等。



注入攻击防御手段2

SQL 预编译参数绑定:使用预编译手段,绑定参数是最好的防 SQL 注入方法。目前许多的数据访问层框架,如 MyBatis,Hibernate 等,都实现 SQL 预编译和参数绑定,攻击者的恶意 SQL 会被当做 SQL 的参数,而不是 SQL 命令被执行。



获取数据库表结构信息的手段

  • 开源:如果网站采用开源软件搭建,如用 Discuz!搭建论坛网站,那么网站数据库结构就是公开的,攻击者可以直接获得。



  • 错误回显:如果网站开启错误回显,攻击者故意构造非法参数,服务端异常信息会输出到浏览器端,为攻击猜测数据库表结构提供了便利。



  • 盲注:网站关闭错误回显,攻击者根据页面变化情况判断 SQL 语句的执行情况,据此猜测数据库结构,此种方式攻击难度较大。

CSRF Cross Site Request Forgery 跨站点请求伪造 攻击

利用登录过的用户信息,伪造用户请求,一般通过302跳转去攻击服务器。



CSRF 攻击防御手段

  1. 表单 Token:CSRF 是一个伪造用户请求的操作,所以需要构造用户请求的所有参数才可以。表单 Token 就是阻止攻击者获得所有请求参数的可能,在页面表单中增加一个随机数 Token,每次请求的 Token 都不相同,请求提交后检查 Token 的值是否正确以确定请求提交者是否合法。



  1. 验证码:相对来说,验证码则更加简单有效,即请求提交时,需要用户输入验证码,以避免在用户不知情的情况下被攻击者伪造请求。但是输入验证码是一个糟糕的用户体验,所以必要的时候才请求,如支付交易等关键页面。



  1. Referer check:HTTP 请求头的 referer 域中记录着请求来源,可通过检查请求来源,验证其是否合法但是该方法有一定局限性,referer 也并不一定总能得到。



其它需要关注的攻击和漏掉

  1. Error Code:也称作错误回显,许多 Web 服务器默认是打开异常信息输出的,即服务器端未处理的异常堆栈信息会直接输出到客户端浏览器,这种方式虽然对程序调试和错误报告有好处,但同时也给黑客造成可乘之机。通过故意制造非法输入,使系统运行时出错,获得异常信息,从而寻找系统漏洞进行攻击。防御手段也很简单,通过配置Web 服务器参数,跳转 500 页面(HTTP 响应码 500 表示服务器内部错误)到专门的错误页面即可,这个功能 Web 应用常用的 MVC 框架也可以做到。

  2. HTML 注释:为了程序调试方便或其它不恰当的原因,有的时候程序开发人员会在PHP、JSP等服务器页面程序中使用 HTML 注释语法进行程序注释,这些 HTML 注释就会显示在客户端浏览器,给黑客造成攻击便利。程序最终发布前需要进行代码 review 或 自动扫描,编码 HTML 注释漏洞。

  3. 文件上传:一般网站都会有文件上传功能,设置头像、分享视频、上传附件等。如果上传的是可执行的程序,并通过该程序获得服务器端命令执行能力,那么攻击者几乎可在服务器上为所欲为,并以此为跳板攻击集群环境的其它机器。最有效的防御手段是设置上传文件白名单,只允许上传可靠的文件类型。此外还可以修改文件名、使用专门的存储等手段,保护服务器免受上传文件攻击。

  4. 路径遍历:攻击者在请求的 URL 中使用相对路径,遍历系统未开放的目录和文件。防御方法主要是将 JavaScript、 CSS 等资源文件独立服务器、独立域名,其它文件不使用静态 URL 访问,动态参数不包含文件路径信息。



Web 应用防火墙



开源 Web 应用防火墙 ModSecurity

ModSecurity 是一个开源的 Web 应用防火墙,探测攻击并保护 Web 应用程序,既可以嵌入到 Web 应用服务器中,也可以作为一个独立的应用程序启动。 ModSecurity 最早只是 Apache 的一个模块,现在已经有 Java、.NET 多个版本,并支持 Nginx。



ModSecurity 采用处理逻辑与规则集合分离的架构模式。处理逻辑负责请求和响应的拦截过滤,规则加载执行等功能。而规则集合则负责对具体的攻击的规则定义、规模识别、防御策略等功能。处理逻辑比较稳定,规则集合需要不断针对漏洞进行升级,这是一种可扩展的架构设计。



网站安全漏洞扫描

和电脑安全漏洞扫描一样,网站也需要安全漏洞扫描。



网站安全漏洞扫描工具是根据内置规则,模拟黑客攻击行为,用以发现网站安全漏洞的工具。许多大型网站的安全团队都有自己开发的漏洞扫描工具,不定期的对网站的服务器进行扫描,查漏补缺。



目前市场上也有许多商用的网站安全漏洞扫描平台。



总结

如果出现循环依赖,系统就挂了。

架构师没有写架构文档,就像程序员不写代码。



发布于: 2020 年 08 月 13 日 阅读数: 59
用户头像

John(易筋)

关注

问渠那得清如许?为有源头活水来 2018.07.17 加入

工作10+年,架构师,曾经阿里巴巴资深无线开发,汇丰银行架构师/专家。开发过日活过亿的淘宝Taobao App,擅长架构、算法、数据结构、设计模式、iOS、Java Spring Boot。易筋为阿里巴巴花名。

评论

发布
暂无评论
极客大学架构师训练营 组件设计原则 安全架构 防火墙ModSecurity 第21课 听课总结