当输出直接进入 JS 而不是 HTML 时,防止 XSS 的正确方法?

信息安全 php xss
2021-08-11 09:50:14

当输出直接进入 HTML 时,我看到了很多示例,但是当输出直接进入 JS 时,我看到了更多冲突的信息。

例如,如果代码是:

var thisIsATest = '<?php echo $_GET['a']; ?>';

URL 攻击向量是:

?a=';alert(1);'

输出呈现为:

var thisIsATest = '';alert(1);'';

我已经看到很多文档建议避免什么(例如 addlashes),以及对 htmlspecialchars() 的引用(但不是单独的)......

最正确的做法是什么?

1个回答

正确的方法是使用框架的工具(及其模板引擎,如果可用)。如果你在 JS 字符串中摆弄 PHP,你可能会让生活变得更加艰难和危险。

使用普通 PHP 的一种常见且安全的方法是按照此处json_encode()的说明使用例如:

var foo = <?php echo json_encode($foo, JSON_HEX_QUOT|JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS); ?>

json_encode()返回一个值的 JSON 表示,因此它可以保证在你的 JS 代码中评估为一个有效的对象,你可以将它分配给一个变量,如图所示。但不要省略附加标志。根据上下文,攻击者可能会使用有效负载</script>来突破整个脚本标签。

htmlentities()您提到的函数htmlspecialchars()用于直接 HTML 输出,不应在 JS 上使用。它们还允许您的字符串包含换行符,从而导致可能产生安全后果的语法错误。

谈到框架,Wordpress 为您提供了包装器,正如本指南wp_json_encode()中所推荐的那样您自己的框架可能有等效的功能。

另请注意,该对象已为 JS 上下文安全地准备好,但您传递的任何字符串仍可能包含 HTML 标记,这些标记通过json_encode()插入是不安全的(完全避免这两个。)document.write()innerHTML

这很愚蠢,但 XSS 安全:

Hello, <span id="display"></span>!
<?php $name = $_GET['name']; ?>
<script>
    var name = <?php echo json_encode($name, JSON_HEX_QUOT|JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS); ?>;
    display.textContent = name;
</script>