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

时间:2010-01-14 17:58:07

标签: php reflection code-injection

我正在编写一个类,它允许您使用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

3 个答案:

答案 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很可能会受到一些攻击,因此它肯定是高风险的。如果您继续使用它,那么我将考虑包括的一个检查是使您希望以这种方式访问​​的任何类实现特定接口并在执行之前检查接口。这样可以防止以任何方式执行任意类,并将其限制为您特别允许的那些。

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