向用户显示 JSON 时的 XSS


XSS when displaying json to users

我通过jQuery获取了一些JSON格式的数据,然后我需要向用户显示它,但是它容易受到XSS攻击。我在这里有什么选择,我应该在将数据放入数据库之前去除字符吗?我正在使用的框架(Kohana)有一个漂亮的功能HTML::Chars();,但由于我使用javascript显示数据,所以我不能在那里使用它。

一种选择似乎是遍历每个正在 json 编码的数组元素并对其应用HTML::Chars();。这是唯一的选择吗,如果是这样,那么这样做的最佳方法是什么?

例:

  1. 用户输入一些数据:title, body
  2. 数据存储到数据库中
  3. 然后其他用户进入站点,数据数组从数据库中获取并导出为 JSON 格式
  4. 我的jQuery脚本正在获取json并将新元素附加到我的页面正文。

法典:

$(document).ready(function(){
    $.ajax({
        url: '/timeline/latest/1',
        dataType: 'json',
        success: function(data){
            $.each(data, function(key, val) {
                switch (val.type){
                    case 'post': // I have only made post so far
                        addPost(val);
                        break;
                }
            });
        }
    });
})
function addPost(val){
    $('.content .timeline').prepend(val.title + '<br />' + val.body); // xss vulnerable
}

从数据库获取数据

<?php
class Controller_Timeline extends Controller{
    public function Action_Latest(){
        $parentID = $this->request->param('id');
        $modelTimeline = new Model_Timeline();
        // Here I get latest entries, big array
        $latest = $modelTimeline->Latest($parentID);
        // Response it and encode with JSON
        $this->response->body(json_encode($latest));
    }
}

到目前为止,我的解决方案是这样的,在我回显出$latest我遍历数组并应用反 xss 功能之前,我不知道它有多理想:

array_walk($latest, function(&$latest){
    foreach ($latest as &$key){
        $key = HTML::chars($key);
    }
});

我建议你像Drupal一样做。

Drupal不会过滤任何输入。它将文本存储在具有XSS漏洞的数据库中,如果要显示此HTML代码而不被过滤。

相反,它会根据输出进行筛选。您绝对应该在服务器端执行此操作。

你应该从Drupal使用filter_xss()函数中激发自己的灵感。

确保它适用于您的每个条目。当然,如果可以的话,请在全球范围内执行此操作,如下所示:

// In the Model_Timeline class
public function Latest( $id ) {
    // Get your array, and then
    foreach ( $array as $entry ) {
        // Filter each entry
        // I use $util->filter_xss but use it how you implemented it
        $entry = $util->filter_xss( $entry );
    }
    // And return the filtered array
    return $array;
}

你应该在将mysql_real_escape_string存储在数据库中之前调用它,htmlspecialchars 是可选的。您的问题是您不想只向用户显示 html,因此 htmlspecialchars 将不起作用,因为它将 <a> 等内容编码为&lt;a&gt;因此如果您打算在用户页面上使用 html,则不适合(您必须再次将其重新转换为可用的 html,因此它是多余的)。

在这种情况下,没有简单的答案 - 这取决于您正在处理哪种 html?如果它像<em> <p> <strong>那样纯粹是表示性的,你应该严格解析 html 服务器端并检查它只有这些东西,并拒绝或删除任何危险的东西,如 <script> .不过它更复杂,因为你也必须厌倦元素属性中的javascript,如onClick="do something bad"。

总之,在使用 PHP 发送 JSON 之前清理您的 html,这有最好的代表:http://htmlpurifier.org/