我想防止我的 Web 应用程序中的 XSS 攻击。我发现对输出进行 HTML 编码确实可以防止 XSS 攻击。现在的问题是如何对应用程序中的每个输出进行 HTML 编码?我有办法自动化这个吗?

我很欣赏 JSP、ASP.net 和 PHP 的答案。

有帮助吗?

解决方案

您不想对所有 HTML 进行编码,您只想对要输出的任何用户输入进行 HTML 编码。

对于 PHP: html实体html特殊字符

其他提示

一件事你 不应该 要做的就是过滤输入数据。人们经常建议这样做,因为这是最简单的解决方案,但它会导致问题。

输入数据除了以 HTML 形式输出外,还可以发送到多个位置。例如,它可能存储在数据库中。过滤发送到数据库的数据的规则与过滤 HTML 输出的规则非常不同。如果您对输入中的所有内容进行 HTML 编码,最终您的数据库中将包含 HTML。(这也是为什么 PHP 的“魔术引号”功能是一个坏主意。)

您无法预测输入数据将到达的所有位置。安全的方法是准备数据 就在之前 它被发送到某个地方。如果要将其发送到数据库,请转义单引号。如果您要输出 HTML,请转义 HTML 实体。一旦它被发送到某个地方,如果您仍然需要处理数据,请使用原始的未转义版本。

这是更多的工作,但您可以通过使用模板引擎或库来减少它。

对于 JSP,您可以鱼与熊掌兼得,使用 c:out 标记(默认情况下会转义 XML)。这意味着您可以将属性作为原始元素绑定:

<input name="someName.someProperty" value="<c:out value='${someName.someProperty}' />" />

当绑定到字符串时,someName.someProperty 将包含 XML 输入,但当输出到页面时,它将自动转义以提供 XML 实体。这对于页面验证的链接特别有用。

我用来转义所有用户输入的一个好方法是为 smarty 编写一个修饰符,它可以转义传递给模板的所有变量;除了那些附加了 |unescape 的。这样,您只允许对您明确授予访问权限的元素进行 HTML 访问。

我不再有那个修饰符了;但可以在这里找到大约相同的版本:

http://www.madcat.nl/martijn/archives/16-Using-smarty-to-prevent-HTML-injection..html

在新的 Django 1.0 版本中,它的工作方式完全相同,jay :)

我个人的偏好是勤奋编码 任何事物 它来自数据库、业务层或用户。

在 ASP.Net 中,这是通过使用来完成的 Server.HtmlEncode(string) .

对任何内容进行编码的原因是,即使您可能认为是布尔值或数字的属性也可能包含恶意代码(例如,复选框值,如果操作不当,可能会以字符串形式返回。如果您在将输出发送给用户之前没有对它们进行编码,那么您就会遇到漏洞)。

您可以包装 echo / print 等。在您自己的方法中,您可以使用它来转义输出。IE。代替

echo "blah";

使用

myecho('blah');

如果需要的话,您甚至可以有第二个参数来关闭转义。

在一个项目中,我们的输出函数中有一种调试模式,这使得通过我们的方法的所有输出文本都不可见。然后我们就知道屏幕上留下的任何东西都没有被逃脱!追踪那些顽皮的未转义位非常有用:)

如果您确实对每个输出进行 HTML 编码,用户将看到 <html> 的纯文本而不是一个正常运行的网络应用程序。

编辑:如果您对每个输入进行 HTML 编码,则在接受包含 < 等的外部密码时会遇到问题。

真正保护自己免受此类攻击的唯一方法是严格过滤您接受的所有输入,特别是(尽管不排除)来自应用程序公共区域的输入。我建议你看看丹尼尔·莫里斯的 PHP过滤类 (一个完整的解决方案)以及 Zend_Filter 包(可用于构建您自己的过滤器的类的集合)。

PHP 是我在 Web 开发方面选择的语言,所以对于我的回答中的偏见表示歉意。

基兰。

OWASP 有一个很好的 API 来编码 HTML 输出,或者用作 HTML 文本(例如段落或 <textarea> 内容)或作为属性的值(例如为了 <input> 拒绝表单后的标签):

encodeForHTML($input) // Encode data for use in HTML using HTML entity encoding
encodeForHTMLAttribute($input) // Encode data for use in HTML attributes.

该项目(PHP 版本)托管在 http://code.google.com/p/owasp-esapi-php/ 并且也适用于其他一些语言,例如。网。

请记住,您应该编码 一切 (不仅仅是用户输入),以及 尽可能晚 (不是存储在数据库中,而是输出 HTTP 响应时)。

输出编码是迄今为止最好的防御。出于多种原因,验证输入很重要,但并不是 100% 防御。如果数据库通过攻击而感染 XSS(即ASPROX)、错误或恶意输入验证不会执行任何操作。输出编码仍然有效。

Joel 有一篇关于软件的好文章(我认为让错误的代码看起来是错误的,我在手机上,否则我会给你一个 URL),其中涵盖了匈牙利表示法的正确使用。简短的版本会是这样的:

Var dsFirstName, uhsFirstName : String;

Begin

uhsFirstName := request.queryfields.value['firstname'];

dsFirstName := dsHtmlToDB(uhsFirstName);

基本上在变量前面加上类似的前缀 “我们” 对于不安全的字符串, “ds” 为了数据库安全, “HS” 为了 HTML 安全。您只想在实际需要的地方进行编码和解码,而不是所有内容。但是,通过使用它们的前缀来推断有用的含义,查看您的代码,如果有问题,您很快就会发现。无论如何,您将需要不同的编码/解码函数。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top