一些关于XSS的澄清

8

我刚好读到了有关XSS及如何避免的内容。根据我所读的,我知道我们需要进行输入过滤、正确处理应用程序代码和输出编码,才能使Web应用程序在一定程度上变得更安全。阅读了几篇文章后,仍然存在一些疑问。

  • 当我尝试使用jQuery.text("untrusted_data")element.text=untrusted_data时,浏览器似乎对内容进行了完美的编码,但我在其他地方读到说客户端编码不可信,必须“始终”在服务器端进行编码。为什么客户端编码被认为不安全?

  • 每当我尝试使用jQuery.val(untrusted_data)element.value=untrusted_data设置值时,它似乎足够安全。那么它真的是XSS安全的吗?还是我错过了某些情况?

  • 此外,我在某个地方读到jQuery.setAttribute(attrName,untrusted_data)setAttribute(attrName,untrusted_data)通常只被认为是安全的,如果属性名称不包括基于URL上下文的属性(src、href等)或事件处理程序(onClick、onMouseOver等)。如果是这样,我该如何使用setAttribute("href",untrusted_data)设置href属性?从服务器端使用encodeForHtmlAttribute(untrusted_data)是正确的方法吗?
  • 我应该如何处理动态HTML创建。请考虑以下示例:

<div id="divName1" onClick="copyData()">untrusted_data</div> <div id="divName2"></div>

function copyData()
{
  var divValue = jQuery("#divName1").html();
  jQuery("#divName2").html(divValue);/XSS Here
}

我想要实现的目标是从divName1获取文本并将其粘贴到divName2的内容中。我上面编写的代码存在XSS漏洞。我可以改成以下代码:

jQuery("#divName2").text(divValue)

所以,这将确保编码,但据我所知,我们说客户端编码不安全,只应使用服务器端编码。如何编写此代码以使其在不使用客户端编码的情况下能够避免XSS攻击呢?我有点困惑 :(. 请帮助我澄清这些疑虑。

element.text 本身是安全的,但如果您使用字符串插值将数据传递给客户端代码,则可能会遇到问题。 - John Dvorak
1个回答

8

一次性提出这么多问题。

为什么客户端编码被认为不安全?

只要客户端编码做得正确和一致,那就没问题。 客户端编码通常门槛较低,因为它不需要担心 UTF-7 攻击之类的字符编码级别攻击。

每当我尝试使用 jQuery.val(untrusted_data) 或 element.value=untrusted_data 设置值时,似乎足够安全。 那么它真的是 XSS 安全的吗? 还是我错过了什么情况?

假设 untrusted_data 是一个字符串,并且被设置值的元素是流或块元素中的普通文本节点,则没有问题。 如果被分配的节点是 <script> 元素中的文本节点、URL、事件处理程序或样式属性节点或与 <object> 有关的任何内容,则可能会遇到问题。

另外,我在某个地方读到,jQuery.setAttribute(attrName,untrusted_data) 和 setAttribute(attrName,untrusted_data) 通常被认为是安全的,只要属性名称不包括基于 URL 上下文的属性(src、href 等)或事件处理程序(onClick、onMouseOver 等)。 如果是这样的话,

部分正确。 其他属性也有一些尖锐的边缘,比如与 <object><embed> 以及 <meta> 有关的许多内容。

如果你不太了解属性,则不要将其暴露给不受信任的数据。通常安全的是包含文本内容的属性,例如 title 或具有枚举值的属性,例如 dir=ltrdir=rtl

一旦你处理需要更复杂值的属性,那么你就处于风险之中,攻击者可能会利用诸如 style 属性中的 -moz-binding 等晦涩浏览器扩展。

似乎足够安全

地雷似乎很安全,直到你踩上它们。

从 "看起来安全" 中你并不能得出太多结论。你需要仔细研究并了解可能出现什么问题,并安排事情,使你只有在所有事情都出现问题(P(灾难)=P(故障0) * P(故障1) * ...)的情况下才面临风险,并且只有一个事情出现问题时(P(灾难)=P(故障0)+P(故障1)*P(!failure0)+...)才不会有风险。

我应该如何使用 setAttribute("href",untrusted_data) 设置 href 属性?

如果没有白名单协议,请勿设置。

if (!/^https?:\/\//i.test(untrusted_data) && !/^mailto:/i.test(untrusted_data)) {
  throw new Error('unsafe');
}

从服务器端调用encodeForHtmlAttribute(untrusted_data)是正确的方法吗?
不是。将传递给setAttribute的值进行HTML编码是冗余的,并且不会帮助保留任何安全属性。如果我对最近规范更改的回忆是正确的,则

1
不错的回答。只是要补充一点 - 正如作者所提到的,属性也应该进行清理。你可以在服务器端或客户端相对容易地完成这个过程 - 主要的困难在于它们可能受到的广泛攻击。网络上有一些非常好的过滤脚本示例。 - Sébastien Renauld
2
“地雷似乎很安全,直到你踩上它们。” 这是我遇到过的任何IT安全问题的最佳概括,其中提出的解决方案“看起来足够安全”... - ppeterka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接