Linux 系统安全(五):网站安全与漏洞
网络层安全和系统层安全保障都是构建纵深防御体系不可或缺的重要组成部分;保障 Linux 应用安全是另一个异常重要的纵深防御体系组成部分。有些业务必须要对全网开放,例如一个电子商务网站或者联机游戏服务器。这时候,仅仅依靠网络防火墙就显得力不从心了,而必须依赖应用本身的安全机制。
简化的网站架构和数据流向
一个简化的网站架构和数据流向如图 8-1 所示:
在现代大型网站系统中,往往有较多组件,数据流向一般也比较复杂。为了说明与网站相关的应用安全,笔者对网站架构和数据流向做了简化和抽象,以便能够将安全目标聚焦在核心和通用组件上。图 8-1 正是这种简化和抽象的结果。其中,图 8-1 中的用户,既包括合法使用网站的人(他们按照网站产品设计的功能和流程使用服务),也包括试图入侵网站的人(他们试图通过网站漏洞来实现 STRIDE 威胁分析模型中的各种破坏)。本章的后续内容,主要是按照图 8-1 的网站架构和数据流向进行安全相关讲解。
主要网站漏洞解析
在 360 公司 2018 年 1 月 23 日发布的《 2017 中国网站安全形势分析报告》中指出,根据 360 网站安全检测平台扫描出高危漏洞的情况,跨站脚本攻击漏洞的扫出次数和漏洞网站数都是最多的,稳居排行榜榜首。其次是 SQL 注入漏洞、SQL 注入漏洞(盲注)、PHP 错误信息泄露等漏洞类型。2017 年 1-10 月份高危漏洞 TOP10 如表 8-1 所示:
表 8-1 1-10 月份高危漏洞 TOP10
漏洞名称 | 扫出次数 (万) | 漏洞网站数(万) |
---|---|---|
跨站脚本攻击漏洞 | 91.7 | 7.6 |
SQL 注入漏洞 | 18.8 | 1.7 |
SQL 注入漏洞(盲注) | 18.0 | 2.3 |
PHP 错误信息泄露 | 9.2 | 0.7 |
数据库运行时错误 | 5.3 | 0.5 |
跨站脚本攻击漏洞 (路径) | 3.7 | 1.1 |
使用存在漏洞的 JQuery 版本 | 3.7 | 1.8 |
MS15-034 HTTP.sys 远程代码执行 | 1.8 | 0.9 |
发现 SVN 版本控制信息文件 | 1.5 | 0.2 |
跨站脚本攻击漏洞(文件) | 1.3 | 0.2 |
SQL 注入漏洞最多,占比为 32.1%,其次是命令执行和信息泄露,占比分别为 27.4% 和 10.5%。占比较高的还有弱口令(10.2%)、代码执行(4.3%),具体漏洞类型分布请见图 8-2:
从表 8-1 和图 8-2 中,我们可以看到,注入类漏洞、跨站脚本、信息泄露是最需要关注的 3 种常见高危漏洞。在国家计算机网络应急技术处理协调中心在 2018 年 4 分发布的《2017 年我国互联网网络安全态势综述》也指出,“2017 年,CNCERT 抽取 1000 余家互联网金融网站进行安全评估检测,发现包括跨站脚本漏洞(占高危漏洞 26.1%)、SQL 注入漏洞(占高危漏洞 22.4%)等网站高危漏洞 400 余个,存在严重的用户隐私数据泄露风险。”
另外,还需要特别关注一类较严重的漏洞:文件解析漏洞。
注入漏洞
注入(Injection)漏洞是指因为应用程序未对输入的数据进行严格校验而导致执行了非预期的命令或者进行了未经授权的数据访问的漏洞。
几乎任何数据源都能成为注入载体,包括环境变量、所有类型的用户、参数、外部和内部 Web 服务。当攻击者可以向解释器发送恶意数据时,注入漏洞产生。注入漏洞十分普遍,尤其是在遗留代码中。注入漏洞通常能在 SQL、LDAP、XPath 或是 NoSQL 查询语句、操作系统命令、XML 解析器、简单邮件传输协议(Simple Mail Transfer Protocol,SMTP)包头、表达式语句及对象关系映射(Object Relational Mapping,ORM)查询语句中找到。注入能导致数据丢失、破坏或泄露给无授权方,也可能会缺乏可审计性或是拒绝服务。注入有时甚至能导致主机被完全接管。
最常见的注入漏洞包括 SQL 注入漏洞、命令注入漏洞这 2 大类。
下面给出 SQL 注入漏洞的示例:
场景 1:应用程序在下面存在脆弱性的 SQL 语句的构造中使用不可信数据:
场景 2:同样的,框架应用的盲目信任仍然可能导致查询语句的漏洞。(例如,Hibernate 查询语言):
在以上这两个案例中,攻击者在浏览器中将 "id" 参数的值修改成:’ or ‘1’='1。例如:
这样查询语句的含义就变成了从 accounts 表中返回所有的记录。
更危险的攻击甚至可能会导致数据被篡改甚至是数据库中的存储过程被非法调用。
跨站脚本漏洞
跨站脚本(Cross Site Scripting,XSS)漏洞是指网站没有对用户提交数据进行转义处理或者过滤不足导致恶意攻击者可以添加一些代码嵌入到 Web 页面中去而使别的用户访问就会执行相应嵌入代码的漏洞。
存在三种 XSS 类型,通常都是用户的浏览器:
反射式 XSS:应用程序或 API 将未经验证和未经转义的用户输入作为 HTML 输出的一部分。一个成功的攻击可以让攻击者在受害者的浏览器中执行任意的 HTML 和 JavaScript。
存储式 XSS:应用或者 API 将未净化的用户输入存储下来了,并在后期在其他用户或者管理员访问时的页面上展示出来。存储型 XSS 一般被认为是高危或严重的风险。
基于 DOM 的 XSS:会动态的将攻击者可控的内容加入页面的 JavaScript 框架、单页面程序或 API 存在这种类型的漏洞。
典型的 XSS 攻击可导致盗取 Session、账户、绕过多因子认证(Multi-Factor Authentication,MFA)、DIV 替换、对用户浏览器的攻击(例如:恶意软件下载、键盘记录)以及其他用户侧的攻击。
下面给出 XSS 漏洞的示例:
应用程序在下面 HTML 代码段的构造中使用未经验证或转义的不可信的数据:
攻击者在浏览器中修改 "CC" 参数为如下值:
这个攻击导致受害者的会话 ID 被发送到攻击者的网站,使得攻击者能够劫持用户当前会话。
注意:攻击者同样能使用跨站脚本漏洞攻破应用程序可能使用的任何跨站请求伪造(Cross-Site Request Forgery,CSRF)防御机制。
信息泄露
信息泄露是指应用程序把敏感信息展示给了未授权用户。这通常包括以下场景:
应用程序未对出错信息加以封装而直接展示给用户,导致泄露了应用程序版本、配置信息、调用的第三方接口或者数据库连接字符串等。如图 8-3 所示,就是某知名电子商务网站的报错信息:
从图 8-3 中,我们可以看到,在该报错信息中暴露了应用程序开发语言(Microsoft VBScript)、数据库驱动引擎(SQLOLEDB)、数据库服务器地址、访问账号(UID、PWD)。黑客可以借助以上信息进行二次利用而对网站安全产生极大的威胁。
因为配置或者操作不当导致源代码、应用程序配置文件可被直接下载。例如,把 Web 可访问目录中的 config.php 复制成 config.php.bak,而导致可直接下载 config.php.bak。如图 8-4 所示就是某网站安全软件拦截信息:
另一个典型的例子是.svn 目录未做过滤而导致的源代码泄露。
机密数据未做强加密或者未使用强散列算法存储而导致被恶意读取后散播和利用。例如,在日志或者数据库中明文记录完整信用卡卡号、用户账号和密码原文等,都极其可能带来信息泄露的问题。
文件解析漏洞
在 2010 年曾经发生过一个 Nginx 解析的问题,导致大量基于 Nginx+PHP 的网站被入侵。
漏洞介绍:Nginx 是一款高性能的 Web 服务器,使用非常广泛,其不仅经常被用作反向代理,也可以非常好的支持 PHP 的运行。默认情况下可能导致服务器错误的将任何类型的文件以 PHP 的方式进行解析,这将可能导致严重的安全问题,例如恶意的攻击者通过上传含有 Webshell 功能的.jpg 结尾的文件,而用 PHP 去解析和执行,则使得恶意的攻击者可能攻陷支持 PHP 的 Nginx 服务器。
漏洞分析:Nginx 默认以 cgi 的方式支持 PHP 的运行,譬如在配置文件当中:
以 cgi 的方式支持对 PHP 的解析,location 对请求进行选择的时候会使用 URI 环境变量进行选择,其中传递到后端 Fastcgi 的关键变量 SCRIPT_FILENAME 由 nginx 生成的 fastcgi_script_name 是直接由 URI 环境变量控制的,这里就是产生问题的点。而为了较好的支持 PATH_INFO 的提取,在 PHP 的配置选项里存在 cgi.fix_pathinfo 选项,其目的是为了从 SCRIPT_FILENAME 里取出真正的脚本名。
那么假设存在一个 http://www.xxx.com/xxx.jpg,我们以如下的方式去访问
将会得到一个 URI /xxx.jpg/xxx.php。
经过 location 指令,该请求将会交给后端的 fastcgi 处理,Nginx 为其设置环境变量 SCRIPT_FILENAME,内容为 /scripts/xxx.jpg/xxx.php。而在其他的 WebServer 如 Lighttpd 当中,我们发现其中的 SCRIPT_FILENAME 被正确的设置为 /scripts/xxx.jpg 所以不存在此问题。
后端的 fastcgi 在接受到该选项时,会根据 fix_pathinfo 配置决定是否对 SCRIPT_FILENAME 进行额外的处理,一般情况下如果不对 fix_pathinfo 进行设置将影响使用 PATH_INFO 进行路由选择的应用,所以该选项一般配置开启。PHP 通过该选项之后将查找其中真正的脚本文件名字,查找的方式也是查看文件是否存在,这个时候将分离出 SCRIPT_FILENAME 和 PATH_INFO 分别为 /scripts/xxx.jpg 和 xxx.php。最后,以 /scripts/xxx.jpg 作为此次请求需要执行的脚本,攻击者就可以实现让 nginx 以 php 来解析任何类型的文件了。
访问一个 nginx 来支持 php 的站点,在一个任何资源的文件如 robots.txt 后面加上 /xxx.php,这个时候你可以看到如下的区别:
访问 http://www.xxx.com/robots.txt
访问 http://www.xxx.com/robots.txt/xxx.php
其中的 Content-Type 的变化说明了后端负责解析的变化,该站点就可能存在漏洞。