You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

118 lines
11 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 10 | 信息泄露:为什么黑客会知道你的代码逻辑?
你好,我是何为舟。
你平时在Debug的时候一定首先会去查看错误信息。根据错误信息你能够了解究竟是什么情况引发了什么样的错误。同样地黑客也能够通过错误信息推断出你的后台代码逻辑。那么黑客究竟是怎么做的呢接下来我们就一起看一下这个过程。
## 为什么错误信息会泄露代码逻辑?
当黑客在登录某个页面时在用户名位置输入一个单引号在密码位置输入一个“g”之后就会出现如下的错误信息。
```
An Error Has Occurred.
Error Message:
System.Data.OleDb.OleDbException: Syntax error (missing operator) in query expression 'username = ''' and password = 'g''. at
System.Data.OleDb.OleDbCommand.ExecuteCommandTextErrorHandling ( Int32 hr) at
System.Data.OleDb.OleDbCommand.ExecuteCommandTextForSingleResult ( tagDBPARAMS dbParams, Object& executeResult) at
```
从这个错误信息中我们可以看到网页最终执行了一个SQL语句这个SQL语句的部分内容为`username = ''' and password = 'g'`。因此,后台的大致逻辑应该是下面这样的。
第一错误信息反馈的是Syntax error即语法错误。在密码位置输入单个字母“g”肯定不会引起错误所以这个SQL语句是因为多了一个单引号导致的报错。而如果使用了PreparedStatement等方法是不会产生这个错误的。因此后台的SQL查询应该是直接采用的字符串拼接且没有过滤单引号。
第二错误信息中显示了部分的WHERE条件是`username = '' and password = ''`。这又是一个登录的逻辑所以只要用户名和密码正确这个SQL语句会返回黑客需要的用户信息。因此后台的SQL语句应该是形如select from where的格式。
根据这些信息黑客很容易就可以发起SQL注入攻击了。
那错误信息中包含的敏感信息这么多怎么避免被直接展示到前端呢我们可以通过正确地配置文件来进行合适的错误处理。比如在PHP中我们可以进行如下配置
```
error_reporting = E_ALL ;向PHP报告发生的每个错误
display_errors = Off ;不显示满足上条指令所定义规则的所有错误报告
log_errors = On ;决定日志语句记录的位置
log_errors_max_len = 1024 ;设置每个日志项的最大长度
error_log = /var/log/php_error.log ;指定产生的错误报告写入的日志文件位置
```
在Java Spring中我们也可以通过配置[ExceptionHandler](https://www.baeldung.com/exception-handling-for-rest-with-spring)等来进行处理。
避免错误信息泄露代码逻辑,一方面是要通过正确地配置文件,避免错误信息被展示到前端;另一方面是要对错误信息进行检测,这里就需要用到“黑盒”检测了。
所谓“黑盒Black Box Testing功能测试就是在不获取代码的情况下直接运行应用然后对应用的请求和响应进行扫描。比如在错误信息泄露的场景中“黑盒”检测可以向应用发起一些必然会导致错误的请求比如上述例子中的单引号然后观察应用是返回完整的错误日志还是返回某些经过处理的页面。
好了,现在你应该明白了,为啥错误信息会泄露代码逻辑。实际上,错误信息泄露属于一种间接的信息泄露方式。间接的信息泄露方式主要是通过拼凑各种零散信息,还原出代码整体的面貌,然后有针对性地发起攻击。所以我们常说,黑客的攻击本身就是一个“聚沙成塔”的过程。
## 除了错误信息,还有什么地方会泄露代码逻辑?
除了错误信息之外,间接的信息泄露方式还有两种:返回信息泄露和注释信息泄露。
注释信息你应该很熟悉。因为所有的前端代码基本都不需要编译就可以展示在浏览器中所以黑客很容易就可以看到前端代码中的注释信息。但是如果这些注释信息中出现服务器IP、数据库地址和认证密码这样的关键信息。一旦这些关键信息被泄露将会造成十分严重的后果。
那该如何避免关键的注释信息出现在线上的代码中呢?我们经常会使用一种叫作“白盒”的代码检测方法。
所谓“白盒White Box Testing结构测试即直接获取到线上的源代码然后对它进行扫描。“白盒”扫描注释信息的原理比较简单因为每一种语言的注释都会带有特殊的标记比如Java和PHP中的/\*等),可以比较准确地被识别出来。除此之外,“白盒”检测通常还会被用来做一些检测代码漏洞或者逻辑漏洞的工作,这一块比较复杂,现在你只需要有一个大概印象即可,我们会在后续的课程中专门来讲。
简单了解了注释信息泄露,我们下面重点来看返回信息泄露。
你可以回忆一下,在前面讲[SSRF](https://time.geekbang.org/column/article/182074)攻击的时候我们模拟过这样一个场景服务端在请求一个图片地址的时候会根据地址的“存活”情况和返回数据的类型分别返回三种结果“图片不存在”“格式错误”以及图片正常显示。而黑客正是通过服务端返回信息的逻辑利用一个请求图片的SSRF摸清整个后端服务的“存活情况”。
类似的多种返回状态的场景还有很多,你可以想想自己平时工作中有没有遇到过。这里我再说一个常见的。当你在登录应用的时候,应用的返回逻辑可能是这样的:如果输入的用户名和密码正确,则登录成功;如果应用没有这个用户,则返回“用户名不存在”;如果输入的用户名和密码不匹配,则返回“密码错误”。
尽管这样清晰的登录提示对于用户体验来说,确实是一个较优解,但这个逻辑同样也暴露了过多的信息给黑客。黑客只需要不断地发起登录请求,就能够知道应用中存在的用户名,然后通过遍历常见的弱密码进行尝试,很容易就能够猜对密码。这样一来,猜对密码的成功率就比尝试同时猜测用户名和密码要高很多。
实际上,返回信息过于明确不算是代码层面的漏洞,更多的是产品层面的漏洞。因此,理论上没有任何技术手段能够对这种漏洞进行检测,只能依靠人为的分析审计来避免。解决方案也比较简单,直接将返回信息模糊化、统一化即可。比如,在上述登录的场景中,我们可以将两种登录失败的返回信息,统一修改为“用户名不存在或密码错误”。这样一来,既避免了用户体验受到太大影响,又消除了关键信息被黑客获取的隐患。
## 有哪些常见的直接泄露方式?
在间接的泄露方式中,黑客可以通过“蛛丝马迹”,推断出服务代码的逻辑。但是信息泄露最普遍的方式还是直接泄露 。这里我会讲两种常见的直接泄露方式。
第一种泄露方式与版本管理工具中的隐藏文件有关。
在开发应用的过程中你一定使用过版本管理工具比如SVN和Git通过这些工具你能够很方便地进行代码回滚、备份等操作。那你有没有想过版本管理工具为什么这么方便呢它的工作原理又是怎么样的呢我们以SVN为例来说一说。
SVN会在项目目录中创建一个.svn文件夹里面保存了应用每一个版本的源文件信息这也是SVN实现代码回滚的数据基础。如果SVN可以通过.svn中的数据提取应用任意版本的代码那黑客也可以。只要你没有在上线代码的时候删除其中的.svn目录那就代表黑客可以通过.svn中的URL访问里面的所有文件。接下来只需要通过执行简单的[脚本](https://github.com/admintony/svnExploit),黑客就可以回溯出一个完整版本的代码了。
对于这种因为目录中额外内容(.svn/.git导致的源码泄露我们一方面需要对线上代码进行人工的代码审查确保无关的文件和文件夹被正确地清除另一方面我们也可以在HTTP服务中对部分敏感的路径进行限制。比如在Apache httpd中配置下面的内容来禁止黑客对.svn和.git目录的访问。
```
<DirectoryMatch \.(svn|git)>
Order allow,deny
Deny from all
</DirectoryMatch>
```
除此之外还有一种最常见、也最不容易注意的泄露方式那就是上传代码到GitHub上。
我们知道Git除了是一个版本管理工具之外还是一个很流行的代码管理工具。除了前面讲过的隐藏文件漏洞之外Git会生成.git同样包含应用各种版本的文件信息Git还存在将代码上传到公开平台的问题。但是使用GitHub上传代码通常属于个人行为所以我们很难从技术层面上进行预防。
那我们有没有一些有效的防护措施,可以尽可能地提高安全性呢?
我个人认为公司应该从加强员工安全意识的培训、强化公司管理制度入手避免员工私自上传代码。除此之外公司还可以对GitHub发起巡检比较知名的工具有[Hawkeye](https://github.com/0xbug/Hawkeye)),通过定期检索公司代码的关键字(比如常用的包名、域名等)来进行检测。通过这些方式匹配到的结果,很可能就是员工私自公开的代码。确认之后,我们就可以联系上传的人员进行删除了。
## 总结
好了,今天的内容讲完了。我们来一起总结回顾一下,你需要掌握的重点内容。
信息泄露这类漏洞很容易理解,但它能够造成的危害却不容小觑。**基本上,所有攻击的第一步都是从信息泄露开始的**。而且黑客没有办法攻击一个未知的系统,所以黑客会通过这些泄露的信息,去推断出应用的整体架构和逻辑。
信息泄露的方式和原因有很多,这其中,除了黑客主动发起攻击导致的信息泄露之外,有很多非技术原因导致的信息泄露。所以,相应的防护手段也比较零散。不过总体来说,我们可以从以下几个方面进行防护:
* 屏蔽信息:通过技术手段,将不该被访问的资源进行屏蔽,从而避免信息泄露的产生;
* 代码检测:从“白盒”和“黑盒”两个方向,对代码、应用等进行检测,对可能的泄露进行预警;
* 人工审计:对于非技术原因造成的泄露,加强人工审计的工作。同时从公司制度上,去提高员工的安全意识。
今天的内容虽然比较简单,但是为了方便你记忆,我还是总结了一张知识脑图,你可以利用它来查缺补漏,加深记忆。
![](https://static001.geekbang.org/resource/image/9a/ad/9a522b774b1e2b40a94894c54300c3ad.jpg)
## 思考题
最后给你留一个思考题。
通过今天的讲解,你可以回忆一下,你的公司或者你负责的应用当中,是否发生过类似的信息泄露事件呢?如果发生过,对你的公司或者应用都造成了什么影响呢?最后又是如何解决的呢?
欢迎留言和我分享你的思考和疑惑,也欢迎你把文章分享给你的朋友。我们下一讲再见!