代码之家  ›  专栏  ›  技术社区  ›  Blixt

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

  •  2
  • Blixt  · 技术社区  · 15 年前

    我正在编写一个类,该类允许您使用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 回复  |  直到 15 年前
        1
  •  2
  •   VolkerK    15 年前

    您可以在不使用ReflectionXYZ类的情况下实现这一点

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

    而且,只要您控制$this->实例是什么,这两种方法都是以相同的方式保存的。
    $action是一个字符串,用于在对象的/class'方法哈希表中搜索条目,并且没有可以转义对象上下文(切换到另一个对象)的魔力符号。而且不需要像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
    

    如果情况总是这样的话,你可能会想看看。有一个条目 - MFH Fixed bug #37816 (ReflectionProperty does not throw exception when accessing protected attribute) .至少对于php 5.3分支来说是这样的。
    您始终可以访问$this->实例的任何基类的公共方法。
    您可以从类上下文中访问受保护的方法,例如,如果$this和$this->实例具有相同的/a派生类型,则可以访问$this->实例的受保护方法。例如

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

        2
  •  1
  •   J. Martin    15 年前

    首先,

    你需要创建一个白名单。

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

    您可以选择自动白名单,也可以选择配置的手动白名单。

    您需要为所有传递的值创建一个Munging/Washing函数。

    在一个州的例子中,州可以是CA,也可以是加利福尼亚,所以本质上,它必须preg_match(“/\w+/”),这样您就可以做一些简单的检查来验证数据。

    如果你想花哨点,你可以允许人们创建一个名为allowedvalues的方法,它是函数name=>/regex/的散列映射,并将其用作有效的数据查找表。如果函数没有在类中定义,你可以使用只允许字符串/数字和特定长度的perhop的通用方法。

        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
        }
    }
    
        3
  •  0
  •   Karl B    15 年前

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

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