3

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

4

3 回答 3

2

首先,

您需要创建一个白名单。

你得到对象的定义函数,然后检查发送给你的函数名是否在数组中,如果是,很好,否则,忘记它。

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

您需要为所有传递的值创建一个 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
    }
}
于 2010-01-14T18:52:45.723 回答
2

您可以在不使用 ReflectionXYZ 类的情况下实现相同的目的

call_user_func( array($this->instance, $action) , $args);

两者都以相同的方式保存,只要您控制 $this->instance 是什么。
$action 是一个字符串,用于搜索对象/类方法哈希表中的条目,并且没有可以转义对象上下文(切换到另一个对象)的魔术符号。并且不涉及解析,例如在 sql 和 sql 注入中。
ReflectionMethod 和 call_user_func_array() 都遵循方法的保护级别。例如

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

如果总是这样,您可能需要查找。例如有一个 entry - MFH Fixed bug #37816 (ReflectionProperty does not throw exception when accessing protected attribute)。至少对于 php 5.3 分支是这样。
您始终可以访问 $this->instance 的任何基类的公共方法。
您可以从类上下文中访问受保护的方法,即如果 $this 和 $this->instance 是相同的/$this->instance 的派生类型受保护的方法是可访问的。例如

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。但这不应该太难避免。

于 2010-01-14T19:13:05.590 回答
0

允许用户输入 PHP 代码的东西很可能会受到一些利用,所以它肯定是高风险的。如果您确实继续使用它,那么我会考虑包括的一项检查是使您希望以这种方式访问​​的任何类都实现特定的接口并在执行之前检查该接口。这将阻止任何任意类以这种方式执行,并将其限制为您明确允许的类。

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

于 2010-01-14T18:19:35.043 回答