我明白在客户端上使用eval(json_str)
容易受到恶意代码的攻击。我的问题是,如果json_str
是由PHP函数json_encode
构造的数组,我安全吗?
json_str = json_encode(array(record1,
record2,
record3));
现在在客户端代码中使用eval(json_str)
是完全安全的吗? 就纯JavaScript而言,是的,您是安全的:json_encode
的输出永远不能包含静态值之外的任何内容,这些值在传递给eval
时不会产生意外的副作用。(尽管在使用eval
时通常必须用()
包围JSON字符串,以避免它将对象文字表达式误解为语句块。)
旁白:这并不一定适用于所有JSON编码器,因为有一些字符在JSON字符串中包含raw是有效的,而在JavaScript中是无效的。最值得注意的是,U+2028和U+2029在JavaScript字符串字面量中不能不转义,因为它们构成换行符。然而,PHP的编码器编码所有非ascii字符(如"'u2028"
),所以这里没有问题。
就JavaScript嵌入到另一种语言(通常是HTML)而言,您不一定是安全的。例如:
<script type="text/javascript">
var v= <?php echo json_encode($value); ?>;
</script>
在这个例子中,如果value
包含一个字符序列为</script
的字符串怎么办?这将允许值过早地结束脚本块,从而转义为HTML标记,然后它可以在那里注入其他恶意脚本。
为了避免这个问题,当在HTML中包含JSON内容时,总是将字符串字面量中的<
字符编码为'x3C
,或者在JSON兼容的术语中编码为'u003C
。为了与XHTML非cdata脚本块兼容,也可以使用&
。为了与JS内部事件处理程序属性兼容,也使用引号。
PHP会为你做正确的选项json_encode()
:
var v= <?php echo json_encode($value, JSON_HEX_QUOT|JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS); ?>;
(您可能需要定义一个快捷函数以使其编写更快)
如果您想使用内容安全策略(CSP),您将被阻止执行内联脚本标记。由于CSP要求所有的JavaScript都在单独的文件中,因此这将使bobince的惊人答案变得不可能。
如何在外部JavaScript中访问动态JSON:
一种方法是用PHP对JSON进行html编码(这应该防止XSS,因为json_encode
将/
转换为'/
),然后将其回发给数据块(非JavaScript MIME类型的script
标签),然后使用JavaScript获取该标签的内容(改编自OWASP):
将其内联。注意,即使不使用CSP,由于type
属性,它实际上也不会被浏览器执行:
<script id="jsonString" type="application/json">
<?php
echo json_encode($object, JSON_HEX_QUOT|JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS);
?>
</script>
…或者使用display: hidden
HTML元素:
<div class="display-hidden">
<?php
echo json_encode($object, JSON_HEX_QUOT|JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS);
?>
</div>
然后在你的外部JavaScript文件中:
var dataElement = document.getElementById('jsonString');
var jsonString = dataElement.textContent || dataElement.innerText;
var jsonObj = JSON.parse(jsonString);
不要使用eval进行JSON解析
别这么做。
很可能您的服务器永远不会受到损害,并且您的应用程序将非常安全,等等等等,这不是重点。它是可能的服务器被部分破坏(太多的攻击向量,如果php json_encode
函数在您的服务器上被破坏了怎么办?)。
简单的解决方案是不要相信任何人发送的任何。现代浏览器都有原生JSON解析器,www.json.org提供了一长串针对不同语言的JSON解析器。为了提高速度,JS版本将回归到原生实现。
这一切意味着没有很好的理由使用eval
进行JSON解析。
是和否:
是:PHP生成有效的JSON
不:PHP也可能像JSON一样返回恶意代码。
如果你可以信任源代码,或者你甚至可以完全控制它(因为它是你的),那就没有问题了。
它应该是安全的,但是在客户端,您不能保证json_str
没有被其他来源注入。