【问题标题】:Protecting against XSS with dynamically generated JavaScript使用动态生成的 JavaScript 防御 XSS
【发布时间】:2015-04-02 16:15:44
【问题描述】:

我必须向 jQuery 插件传递一些数据。我可以向它传递一个 URL,它将使用 GET 请求来获取数据,或者直接向它传递一个将消除一个服务器请求的数组。有问题的数据是用户提供的,没有在数据库输入时进行清理。

下面的脚本没有显示插件,但显示了我如何将数据传递给客户端,以便可以直接传递给插件。可以看出,动态生成的 JS 方法对 XSS 来说是可疑的,但是,Ajax/JSON 方法似乎不是。

对于这种情况,应该如何保护动态生成的 JavaScript 方法,Ajax/JSON 方法是否存在风险?

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>XSS Testing</title>  
        <script src="getStuff.php?type=js" type="text/javascript"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.js" type="text/javascript"></script>
        <script type="text/javascript"> 
            $(function(){
                console.log(stuff);
                $.get( "getStuff.php", function( data ) {
                    console.log(data);
                },'json');
            });
        </script>
    </head>

    <body>
    </body> 
</html> 

getStuff.php

<?php
$getFromDB=array(
    'Mary',
    'x"];alert(\'xss2\');x=["x',
    'John'
);
if(isset($_GET['type']) && $_GET['type']=='js') {
    header('Content-Type: application/javascript;');
    $s='var stuff=[';
    foreach($getFromDB as $row) {
        $s.='"'.$row.'",';
    }
    $s=substr($s, 0, -1).'];';
    echo($s);
}
else {
    header('Content-Type: application/json;');
    echo(json_encode($getFromDB));
}
?>

【问题讨论】:

  • “有问题的数据是用户提供的,没有在数据库输入时进行清理。” 嗯,所有数据都是从外界进入系统的需要在任何合理的系统中记录在数据库中之前进行消毒/检查。如果您不这样做,您将在某个时候被有效登录您的系统但具有邪恶意图的人咬伤。
  • 是的,这措辞很糟糕,正如我们在其他地方所同意的那样。对不起。我不是说在输入时 escape 它,我说的是在输入时 check 它是否看起来合理。当然,你会在输出时转义 as I said below

标签: javascript php jquery ajax xss


【解决方案1】:

如果您希望使用 JSON,为什么不首先验证您正在使用的是什么?

$.get(...)
 .success(function(data) {
    try {
      JSON.parse(data)
    } catch (e) {
      console.error("this isn't actually JSON");
    }
 })

JSON 不能包含函数,也不能包含函数调用,因此只需询问浏览器是否 可以 被解析就足以让它运行“这里有一些不是真正的 JSON 的东西数据”。

当然,您的 PHP 也是如此。 如果您需要特定的序列化,切勿构建字符串。在这种情况下,以通常的 PHP 方式构建您的键/映射对象,然后使用内置的 json_encode 函数将其转换为合法的 JSON 序列化。

【讨论】:

  • 谢谢 Mike,“特定序列化”是什么意思?使用动态生成的 JS 方法进行保护怎么样?
  • 任何“实际具有规范”的对象序列化,如 JSON、HTML、XML 等。不要将它们构建为字符串,将它们构建为结构化对象,然后告诉它们自己序列化(如果可以),或者使用序列化 API 调用。即使您绕过 GET,您也希望获取该用户数据,并通过 JSON.parse 运行它,这样您就可以判断数据是否实际上是纯 JSON 数据类型(对象、数组、字符串、数字 - 没有函数,没有函数调用)
  • 啊,你的意思是exit('var stuff='.json_encode($getFromDB).';');?我对其进行了测试,它不执行alert 语句。这被认为是安全的吗?
  • @Mike'Pomax'Kamermans “如果您希望使用 JSON,为什么不首先验证您使用的是什么?” 他已经这样做了@ 987654326@ 如果 jQuery 收到不是 json 的东西,就会出错。
【解决方案2】:

这几乎就像您将示例设计为容易受到黑客攻击一样。在“js”情况下,您没有做任何事情来确保数据以正确的转义方式输出,您只是在“json”情况下这样做。

如果您要包含纯数据的 JavaScript 文件,如下所示:

<script src="getStuff.php?type=js"></script>

那么getStuff.php 需要确保它发回的内容作为数据正确转义

<?php
$getFromDB=array(
    'Mary',
    'x"];alert(\'xss2\');x=["x',
    'John'
);
if(isset($_GET['type']) && $_GET['type']=='js') {
    header('Content-Type: application/javascript');
    echo('var data = ');
    echo(json_encode($getFromDB));
    echo(';');
}
else {
    header('Content-Type: application/json');
    echo(json_encode($getFromDB));
}
?>

并且繁荣:没有警报。


旁注:; 不应位于 Content-Type 字符串的末尾。我已经在上面删除了它们。

【讨论】:

  • 谢谢 TJ。我同意这种方法有效。直到看到 Pomax 的回复,我才知道会这样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-08
  • 1970-01-01
  • 2013-05-26
  • 2015-10-11
相关资源
最近更新 更多