А если у меня quote_chars включены, то запрос будет таким? Он отработает вообще?
ORDER BY `me`.`id`, `(select 1 from (SELECT name, CASE name='first' WHEN FALSE THEN pg_sleep(0) ELSE pg_sleep(10) END from users) as t limit 1)` ASC 2015-12-24 23:47 GMT+03:00 Grigory Batalov <[email protected]>: > Всем привет! > > Коллеги нашли в моём коде уязвимость, спешу поделиться, как не надо писать :) > Мне эта тема кажется интересной, может ещё кому-то пригодится. > > В одном веб-проекте я использую фреймворк Mojolicious, плагин jQuery > dataTables.net и ORM DBIx::Class. DataTables (в режиме serverSide: true) > получает от сервера JSON и заполняет таблицы, которые можно сортировать > по колонкам или применить фильтр поиска. При сортировке или фильтрации > на сервер поступает новый запрос и приходит новый JSON-ответ, заполняющий > таблицу. > > Параметры запроса примерно такие: > columns[0][data] "username", > columns[0][name] "", > columns[0][orderable] "true", > columns[0][searchable] "true", > columns[0][search][regex] "false", > columns[0][search][value] "", > columns[1][data] "filename", > columns[1][name] "", > columns[1][orderable] "true", > columns[1][searchable] "true", > columns[1][search][regex] "false", > columns[1][search][value] "", > length 10, > order[0][column] 1, > order[0][dir] "asc", > search[regex] "false", > search[value] "", > start 0 > > Конечно, я не разбираю их вручную, а поручаю это модулю > JQuery::DataTables::Request. Как видите, в запросе указан номер колонки > для сортировки (order) и направление. > > my $req = > JQuery::DataTables::Request->new( > client_params => $self->req->body_params->to_hash ); > > my $sort_column = $req->column( $req->order(0)->{'column'} )->{'data'}; > my $sort_direction = $req->order(0)->{'dir'}; > > DBIx::Class же умеет сортировать выборку из таблицы в базе данных > (resultset) так: search( {...}, { order_by => { -desc => 'filename' } } ). > Заманчиво указать прямо здесь параметры, полученные от dataTables :) > > my $files = $schema->resultset('File')->search( > { purge => 0 }, > { order_by => { "-$sort_direction" => $sort_column } > ); > > DBIx::Class (посредством SQL::Abstract) обычно формирует запрос с > подстановками > типа > > SELECT filename FROM files WHERE SIZE > ? LIMIT ? : '1024', '10' > > Но не в этом случае! Если вмешаться в запрос и в колонку вписать > > columns[1][data] "id, (DELETE FROM files;)" > > в SQL-запросе появится непосредственно > > ORDER BY id, (DELETE FROM files;) ASC > > К счастью, такие наивные попытки уязвить базу данных пресекаются проверкой > в SQL::Abstract: > > SQL::Abstract::puke(): [SQL::Abstract::_assert_pass_injection_guard] > Fatal: Possible SQL injection attempt 'id, (DELETE FROM files;)' > If this is indeed a part of the desired SQL use literal SQL ( '...' or [ > '...' ] ) > or supply your own {injection_guard} attribute to DBIx::Class::SQLMaker->new() > > Тем не менее, есть и более изощрённые методы. Что произойдёт, если вместо > названия колонки указать > > columns[1][data] "id, (select 1 from (SELECT name, CASE name='john' WHEN > FALSE THEN pg_sleep(0) ELSE pg_sleep(10) END from users) as t limit 1)" > > ? (это PostgreSQL) В хвосте SQL-запроса окажется > > ORDER BY me.id, (select 1 from (SELECT name, CASE name='first' WHEN FALSE > THEN pg_sleep(0) ELSE pg_sleep(10) END from users) as t limit 1) ASC > > Т.е. помимо выполнения обычного запроса (он не испорчен), произойдёт поиск > пользователя > john в таблице users. При неудаче ответ вернётся сразу, а в случае успеха - > через 10 сек. > Таким образом, злоумышленник, генерируя запросы через веб-интерфейс, может > перебором > определить содержимое таблицы! Такой "слепой" метод доступа к базе данных > называется > Blind SQL Injection и широко используется нашими нечистоплотными коллегами. В > сети > есть автоматические средства для перебора. > > Подытоживая эту историю, посыпаю голову пеплом и напоминаю, что никаким > входным данным > нельзя доверять! :) Любая мелочь может привести если не к порче информации, > то к утечке. > > Я же вынес сортировку в отдельный файл ResultSet/File.pm (там ещё кое-что > есть), > добавив проверку: > > # apply sorting order > sub order_by { > my $self = shift; > my ( $column, $direction ) = @_; > > # an unknown column name is given > return $self if none { $_ eq $column } $self->result_source->columns; > > # sanitize order direction > $direction = 'ASC' if uc $direction ne 'DESC'; > > return $self->search( undef, { order_by => { "-$direction" => > "me.$column" } } ); > } > > Используется так: > > my $files = $schema->resultset('File')->search( { purge => 0 } ) > ->another_filter > ->order_by( $sort_column, $sort_direction ); > -- > Moscow.pm mailing list > [email protected] | http://moscow.pm.org -- //wbr, Dmitry L. -- Moscow.pm mailing list [email protected] | http://moscow.pm.org
