如何避免PHP中的反射注入攻击?

如何避免PHP中的反射注入攻击?,php,reflection,code-injection,Php,Reflection,Code Injection,我正在编写一个类,它允许您使用JSON为数据桥接HTTP请求和类实例,而无需在要桥接到的类中进行任何实现。基本上是这样的: // This is just an ordinary class. $service = new WeatherService(); $jhi = new JsonHttpInterface($service); $jhi->exec(); JsonHttpInterface类将检查请求的PATH\u INFO,并调用该方法,将任何查询字符串参数作为参数应用 h

我正在编写一个类,它允许您使用JSON为数据桥接HTTP请求和类实例,而无需在要桥接到的类中进行任何实现。基本上是这样的:

// This is just an ordinary class.
$service = new WeatherService();

$jhi = new JsonHttpInterface($service);
$jhi->exec();
JsonHttpInterface
类将检查请求的
PATH\u 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的完整源代码可以在这里找到:

允许用户输入PHP代码的Anthing可能会受到一些攻击,因此风险肯定很高。如果您继续使用它,那么我将考虑一个检查,包括以这种方式生成任何您想要访问的类,实现一个特定的接口,并在执行之前检查接口。这将防止任何任意类以这种方式执行,并将其限制在您特别允许的范围内

更好的解决方案可能是自动生成包含所有所需调用的静态文件,这样可以明确允许特定操作,而不是试图猜测所有漏洞的位置。

首先

您需要创建一个白名单

获取对象的已定义函数,然后检查发送给您的函数名是否在数组中,如果在数组中,则为good,否则,请忽略它

您可以选择执行自动白名单或手动配置白名单

您需要为所有传递的值创建一个mung/washing函数

在一个州的例子中,该州可以是加利福尼亚州,也可以是加利福尼亚州,因此本质上,它必须是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
    }
}

不使用ReflectionXYZ类也可以实现同样的效果

call_user_func( array($this->instance, $action) , $args);
只要您控制$this->instance是什么,它们都以相同的方式保存。
$action是一个字符串,用于在对象的/class方法哈希表中搜索条目,并且没有可以逃逸对象上下文的神奇符号(切换到另一个对象)。而且不需要像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在访问受保护属性时不会引发异常)
。至少PHP5.3分支是这样。
您始终可以访问$this->instance的任何基类的公共方法。
您可以从类上下文中访问受保护的方法,即如果$this和$this->instance属于相同的/a派生类型,则可以访问$this->instance的受保护方法。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()
。但这应该不会太难避免。

不要使用PHP来避免此类攻击。在进行调用之前,您可能需要进行函数\u exists()检查。我猜您的意思是
方法\u exists()
,但我明白您的意思。然而,如果
ReflectionMethod
基本上做了相同的事情,如果失败就会抛出错误,我宁愿这样做,因为这意味着更少的自定义代码。这就是我要问的。。。
ReflectionMethod
可靠吗,或者它允许的错误检查比自定义错误检查更多?您是对的,函数_exists()没有帮助。is_callable()也是一个不错的选择。虽然检查是一行额外的代码,但它允许您避免抛出错误。在我看来,让PHP抛出错误是草率的;必要时我宁愿抛出自己的异常。但这在很大程度上是一种风格。我知道你是从哪里来的,但我不抛出自己的异常的原因是因为已经有了处理异常的代码,将错误返回给客户端。我认为没有必要再做一个异常,返回PHP返回的相同错误,因为这个类只是一个shell,它将显示底层类抛出的异常(与这个类无关),因此,通过自定义异常不会获得一致性。此类的目的是不要求在被调用的类中完成任何工作。让类“public”的人应该知道,任何能够对调用
exec()
方法的PHP脚本执行HTTP调用的人都可以访问它的所有公共成员。我担心的是
ReflectionMethod
类中的漏洞。这是一个糟糕的设计决策,就像说“嘿,我重新发明了车轮,没有橡胶,或者测试它的安全性,或者其他任何东西,但它是一个车轮,所以使用它。”如果你能做到,也应该做到,那么不要疏忽,以正确的方式去做。我妈妈总是说,如果某件事值得去做,那么它就值得去做正确的事情。这个想法是在设计为服务的类之上做一个外壳。这些课程应该是n