ASP.NET 跨站脚本 (XSS) 防范入门教程






4.91/5 (40投票s)
本文将介绍什么是跨站脚本 (XSS)。
引言
本文将介绍什么是 跨站脚本 (XSS)
。我们将尝试查看一些容易受到 XSS 攻击的示例,并尝试注入一些脚本。然后,我们将了解如何在 ASP.NET 网站中防范 XSS 攻击。
背景
跨站脚本是困扰许多网站的问题之一。根据 WhiteHat Security Top Ten 的数据,超过 50% 的网站容易受到跨站脚本攻击。作为一名 Web 开发人员,了解什么是跨站脚本以及如何保护我们的网站免受此类攻击至关重要。
跨站脚本本质上是将客户端脚本注入网站。这些脚本可以是 HTML 脚本或 JavaScript 脚本。现在的问题是,一个人如何向正在运行的页面注入脚本?这可以通过网站收集输入的各种方式轻松完成。跨站脚本可以通过以下形式传递脚本来执行:
- 文本框 (输入控件)
- 查询字符串
- Cookie
- Session变量
- 应用程序变量
- 从外部或共享源检索的数据
现在,让我们来看一些非常基础的跨站脚本示例,然后我们将尝试了解 ASP.NET 提供了哪些工具来防范跨站脚本。我们还将研究为了使我们的网站免受跨站脚本攻击而需要遵循的最佳实践。
使用代码
现在,在编写易受跨站脚本攻击的应用程序之前,我们应该知道 ASP.NET 在开箱即用的情况下提供了一些安全措施来防范此类攻击,即 RequestValidations
。这对 ASP.NET 开发人员来说是一件好事。我们将在文章的后面部分讨论它,但现在让我们看看如何禁用此防范机制。
准备测试项目
禁用请求验证的第一步是将页面指令的 ValidateRequest
属性设置为 false
。如果我们需要为整个网站执行此操作,可以从 web.config 的 pages 元素进行设置。
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" ValidateRequest="false" %>
现在,为了让上述设置生效,我们还需要将 httpRuntime
的 requestValidationMode
更改为 2.0
。只有当此模式设置为 2.0
时,请求验证才会被禁用,否则将不起作用。
<httpRuntime requestValidationMode="2.0"/>
注意:我们正在禁用请求验证,因为我们要测试跨站脚本。如果不禁用,就无法看到跨站脚本的实际效果。不建议在生产环境中关闭 requestvalidation
,因为这会使网站容易受到跨站脚本攻击。
通过查询字符串执行 XSS
现在,让我们创建一个简单的 Web 窗体,它将仅接受用户的查询字符串并显示查询字符串值在页面上。

页面的后台代码如下:
protected void Page_Load(object sender, EventArgs e)
{
string id = Request.QueryString["id"] as string;
if (id == null)
{
lblId.Text = "NA";
}
else
{
lblId.Text = id;
}
}
在正常情况下,这可以正常工作,但如果我尝试在查询字符串中传递一些脚本,那么就会出现问题。现在,我将查询字符串参数传递为:
Default.aspx?id=<h3>Hello from XSS"</h3>
现在,当我们打开页面时:

现在我们遇到了问题。用户可以从查询字符串传递任何 HTML,该 HTML 将在页面上呈现。这是一个非常基本的示例,但请想象一个包含绝对定位标签和图片的 HTML,它可能会完全覆盖原始页面并显示其他内容。
同样的情况也可能发生在 JavaScript 上。我可以将任何 JavaScript 注入到这个页面。让我们尝试一下:
Default.aspx?id=<script>alert('you have been hacked');</script>
输出将是:

现在我们可以疯狂地尝试编写此 JavaScript 来以任何方式操作 DOM 对象。
通过输入字段执行 XSS
现在,让我们创建一个简单的 textbox
来接受用户名,然后在页面上显示用户的名字以及一些欢迎信息。

按钮单击的后台代码如下:
protected void Button1_Click(object sender, EventArgs e)
{
lblMessage.Text = "Hello " + TextBox1.Text;
}
在正常的输入场景下,一切都会正常工作,但一旦我们尝试在文本框中传递一些 HTML 和 JavaScript,问题就会显现出来。让我们使用以下输入在文本框中将一个图片放在页面上,覆盖页面上的所有其他内容:
<img src="dilbert-03.jpg" style="position:absolute;top:0;left:0;display:block"/>

所以我们看到了如何通过跨站脚本攻击轻松地在页面中注入客户端脚本。让我们看看作为一名 ASP.NET 开发人员(或 Web 开发人员)需要做什么来遏制这些攻击。
防范跨站脚本
ASP.NET 网站开发人员相对于其他技术具有一些优势,因为 ASP.NET 在框架本身中内置了一些跨站脚本防范逻辑,即 RequestValidations
。在我们之前的示例中,我们禁用它来检查跨站脚本,但这根本不推荐,除非万不得已,否则不应禁用。
如果我们启用 RequestValidation
为 true 的页面,我们将收到一个错误而不是修改后的页面。

但除了这个内置的默认防范机制之外,开发人员应始终遵循以下准则来防范 XSS:
- 将用户输入限制为该特定字段可接受的字符。
- 永远不要信任用户输入。在处理所有用户输入之前,请始终对其进行编码。
- 如果数据来自外部源或共享源,切勿显示原始数据。在向用户显示数据之前,务必对其进行编码。
现在,让我们回到之前易受 XSS 攻击的页面。我们将在此页面上添加一个文本框和一个按钮,以查看如何限制用户输入。
我们始终可以使用 JavaScript 过滤器来限制用户输入。让我们在这个新的文本框上应用一些基于 JavaScript 的过滤器,以便我们只接受字母数字字符,仅此而已。
<asp:TextBox ID="TextBox2" runat="server" onkeypress="return AcceptAlphaNumericOnly(event, false, false);"></asp:TextBox>
现在,这将阻止用户在文本框中键入任何不需要的字符。我们也应该在服务器端检查和删除不需要的字符,因为客户端脚本很容易被绕过(即使在上面的文本框中,我们也可以粘贴复制的脚本)。
注意:此代码使用一个小型 s 文件来验证和过滤用户输入。此文件及其详细信息可以在此处找到:用于常见验证场景的微型 Javascript 框架。[^]
现在,关于用户输入编码部分。让我们再次添加一个类似的文本框,并为此输入编码用户输入的逻辑。
protected void Button3_Click(object sender, EventArgs e)
{
string rawInput = TextBox3.Text;
string encodedinput = Server.HtmlEncode(rawInput);
lblMessage3.Text = "Hello " + encodedinput;
}
现在,如果我们尝试通过此文本框注入内容,输出将是:

如果数据来自外部源或共享源,也应该做同样的事情。我们永远不应该信任不是我们创建的数据。
因此,现在我们了解了一些可以防范我们网站遭受跨站脚本攻击的基本防范机制。除了这些机制之外,使用一些稳定的第三方跨站脚本防范库也是明智的。其中一个库是 AntiXSS
(http://wpl.codeplex.com/[^])。使用此类库可以在框架和框架功能不足的情况下提供防范。
关注点
在本文中,我们从绝对初学者的角度了解了什么是跨站脚本。我们看到了一些容易受到跨站脚本攻击的示例,并了解了 ASP.NET RequestValidation
如何帮助我们防范 XSS 攻击,最后我们看到了从开发人员角度需要做什么来确保 XSS 攻击不会导致不良行为。本文是从一个对跨站脚本一无所知或知之甚少的初学者的角度编写的,因此我们没有讨论 AntiXss
等库。希望本文内容有所帮助。
历史
- 2013年4月06日:初稿。