You are here

Drupal专业开发指南 第20章 使用filter_xss()阻止跨站点脚本攻击

g089h515r806 的头像
Submitted by g089h515r806 on 星期四, 2009-08-27 13:04

跨站点脚本(XSS)是攻击网站的一种常用方式,攻击者可以向一个网页插入他/她自己的代码,然后使用这些代码进行各种破坏活动。

 
     注意:XSS攻击的例子,参看http://ha.ckers.org/xss.html
 
假定你允许用户向你的网站输入HTML,期望他们这么输入
 
<em>Hi!</em> My name is Sally, and I...
 
但是他们输入了
 
 
    哎哟!我们又学了一课:永远不要信任用户输入。下面是函数filter_xss()的签名:
filter_xss($string, $allowed_tags = array('a', 'em', 'strong', 'cite', 'code',
'ul', 'ol', 'li', 'dl', 'dt', 'dd'))
 
    函数filter_xss()对传递给它的文本字符串进行以下操作:
 
1.它通过检查确保被过滤的文本是有效的UTF-8,从而阻止IE6下面的bug。
 
2. 它删掉诡异的字符比如NULL和Netscape4 JavaScript实体。
 
3. 它确保HTML实体比如&amp; 形式正确。
 
4.它确保HTML标签和标签属性的形式正确。在本阶段,没有出现在允许列表中——也就是,filter_xss()中的第2个参数——的标签,将被删除。属性style也被删除,这是由于通过覆盖CSS,它能够影响页面的外观,或者通过将页面的背景颜色设为一个垃圾链接的颜色来隐藏内容。以on开头的任何属性都会被删除(比如,onclick 或者 onfocus)如果你熟悉正则表达式,并且能够记住HTML实体的字符编码的话,你可以使用一个调试器来一步一步的学习一下filter_xss()(位于modules/filter/filter.module)以及它的相关函数。
 
5. 它确保所有的HTML标签,都不包含不允许的协议。允许的协议有http,https, ftp, news, nntp, telnet, mailto, irc, ssh, sftp, 和 webcal。你可以通过设置filter_allowed_protocols变量来修改这一列表。通过将下面的代码添加到你的settings.php文件中(参看settings.php文件中的关于变量覆写的注释),可以将允许的协议限制为http 和 https:
$conf = array(
'filter_allowed_protocols' => array('http', 'https')
);
 
下面的filter_xss()例子来自于modules/aggregator/aggregator.pages.inc,聚合器模块处理存在潜在安全隐患的RSS 或者 Atom种子。在下面,该模块为显示种子项模板文件准备使用的变量:
 
/**
 * Process variables for aggregator-item.tpl.php.
 *
 * @see aggregator-item.tpl.php
 */
function template_preprocess_aggregator_item(&$variables) {
$item = $variables['item'];
 
$variables['feed_url'] = check_url($item->link);
$variables['feed_title'] = check_plain($item->title);
$variables['content'] = aggregator_filter_xss($item->description);
...
}
 
注意我们调用了aggregator_filter_xss(),它对filter_xss()进行了封装并提供了一组可接受的HTML标签。我们将这个函数稍微做了简化,如下所示:
 
/**
 * Safely render HTML content, as allowed.
 */
function aggregator_filter_xss($value) {
$tags = variable_get("aggregator_allowed_html_tags",
'<a> <b> <br> <dd> <dl> <dt> <em> <i> <li> <ol> <p> <strong> <u> <ul>');
// Turn tag list into an array so we can pass it as a parameter.
$allowed_tags = preg_split('/\s+|<|>/', $tags, -1, PREG_SPLIT_NO_EMPTY));
return filter_xss($value, $allowed_tags);
}
 
     注意 作为安全性的一个练习,你可以拿出你自己的一些定制模块,来追踪输入到系统中了的用户输入,一定要确保在进行逻辑处理之前,先对用户输入进行清理,以保证安全性。
老葛的Drupal培训班 Think in Drupal

Drupal版本: