接受具有潜在危险的字符并防止 Stored XSS
Accepting potentially dangerous characters and preventing Stored XSS
我在 Web 应用程序中有一些字段,其要求是接受任何字符并将它们存储在数据库中。它们稍后会被检索并以多种方式显示,包括 JQuery 绑定、MVVM 框架等。
接受和处理这些数据的正确方法是什么?我是在存储数据之前在服务器端对数据进行编码还是以其原始格式存储?我是否分析每种呈现方法以了解它们如何安全地处理数据?
TL;DR: 是后者,XSS是输出编码问题
您可以将任何用户输入存储在您的数据库中,它本身不易受到攻击。当然,如果可以,您应该进行输入验证,但有时由于您在正常操作中期望的数据的性质,您无法真正验证某些输入。这不是什么大问题,XSS 通常无法通过输入验证来阻止。
反对在数据库中存储编码值的一个论点是,这是一种关注点分离。有几种不同的编码(HTML、Javascript、URL、XML 等)并且接收数据的组件可能(并且应该)与稍后呈现它的那个。另一个反对它的论点与这个有关,当存储数据时,你不想知道它会如何呈现,所以你无法选择正确的编码。编码数据的搜索或排序也将更加困难。所以你应该把它按原样存储。
为了防止 XSS,你必须在编写时根据上下文(plain html、javascript、json、xml、whatever)小心地实现输出编码这样的数据到某种输出。请注意,这并不简单,例如在 HTML 页面中,不仅脚本块会创建 javascript 上下文,而且例如事件属性(onclick、onmouseover 等)也会创建,如如果变量是 href 值的第一个字符,则为 标记执行 href(参见 javascript:alert(1)
)。
但最重要的是,您始终必须找到正确的编码方法,并在将所有变量写入输出时对其进行编码。
MVVM 是一种特殊情况。大多数客户端模板都有方法来编写编码或原始变量,客户端数据绑定通常提供将变量绑定为解析的 html 节点或仅作为文本的工具。显然,您应该选择文本,如果涉及用户输入,html 可能容易受到 XSS 攻击。这实际上意味着在 Knockout 中使用 text:
绑定而不是 html:
,或者使用 jQuery 的 .text()
方法而不是 .html()
.
在这些情况下,数据通常在 AJAX 请求中下载为 JSON,其中仍然不需要编码,因为您仍然不一定知道您将在哪里使用它,您可能仍想在客户端上 search/sort(但为了不受到攻击,您需要使用 application/json
内容类型发送它,而不是 text/html
)。但它只是数据,JSON只是一种数据格式。当然,它需要编码为 JSON,但标准对象序列化程序会为您完成。如果你想在页面中生成 JSON (比如初始化 SPA),你需要 HTML 编码 JSON 对象中的值 - 获取此数据更好更容易AJAX.
我在 Web 应用程序中有一些字段,其要求是接受任何字符并将它们存储在数据库中。它们稍后会被检索并以多种方式显示,包括 JQuery 绑定、MVVM 框架等。
接受和处理这些数据的正确方法是什么?我是在存储数据之前在服务器端对数据进行编码还是以其原始格式存储?我是否分析每种呈现方法以了解它们如何安全地处理数据?
TL;DR: 是后者,XSS是输出编码问题
您可以将任何用户输入存储在您的数据库中,它本身不易受到攻击。当然,如果可以,您应该进行输入验证,但有时由于您在正常操作中期望的数据的性质,您无法真正验证某些输入。这不是什么大问题,XSS 通常无法通过输入验证来阻止。
反对在数据库中存储编码值的一个论点是,这是一种关注点分离。有几种不同的编码(HTML、Javascript、URL、XML 等)并且接收数据的组件可能(并且应该)与稍后呈现它的那个。另一个反对它的论点与这个有关,当存储数据时,你不想知道它会如何呈现,所以你无法选择正确的编码。编码数据的搜索或排序也将更加困难。所以你应该把它按原样存储。
为了防止 XSS,你必须在编写时根据上下文(plain html、javascript、json、xml、whatever)小心地实现输出编码这样的数据到某种输出。请注意,这并不简单,例如在 HTML 页面中,不仅脚本块会创建 javascript 上下文,而且例如事件属性(onclick、onmouseover 等)也会创建,如如果变量是 href 值的第一个字符,则为 标记执行 href(参见 javascript:alert(1)
)。
但最重要的是,您始终必须找到正确的编码方法,并在将所有变量写入输出时对其进行编码。
MVVM 是一种特殊情况。大多数客户端模板都有方法来编写编码或原始变量,客户端数据绑定通常提供将变量绑定为解析的 html 节点或仅作为文本的工具。显然,您应该选择文本,如果涉及用户输入,html 可能容易受到 XSS 攻击。这实际上意味着在 Knockout 中使用 text:
绑定而不是 html:
,或者使用 jQuery 的 .text()
方法而不是 .html()
.
在这些情况下,数据通常在 AJAX 请求中下载为 JSON,其中仍然不需要编码,因为您仍然不一定知道您将在哪里使用它,您可能仍想在客户端上 search/sort(但为了不受到攻击,您需要使用 application/json
内容类型发送它,而不是 text/html
)。但它只是数据,JSON只是一种数据格式。当然,它需要编码为 JSON,但标准对象序列化程序会为您完成。如果你想在页面中生成 JSON (比如初始化 SPA),你需要 HTML 编码 JSON 对象中的值 - 获取此数据更好更容易AJAX.