我正在编写一个类,它允许您使用JSON为数据桥接HTTP请求和类实例,而无需在您正在桥接的类中实现任何实现。基本上这就是它的工作原理:
// This is just an ordinary class.
$service = new WeatherService();
$jhi = new JsonHttpInterface($service);
$jhi->exec();
JsonHttpInterface
类将检查请求的PATH_INFO
并调用该方法,将任何查询字符串参数应用为参数。
http://example.com/the_above.php/getWeather?state="CA"
会转换为
$service->getWeather("CA")
(假设第一个参数的名称为$state
)。
这是找到和调用方法的方法:
$method = new ReflectionMethod(get_class($this->instance), $action);
/*
... code that matches query string values to arguments of above method...
*/
$response = $method->invokeArgs($this->instance, $args);
现在我想知道的是:这种系统有哪些漏洞。我对错误检查非常宽容,在尝试调用不存在的或私有/受保护的方法时依赖PHP来抛出错误。
JsonHttpInterface的完整源代码可在此处获取:http://blixt.org/js/two-cents.php
答案 0 :(得分:2)
您可以在不使用ReflectionXYZ类
的情况下实现相同目的call_user_func( array($this->instance, $action) , $args);
两者都以同样的方式保存,只要你控制$ this->实例是什么
$ action是一个字符串,用于搜索对象的/类'方法哈希表中的条目,并且没有可以逃避对象上下文的魔术符号(切换到另一个对象)。并且没有涉及例如解析,例如在sql和sql注入。
ReflectionMethod和call_user_func_array()都遵循方法的保护级别。 e.g。
class Foo {
public function publicfn() {
echo 'abc';
}
protected function protectedfn() {
echo 'xyz';
}
}
$obj = new Foo;
call_user_func_array(array($obj, 'publicfn'), array());
call_user_func_array(array($obj, 'protectedfn'), array());
$ro = new ReflectionMethod($obj, 'protectedfn');
$ro->invokeArgs($obj, array());
打印
abc
Warning: call_user_func_array() expects parameter 1 to be a valid callback, cannot access protected method Foo::protectedfn() in blabla on line 14
Fatal error: Uncaught exception 'ReflectionException' with message 'Trying to invoke protected method Foo::protectedfn() from scope ReflectionMethod' in blabla:16
Stack trace:
#0 blabla(16): ReflectionMethod->invokeArgs(Object(Foo), Array)
#1 {main}
thrown in blabla on line 16
如果情况总是如此,您可能想要查找。有例如条目- MFH Fixed bug #37816 (ReflectionProperty does not throw exception when accessing protected attribute)
。至少对于php 5.3分支来说这是真的
您始终可以访问$ this->实例的任何基类的公共方法
您可以从类上下文中访问受保护的方法,即,如果$ this和$ this->实例是相同的/派生类型,则可以访问$ this->实例的受保护方法。 e.g。
class Foo {
protected $instance;
public function __construct(Foo $instance=null) {
$this->instance = $instance;
}
public function publicfn() {
if ( !is_null($this->instance)) {
call_user_func_array( array($this->instance, 'protectedfn'), array());
}
}
protected function protectedfn() {
echo 'Foo::protectedfn() invoked';
}
}
class Bar extends Foo {
protected function protectedfn() {
echo 'Bar::protectedfn() invoked';
}
}
$foo = new Foo(new Bar);
$foo->publicfn();
打印Bar::protectedfn() invoked
。但这不应该太难避免。
答案 1 :(得分:1)
首先,
您需要创建一个white_list。
你得到了对象的已定义函数,并检查发送给你的函数名是否在数组中,如果是,那么好,否则,忘掉它。
您可以选择自动白名单或配置的手动白名单。
您需要为所有传递的值创建一个munging / washing函数。
在州的例子中,州可以是CA或加利福尼亚州,所以基本上它必须是preg_match('/ \ w + /'),这样你就可以做一些简单的检查来验证数据。
如果你想获得幻想,你可以允许人们创建一个名为allowedValues的方法,它是functionName =>的哈希映射。 / Regex /,并将其用作有效的数据查找表,如果该类中未定义该函数,则使用仅允许字符串/数字和perhops仅具有一定长度的泛型。
class MyClass{
public function allowedArguments() {
//This acts as a white list, and a cleaner/restricter
return array(
'myfunc' => array(
'pattern' => '/\w+/'
'length' => 255
)
);
}
public function myFunc($arg) {
... do something
}
}
答案 2 :(得分:0)
允许用户输入的PHP代码的Anthing很可能会受到一些攻击,因此它肯定是高风险的。如果您继续使用它,那么我将考虑包括的一个检查是使您希望以这种方式访问的任何类实现特定接口并在执行之前检查接口。这样可以防止以任何方式执行任意类,并将其限制为您特别允许的那些。
更好的解决方案可能是使用您需要的所有调用自动生成静态文件,这样您就可以明确地允许特定操作,而不是试图猜测所有漏洞可能位于何处。