将 PHP 代码直接传递到 HTML5 中的 JavaScript

信息安全 php xss javascript json html-5
2021-08-20 07:43:24

我想将 PHP 字符串直接传递给 JavaScript 变量,并将服务器上的负载降至最低。我在 PHP 文件中有以下 JavaScript 用于执行此操作:

<!DOCTYPE html>
<html>
...
<body>

<section id="section1"></section>

<script>
var example = <?php json_encode($string_var, JSON_HEX_TAG);?>;
example.replace(/[<>]/g, (m) => {return m == "<"? "&lt;" : "&gt;";});
document.getElementById('section1').innerHTML = example;
</script>

...
</body>
</html>

$string_var来自 PHP的变量是一个未以任何方式清理的用户输入(也就是说,我什至没有对其执行htmlspecialchars())。

我的例子安全吗?还是我需要使用所有这些标志json_encode,即JSON_HEX_QUOT | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS我知道这个示例没有遵循最佳实践,但其中是否存在任何具体的风险或漏洞?

参考:

  1. 为什么使用JSON_HEX_TAG?
  2. JSON_HEX_QUOT | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS为 PHP推荐标志的答案json_encode
1个回答

JSON_HEX_TAG

如果您在 HTML 文档中回显到 JS(就像您在示例中一样),这是必要的,否则您可能会打开一个巨大的 XSS 漏洞。如果没有这个,攻击者可以发布类似以下内容的内容:

</script>alert("XSS");</script>

自 PHP 5.4 以来,此问题已得到修复,并且默认情况下会转义斜杠,但您仍然永远不知道您的代码将在哪个 PHP 版本上运行。安全总比后悔好。

正如 OP 指出的那样,即使在 PHP 的任何版本中,您都可以插入 a<!--来弄乱整个页面,这可能会导致意外行为。所以在所有 PHP 版本中确实需要这个标志。

JSON_HEX_QUOT 和 JSON_HEX_APOS

要了解它的作用,请查看以下示例:

$array = array(
    "a" => "'",
    "b" => '"',
);

// This will output {"a":"'","b":"\""}
echo json_encode($array);

// This will output {"a":"\u0027","b":"\u0022"}
echo json_encode($array, JSON_HEX_QUOT | JSON_HEX_APOS);

所以字符串文字周围的引号永远不会被编码。字符串文字中的引号将在没有标志的情况下进行转义,并使用它们进行编码

根据您的参考资料,这用于使输出在事件处理程序中安全使用(即 HTML 属性)。确实,它们在脚本标签中并不是严格需要的,但它们在事件处理程序中是安全的并不完全正确。

例如看一下这个例子:

<?php $data = array(" onmouseenter=alert(1) " => "foo"); ?>
<a onclick="x = <?= json_encode($data, JSON_HEX_QUOT | JSON_HEX_APOS); ?>">test</a>

导致:

<a onclick="x = {" onmouseenter=alert(1) ": "foo"}">test</a>

我认为如果你总是用单引号将你的属性值括起来,你是安全的,但这仍然感觉有点冒险。

JSON_HEX_AMP

在这里引用您的参考

为了与 XHTML 非 CDATA 脚本块兼容,也可以使用 &。

因此,由于您正在使用 HTML5,因此这不适用于您,而且我认为这里不存在安全漏洞。尽管如此,编码并没有什么坏处。

结论

  • 对于您的使用 - 在 HTML5 中的脚本标记内 - 只需使用JSON_HEX_TAG就足够了。
  • 在属性(事件处理程序)中执行此操作是危险的,至少除非您用单引号引起来。
  • 如果我是你,我会创建一个名为的小辅助函数safe_json_encode,它使用所有四个标志,然后只在脚本标签中使用它。过度编码不会伤害您。

补充说明

  • 确保为页面提供正确的内容类型和字符编码。搞砸这个可能会导致绕过编码的方法。
  • 如果稍后将变量值输出到 HTML,则需要再次考虑 XSS。例如,使用 JSON 中的值innerHTMLdocument.write将不安全。(我看到你在脚本的第二行处理了这个问题。)

免责声明:这是基于我今天所做的研究。我不是 PHP 大师。如果您依靠它来做一些关键的事情,您可能想自己做更多的研究,以确保我在这里没有遗漏任何东西。