只要代码在返回客户端的 HTML 输出流中使用输入参数,就很容易受到跨站点脚本(XSS,也称 CSS)攻击。即使在进行代码审查之前,您也可以运行一个简单的测试,来检查应用程序是否存在 XSS 缺陷。搜索那些将用户输入信息发送回浏览器的页。
XSS 错误是在用户输入的数据中保持太多信任的一个例子。例如,应用程序可能期望用户输入一个定价,但是攻击者会在定价之外包含一些 HTML 和 JavaScript 代码。所以,您应该总是确保对来自不可信来源的数据进行验证。在审查代码时,总是询问这样的问题:“这个数据进行验证了吗?”在 ASP.NET 应用程序中保存所有入口点(如 HTTP 头、查询字符串、窗体数据等等)的列表,并确保所有输入都会在某点受到有效性检查。不要测试输入值是否不正确,因为这种方法认为您会留意所有存在潜在危险的输入。ASP.NET 应用程序中最常见的检查数据有效性的方式是使用正则表达式。
您可以通过在窗体字段中键入一些文字(如“XYZ”)并测试输出,来进行简单的测试。如果浏览器显示“XYZ”或者如果查看 HTML 源文件时看到的是“XYZ”,那么您的 Web 应用程序将很容易受到 XSS 攻击。如果您需要看到更动态的内容,需要注入 <script>alert('hello');</script>。这种技术可能无法在所有情况下都适用,因为它取决于如何使用输入来生成输出。以下过程有助于识别常见的 XSS 缺陷:
? |
标识输出输入的代码。
|
? |
标识有可能存在危险的 HTML 标记和属性。
|
? |
标识处理 URL 的代码。
|
? |
检查输出是否编码。
|
? |
检查字符编码是否正确。
|
? |
检查 validateRequest 属性。
|
? |
检查HttpOnly cookie 选项。
|
? |
检查 <frame> 安全属性。
|
? |
检查是否使用 innerText 和 innerHTML 属性。
|
标识输出输入的代码
从浏览器查看页输出的源代码,看是否您的代码位于一个属性中。如果确实如此,注入以下代码并重新测试,以查看输出。
"onmouseover= alert('hello');"
开发人员常用的一个技术是筛选 < and > 字符。如果所审查的代码筛选了这些字符,那么可以改用以下代码测试:
&{alert('hello');}
如果代码不筛选这些字符,那么可以通过使用以下脚本测试代码:
<script>alert(document.cookie);</script>;
在使用这个脚本之前可能必须要添加一个结束标记,如下所示。
"></a><script>alert(document.cookie);</script>
搜索“.Write”
在 .aspx 源代码和任何其他为应用程序开发的程序集包含的代码中搜索“.Write”字符串。这将定位所有出现的 Response.Write,以及任何可能通过响应对象变量生成输出的内部例程,如下面所示的代码。
public void WriteOutput(Response respObj)
{
respObj.Write(Request.Form["someField"]);
}
您还应该在 .aspx 源代码中搜索 “<%=”字符串,这也可以用来写输出,如下所示:
<%=myVariable %>
下表列出了一些常见的结合使用输入字段和 Response.Write 的情况。
窗体字段
|
Response.Write(name.Text); Response.Write(Request.Form["name"]);
|
查询字符串
|
Response.Write(Request.QueryString["name"]);
|
Cookie
|
Response.Write( Request.Cookies["name"].Values["name"]);
|
会话变量和应用程序变量
|
Response.Write(Session["name"]); Response.Write(Application["name"]);
|
数据库和数据存储区
|
SqlDataReader reader = cmd.ExecuteReader();Response.Write(reader.GetString(1));
|
标识有可能存在危险的 HTML 标记和属性
虽然并不全面,但是以下常用的 HTML 标记可能使恶意用户可注入脚本代码:
? |
<applet>
|
? |
<body>
|
? |
<embed>
|
? |
<frame>
|
? |
<script>
|
? |
<frameset>
|
? |
<html>
|
? |
<iframe>
|
? |
<img>
|
? |
<style>
|
? |
<layer>
|
? |
<ilayer>
|
? |
<meta>
|
? |
<object>
|
HTML 属性(如 src、lowsrc、style 和 href)可以与以上的标记结合使用,导致 XSS 攻击。
例如,<img> 标记的 src 属性可能是注入的来源,如下例中所示。
<IMG SRC="javascript:alert('hello');">
<IMG SRC="java
script:alert('hello');">
<IMG SRC="java
script:alert('hello');">
<style> 标记还能通过改变 MIME 类型,成为注入的来源,如下所示。
<style TYPE="text/javascript">
alert('hello');
</style>
检查是否您的代码试图通过筛选掉一些已知的危险字符来净化输入。不要依赖此方法,因为恶意用户一般可找到替代的表示方法绕过验证。相反,您的代码应该对已知安全的输入进行验证。下表列出了表示一些常用字符的若干方式:
"(双引号)
|
"
|
"
|
"
|
\u0022
|
'(单引号)
|
'
|
'
|
'
|
\u0027
|
&(和号)
|
&
|
&
|
&
|
\u0026
|
<(小于号)
|
<
|
<
|
<
|
\u003c
|
>(大于号)
|
>
|
>
|
>
|
\u003e
|
标识处理 URL 的代码
处理 URL 的代码可能存在缺陷。审查代码,看看是否容易受到以下常见攻击:
? |
如果您的 Web 服务器没有使用最新的安全修补程序更新,它可能遭到目录遍历和双斜杠攻击,如:
http://www.YourWebServer.com/..%255%../winnt
http://www.YourWebServer.com/..%255%..//somedirectory
|
? |
如果您的代码筛选了“/”,攻击者可通过使用同一字符的替代表示形式,很容易地绕过筛选器。例如,“/”的超长 UTF?C8 表示形式是“%c0f%af”,可以用在以下 URL 中:
http://www.YourWebServer.com/..%c0f%af../winnt
|
? |
如果您的代码处理查询字符串输入,应该检查它是否对输入数据进行了限制并执行了边界检查。检查如果攻击者通过查询字符串参数传递非常多的数据,代码是否不易受到攻击。
http://www.YourWebServer.com/test.aspx?var=InjectHugeAmountOfDataHere
|
检查输出是否编码
您应该检查是否使用 HtmlEncode 对包含所有类型输入的 HTML 输出进行了编码,虽然这不能替代对输入是否正确和输入的格式是否规范的检查。还要检查是否使用了 UrlEncode 来编码 URL 字符串。输入数据可能来自查询字符串、窗体字段、cookie、HTTP 头和从数据库中读取的输入,尤其是在与其他应用程序共享数据库时。通过对数据进行编码,可以防止浏览器将 HTML 视为可执行脚本。
检查字符编码是否正确
为了帮助防止攻击者使用规范化和多字节转义序列欺骗输入验证例程,应该检查字符编码是否已经正确设置以限制表示输入的方式。
检查应用程序的 Web.config 文件是否已经设置由 <globalization> 元素配置的 requestEncoding 和 responseEncoding 属性,如下所示。
<configuration>
<system.web>
<globalization
requestEncoding="ISO-8859-1"
responseEncoding="ISO-8859-1"/>
</system.web>
</configuration>
字符编码还可以使用 <meta> 标记或者 ResponseEncoding 页级属性在页级设置,如下所示。
<% @ Page ResponseEncoding="ISO-8859-1" %>
有关更多信息,请参阅“构建安全的 ASP.NET 页和控件”单元。
检查 validateRequest 属性
使用 .NET Framework 1.1 版构建的 Web 应用程序执行输入筛选,以消除潜在的恶意输入,如嵌入脚本。但不要依赖这一点,应该使用它作为纵深防范措施。检查配置文件中的 <pages> 元素,确认 validateRequest 属性是否已经设置为 true。这还可以设置为页级属性。扫描 .aspx 源文件中的 validateRequest,检查它没有为任何页设置为 false。
检查 HttpOnly cookie 选项
Internet Explorer 6 SP 1 支持一个新的 HttpOnly cookie 属性,可以防止客户端脚本从 document.cookie 属性访问 cookie。这样返回的将是一个空的字符串。无论何时用户浏览到当前域中的 Web 站点,仍然发送 cookie 到服务器。有关更多信息,请参阅“构建安全的 ASP.NET 页和控件”单元中的“跨站点脚本攻击”部分。
检查 安全属性
Internet Explorer 6 和更高版本支持 <frame> 和 <iframe> 元素的一个新属性 security。您可以使用 security 属性将用户的受限站点 Internet Explorer 安全区域设置应用于单独的 frame 或者 iframe。有关更多信息,请参阅“构建安全的 ASP.NET 页和控件”单元中的“跨站点脚本攻击”部分。
检查是否使用 innerText 和 innerHTML 属性
如果您创建了一个带有不可信输入的页,应该验证是否使用了 innerText 属性而非 innerHTML。innerText 属性可安全呈现内容并确保不会执行脚本。