preg_replace & 预替换preg_replace_callback 安全问题
好吧,我知道这是一种不好的做法,但是部分代码已经存在,我必须扩展它以使用一个参数运行自定义函数。
因此,我们的页面存储在数据库中,当它们显示在我们的模板中时,我们当前在整个 html 页面上使用三个带有 e 修饰符的不同 preg_replace 函数。
这看起来很慢,所以我想将其更改为仅使用一个 preg_replace 调用,并且能够以 bbcode 方式提供带有 1 个参数的自定义函数:示例:
[FUNC:testfunc(test string)]
所以,这是我想出了什么...我不确定哪种方法更安全,带有 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);
这将回调_caller()函数传递给我的整个文章类以供使用。 为每场比赛创建这样的匿名函数在性能方面是否很糟糕?
Ok, I know this is a bad practice, but part of the code was existing, and I have to extend it to run custom functions with one argument.
So, our pages are stored in the db, and when they are displayed in our template, we are currently using three different preg_replace function with e modifiers, on the whole html page.
This seems slow, so I'd like to change it to only use one preg_replace call, and be able to supply a custom function with 1 argument in a bbcode way: Example:
[FUNC:testfunc(test string)]
So, this is what I came up with... I'm not sure which method is more secure, preg_rplace with the e modifer, or 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;
}
}
?>
THe thing I like about using the e modifier, is that I could add another parameter onto the function call directly in php if I needed to, like this:
preg_replace('~\[FUNC:(.*?)\((.*?)\)\]~e', 'emodcaller("\\1", "\\2", $page->getid())', $str);
Is one method safer than the other? Are they both huge security risks? I have to have some implementation of these..
Edit: I figured out that you can pass the callback function additional parameters using an anonymous function like:
$content = preg_replace_callback(
'~(?:\<p\>)?\[FUNC:(.*?)\((.*?)\)\](?:\<\/p\>)?~',
function($matches) use ($article) {
return callback_caller($matches, $article);
},
$content);
This passes the callback_caller() function my entire article class for use.
Is creating an anonymous function like this for every match bad, performance-wise?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
根据执行此操作的次数,创建匿名函数可能会很糟糕。
您始终可以使用方法调用进行回调,如下所示:
这样您就可以避免将任何参数传递到方法中(如果它们已经是对象属性)。
我倾向于使用
preg_replace_callback()
而不是使用 'e' 的preg_replace()
,因为它避免了在评估代码中正确转义任何模式匹配的陷阱,并避免了必须进行 eval 的开销(如果您使用像 APC 这样的操作码缓存,这意味着与每次调用时都会编译的 eval 相比,编译次数为零)。它还使代码更容易阅读 - 评估的代码总是看起来有点难看,因为你必须转义字符串。也就是说,将 preg_replace() 与 'e' 一起使用并没有本质上的错误。
Depending on how many times you're executing this, creating the anonymous functions may be bad.
You can always use a method call for a callback like this:
That allows you to avoid having to pass any arguments into the method if they are already object properties.
I tend to favor
preg_replace_callback()
overpreg_replace()
with 'e', because it avoids the pitfalls of correctly escaping any pattern matches in the eval'd code and avoids the overhead of having to eval at all (and if you're using an opcode cache like APC, it means that there's zero compilation vs the eval which compiles on every call). It also makes code a little easier to read - eval'd code always looks a little uglier because you have to escape the string.That said, there's nothing inherently wrong with using preg_replace() with 'e'.