【问题标题】:preg_replace & preg_replace_callback security concernspreg_replace & preg_replace_callback 安全问题
【发布时间】:2011-12-10 11:52:04
【问题描述】:

好的,我知道这是一种不好的做法,但部分代码已经存在,我必须对其进行扩展以运行带有一个参数的自定义函数。

因此,我们的页面存储在 db 中,当它们显示在我们的模板中时,我们目前在整个 html 页面上使用三个不同的带有 e 修饰符的 preg_replace 函数。

这似乎很慢,所以我想将其更改为仅使用一个 preg_replace 调用,并能够以 bbcode 方式提供具有 1 个参数的自定义函数:示例:

[FUNC:testfunc(测试字符串)]

所以,这就是我想出的……我不确定哪种方法更安全,使用 e 修饰符的 preg_rplace 或 preg_replace_callback:

<?php
$str = '
<h2>Title That should Not Be Affected</h2>
<p>[FUNC:linkbox(/somestuff/newpage.html)]</p>
<a href="[FUNC:getvar(url)]">[FUNC:getvar(title)]</a>
<p>Random Html THat should not be affected</p>
<p>[FUNC:linkbox(/somestuff/otherpage.html)]</p>
';

$str2 = preg_replace_callback('~\[FUNC:(.*?)\((.*?)\)\]~', 'callback_caller', $str);

$str = preg_replace('~\[FUNC:(.*?)\((.*?)\)\]~e', 'emodcaller("\\1", "\\2")', $str);

echo $str.'<br><br>'.$str2;

function callback_caller($args){

    if(!isset($args[0], $args[1]))
        return false;

    $func = strip_tags($args[1]);
    $param = isset($args[2]) ? strip_tags($args[2]) : '';

    //Only allow calling of known functions
    switch($func){

        case 'linkbox':
            return linkbox($param);
        break;

        case 'getvar':
            return getvar($param);
        break;

        case 'default':
            return '';
        break;

    }

}

function emodcaller($fun, $arg){
    $arg = strip_tags($arg);

    //Only allow calling of known functions
    switch($fun){
        case 'linkbox':
            return linkbox($arg);
        break;

        case 'getvar':
            return getvar($arg);
        break;

        case 'default':
            return '';
        break;

    }

}

function linkbox($addy){
    return 'Linkbox Called: '.$addy;
}

function getvar($arg) {

    switch($arg){
        case 'url':
            return '/index.html';
        break;

        case 'title':
            return 'This is a test title';
        break;
    }

}
?>

我喜欢使用 e 修饰符的一点是,如果需要,我可以直接在 php 中为函数调用添加另一个参数,如下所示:

preg_replace('~\[FUNC:(.*?)\((.*?)\)\]~e', 'emodcaller("\\1", "\\2", $page->getid())', $str);

一种方法比另一种更安全吗?它们都是巨大的安全风险吗?我必须对这些进行一些实现..

编辑:我发现您可以使用匿名函数向回调函数传递附加参数,例如:

$content = preg_replace_callback(
'~(?:\<p\>)?\[FUNC:(.*?)\((.*?)\)\](?:\<\/p\>)?~',
function($matches) use ($article) {
return callback_caller($matches, $article);
}, 
$content);

这会将 callback_caller() 函数传递给我的整个文章类以供使用。 为每场比赛创建一个这样的匿名函数是否对性能不好?

【问题讨论】:

    标签: php security preg-replace preg-replace-callback


    【解决方案1】:

    根据您执行此操作的次数,创建匿名函数可能很糟糕。

    您始终可以像这样使用方法调用进行回调:

    $content = preg_replace_callback($rx, array($obj, 'method_name'), $content);
    

    如果它们已经是对象属性,则可以避免将任何参数传递给方法。

    我更倾向于 preg_replace_callback() 而不是 preg_replace() 使用 'e',因为它避免了在 eval 代码中正确转义任何模式匹配的陷阱,并且完全避免了必须进行 eval 的开销(如果你'正在使用像 APC 这样的操作码缓存,这意味着编译与在每次调用时编译的 eval 相比是零编译)。它还使代码更易于阅读 - eval 的代码总是看起来有点难看,因为您必须对字符串进行转义。

    也就是说,将 preg_replace() 与 'e' 一起使用并没有本质上的错误。

    【讨论】:

    • 感谢您的信息,我没有意识到我可以使用类方法,这使它更容易一些。我想我会坚持使用 replace_callback 方法。
    猜你喜欢
    • 2017-06-02
    • 2016-02-07
    • 1970-01-01
    • 2014-04-27
    • 2015-08-09
    • 1970-01-01
    • 2011-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多