搜索

首页  >  问答  >  正文

无需 JavaScript 即可安全地将不受信任的输入分配给 CSS 自定义属性:指南

假设我有一个字符串键和字符串值的对象,我想将它们作为 CSS 自定义属性写入服务器生成的一些 HTML 中。我怎样才能安全地做到这一点?

我所说的安全是指

为了简单起见,我将限制键仅允许 [a-zA-Z0-9_-] 类中的字符。

通过阅读 CSS 规范和一些个人测试,我认为通过以下步骤获取值可以取得很大的进展:

我根据这个 CSS 语法规范想出了上述步骤

对于上下文,这些属性可以由我们在其他地方插入的用户自定义样式使用,但同一对象也用作模板中的模板数据,因此它可能包含旨在作为内容的字符串和预期的字符串的混合作为 CSS 变量。我觉得上面的算法取得了很好的平衡,既非常简单,又不会冒丢弃太多可能在 CSS 中有用的键值对的风险(即使考虑到未来对 CSS 的添加,但我想确保我没有遗漏什么。


这里有一些 JS 代码,展示了我想要实现的目标。 obj 是有问题的对象,而 preprocessPairs 是一个函数,它接受该对象并对其进行预处理,删除/重新格式化值,如上述步骤所述。

function generateThemePropertiesTag(obj) {
  obj = preprocessPairs(obj);
  return `<style>
:root {
${Object.entries(obj).map(([key, value]) => {
  return `--theme-${key}: ${value};`
}).join("\n")}
}
</style>`
}

所以当给定一个这样的对象时

{
  "color": "#D3A",
  "title": "The quick brown fox"
}

我希望 CSS 看起来像这样:

:root {
--theme-color: #D3A;
--theme-title: The quick brown fox;
}

虽然 --theme-title 在 CSS 中使用时是一个非常无用的自定义变量,但它实际上并没有破坏样式表,因为 CSS 会忽略它不理解的属性。

P粉356361722P粉356361722445 天前724

全部回复(1)我来回复

  • P粉898107874

    P粉8981078742023-09-07 21:34:20

    我们实际上可能只使用正则表达式和一些其他算法,而不必依赖于一种特定的语言,希望这是您所需要的。

    通过声明对象键位于 [a-zA-Z0-9_-] 内,我们需要以某种方式解析值。

    价值模式

    因此,我们可以将其分为几类,然后看看我们会遇到什么(为了清楚起见,它们可能会稍微简化):

    1. '.*'(用撇号包围的字符串;贪婪)
    2. ".*"(用双引号括起来的字符串;贪婪)
    3. [+-]?\d+(\.\d+)?(%|[A-z]+)?(整数和小数,可选百分比或带单位)
    4. #[0-9A-f]{3,6}(颜色)
    5. [A-z0-9_-]+(关键字、命名颜色、“缓入”等内容)
    6. ([\w-]+)\([^)]+\) (类似 url()calc() 的函数> 等等)

    第一次过滤

    我可以想象在尝试识别这些模式之前您可以进行一些过滤。也许我们首先修剪值字符串。正如您所提到的, <<> 可以在 preprocessPairs() 函数的开头进行转义,因为它不会出现为我们上面有的任何模式。如果您不希望在任何地方出现未转义的分号,您也可以转义它们。

    识别模式

    然后我们可以尝试识别中的这些模式,对于每个模式,我们可能需要再次运行过滤。我们期望这些模式将由一些(或两个)空白字符分隔。

    包括对多行字符串的支持应该没问题,这是一个转义的换行符。

    语言环境

    我们需要认识到我们至少要过滤两个上下文 - HTML 和 CSS。当我们在