Как избежать атак инъекций в PHP? - PullRequest
2 голосов
/ 14 января 2010

Я пишу класс, который позволяет связывать HTTP-запросы с экземплярами классов, используя JSON для данных, без какой-либо реализации в классе, к которому вы подключаетесь. Вот как это работает:

// 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 ]

2 голосов
/ 14 января 2010

Вы можете достичь того же, не используя классы 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

Возможно, вы захотите посмотреть, если это всегда было так. Там, например, запись - 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. Но этого не должно быть слишком трудно избежать.

1 голос
/ 14 января 2010

Прежде всего,

Вам необходимо создать white_list.

Вы получаете определенные функции объекта и проверяете, находится ли отправленное вам имя функции вмассив, если это хорошо, иначе забудьте об этом.

Вы можете создать автоматический белый или настроенный вручную белый список.

Вам необходимо создатьфункция обрезки / стирки для всех пройденных значений.

В примере штата, штат может быть CA или California, поэтому, по сути, он должен быть preg_match ('/ \ w + /'), чтобы вы могли легко проверить данные.

Если вы хотите получить фантазию, вы можете позволить людям создать метод с именем allowValues, который представляет собой хэш-карту functionName => / Regex /, и использовать его в качестве допустимой таблицы поиска данных, если функция не определенакласс, вы используете универсальный, который позволяет только строки / числа и перфорации только определенной длины.

    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
    }
}
0 голосов
/ 14 января 2010

Anthing, который позволяет вводить пользовательский код PHP, вероятно, будет открыт для некоторой эксплуатации, так что это, безусловно, высокий риск. Если вы продолжите в том же духе, то я хотел бы рассмотреть одну проверку, в том числе: заставить все классы, к которым вы хотите получить доступ, таким образом, реализовать определенный интерфейс и проверить интерфейс перед выполнением. Это предотвратит выполнение любого произвольного класса таким способом и ограничит его только теми, которые вы специально разрешили.

Лучшим решением может быть автоматическая генерация статических файлов со всеми необходимыми вызовами, чтобы вы явно разрешали конкретные действия, а не пытались угадать, где могут быть все дыры.

...