Синтаксис составления запросов, гарантирующий от взлома

Фанат

oncle terrible
Команда форума
Синтаксис составления запросов, гарантирующий от взлома

Решил я тут попробовать систематизировать это дело в виде двух пар правил.
Поскольку одна голова всяко хуже, чем миллион леммингов, то прошу высказываться.
Всё ли понятно написано, а - главное - все ли случаи учтены.

Основная задача - формализовать правила так, чтобы при их соблюдении достигалась 100%-я гарантия безопасности.
К примеру, для пхп скриптов такие правила написать довольно затруднительно - они получатся слишком длинными и конкретными, для каждого случая. Для SQL(MySQL) же, как мне кажется, возможно составить набор ПРОСТЫХ правил, соблюдая которые можно гарантировать безопасность.

Правила эти делятся на две группы.
1. Все значения полей, которые используются в запросе, дожны быть
- заключены в кавычки
- к ним должна быть применена функция mysql_real_escape_string()
2. Все остальные части запроса, которые меняются в зависимости от выбора пользователя, ни в коем случае не должны подставляться напрямую, а только в виде результатов вычислений.
То есть:
- Если параметр имеет строковый тип, то все возможные значения должны быть прописаны в скрипте заранее. И уже из них выбирается нужное на основании выбора пользователя.
- если параметр является числом, то обязан получаться в результате арифметического выражения.
К примеру, все поля, по которым производится сортировка, должны быть прописаны в массиве, индексами которого являются значения, которые выбирает пользователь.
Цифры для лимита должны быть результатом арифметического выражения, и так далее.
То есть, повторюсь - операторы SQL не должны ни в коем случае попадать в запрос напрямую, а могут только служить исходными данными для выражения, которое и вернёт нужный параметр. То есть, скрипт не должен их ПРОВЕРЯТЬ, и после проверки подставлять. В этом подходе изначально заложена ошибка. а должно быть именно только так, чтобы строка, переданная от пользователя, ни в каком виде не попадала в запрос ввиде оператора.
Речь во второй части, повторюсь, идёт об ОПЕРАТОРАХ, т.е. о любых частях запроса, которые не являются значениями полей.

Вторая часть правил получилась длинноватой, и это настораживает.
 

Develar

Новичок
1) Надо бы сказать о PDO - это расширение предоставляет большие возможности, то есть фразу после mysql_real_escape_string() надо продолжить описанием альтернативных функций экранирования.
2)
То есть, повторюсь - операторы SQL не должны ни в коем случае попадать в запрос напрямую, а могут только служить исходными данными для выражения, которое и вернёт нужный параметр
Здесь следовало бы сказать и об уменьшении сложности программы, то есть при вынесении таких операций в отдельный метод - вы не только делаете код безопасным, но и легким для сопровождения и понимания

PHP:
$Db = Db::$pdo->prepare("SELECT
SQL_CALC_FOUND_ROWS objects.uri, objects.id, objects.title, producer.title AS producer, series.title AS series 
FROM conditioner  
LEFT JOIN objects USING (id)  	
LEFT JOIN producer ON producer.id = conditioner.producer  				
LEFT JOIN series ON series.id = conditioner.series  		" . $this->getWhere() . "  " . $this->getOrder() . " " . $this->getLimit());
То есть при чтении запроса вы не вникаете в $this->getLimit(), а спокойно читаете и понимаете из понятного имени метода что он делает, а в противном случае Вам бы пришлось читать ещё 20 строчек ненужного вам в данный момент кода.
 

Фанат

oncle terrible
Команда форума
это всё частности. реализация.
пишите, пожалуйста, по теме.
 

ONK

Пассивист PHPСluba
Фанат, думаю, что если вторую часть правила разбавить краткими примерами кода, то она будет выглядеть понятнее и продуманнее. В остальном всё вполне нормально.
Единственное что в выражение "Цифры для лимита должны быть результатом арифметического выражения" подстроку "должны быть результатом арифметического выражения" на мой взгляд, стоит заменить на что-то вроде "должны приводиться к необходимому типу данных (целочисленному, беззнаковому типу)". То, каким образом они приводятся к этому типу, уже не имеет значение.
 

Фанат

oncle terrible
Команда форума
я думал об этом.
но моей задачей было вывести всеобъемлющее правило.
"привести" - это значит "обработать". а я пытаюсь как раз уйти от _обработки_.
значения полей - ОБРАБАТЫВАЕМ.
остальные части запроса - не подставляем ни под каким видом, с обработкой или без. только в два действия. только, как источник.
вот основная мысль.
не уверен, что правильная
 

svetasmirnova

маленький монстрик
остальные части запроса - не подставляем ни под каким видом, с обработкой или без. только в два действия. только, как источник.
вот основная мысль.
Чтобы это понять из первоначальной формулировки, мне её пришлось перечитать раз 5 :)
 

Фанат

oncle terrible
Команда форума
ага.
это ценное замечание.
надо будет переписать.
а сама мысль - как? можно ли уложить в неё все случаи, встречающиеся в жизни?
 

Profic

just Profic (PHP5 BetaTeam)
По моему скромному мнению, в этих правилах упомянуты все принципиально различные случаи. Однако я попробовал их немного сократить.

Правила делятся на две группы:
1. Все значения полей, которые используются в запросе, должны:
- или заключаться в кавычки и экранироваться функцей mysql_real_escape_string()
- или пропускаться через механизм placeholder-ов
2. Все остальные части запроса, которые меняются в зависимости от выбора пользователя должны:
- строковые - браться из списка заранее определенных значений, которые выбираются на основе пользовательского ввода.
- числовые - быть результатом арифметических вычеслений
То есть, скрипт не должен их ПРОВЕРЯТЬ, и после проверки подставлять. В этом подходе изначально заложена ошибка. Должно быть именно только так, чтобы строка, переданная от пользователя, ни в каком виде не попадала в запрос ввиде оператора.
Речь во второй части, повторюсь, идёт о любых частях запроса, которые не являются значениями полей.

Незачем расписывать вторую часть так сильно, так, по-моему, короче и понятнее.
Не знаю, стоит ли упомянуть про LIKE и RLIKE. С одной стороны при следовании этим правилам это не будет дырой для взлома, но с другой в результате может получиться совсем не то, что предполагал программист.

ЗЫ. Упс, пока писал, появились новые сообщения...
 

Фанат

oncle terrible
Команда форума
про лайк уже написано.
PHP FAQ: \"Кавычки \". Особенности работы с оператором LIKE
и я очень надеюсь, что тема лайка на этом закрыта =)
Хотя я точно так же каждый раз надеялся, когда переписывал фак очередной раз кардинально =)

-~{}~ 04.12.05 13:46:

механизм placeholder-ов РЕАЛИЗУЕТ описанные здесь правила.
реализацию можно рассматривать отдельно.
но не здесь.
механизм не делает ничего такого, чего не делает прослешивание/обкавычивание. это просто инструмент.
 

svetasmirnova

маленький монстрик
>можно ли уложить в неё все случаи, встречающиеся в жизни?
Похоже что можно.
Исключение: приложения типа phpMyAdmin. Но это совсем другая история.
 

Фанат

oncle terrible
Команда форума
параллельно к этому тексту появилось ещё две мысли.
1. я тут одно время толкал со страшной силой идею о том, что не бывает SQL-инъекций - бывает несоблюдение синтаксиса. Относительно первой части это верно. а вот вторая - это, как раз, и есть мишень для инъекций. был неправ.

2. Часто задают вопрос о безопасности пхп скриптов.
правило 2.1 - это как раз оно и есть, наверное.

как вам такой ответ на вопрос "как писать безопасные скрипты на пхп?" (в части взлома именно пхп, не ХСС):
1. не использовать получаемые от пользователя данные напрямую, а только как индексы для выбора заранее прописанных в скрипте параметров.
2. все данные хранить в мускуле - там возможна надёжная работа с любыми данными без опасности взлома.
 

Profic

just Profic (PHP5 BetaTeam)
Механизм плейсхолдеров реализует только первый подпункт первого пункта. Т.е. в первом пункте получается альтернатива или кавычки и mysql_real_escape_string(), или placeholder-ы. Хотя для LIMIT-а их, вроде, тоже можно использовать, а вот для подстановки имен полей - нет.
 

svetasmirnova

маленький монстрик
>все данные хранить в мускуле
А в постгресе нельзя ;) ?
Вообще-то если соблюдать правило №1 данные можно хранить где угодно. Или при записи в файл может произойти что-то непредвиденное?
 

Фанат

oncle terrible
Команда форума
ты гонишь.
механизм плейсходеров именно для того и нужен, чтобы реализовать ОБА пункта.
иначе грош ему цена. это будет не маханизм плейсхолдеров, а погремушка.

по-моему, ты не очень хорошо понимаешь, что это за механизм.
или я.
я знаком с двумя реализациями - PEAR DB и котерова.
оба они не заменяют, естественно, обкавычивание/прослешивание, а применяют их. разве не так?

для лимита плейсхолдеры использовать можно, наверное, если указывать тип передаваемого параметра. Только это кажется мне неуниверсальным.

-~{}~ 04.12.05 14:20:

svetasmirnova
К сожалению, правило номер 1 неприменимо ко всем случаям жизни.
да и вообще, глупость я написал
 

Profic

just Profic (PHP5 BetaTeam)
Фанат
Моя ошибка в том, что я не сказал, что я имею ввиду нативную реализацию placeholder-ов. Т.е. ту, которую предоставляет php в mysqli/pdo_mysql

The parameter query can include one or more parameter markers in the SQL statement by embedding question mark (?) characters at the appropriate positions.

Note: The markers are legal only in certain places in SQL statements. For example, they are allowed in the VALUES() list of an INSERT statement (to specify column values for a row), or in a comparison with a column in a WHERE clause to specify a comparison value.

However, they are not allowed for identifiers (such as table or column names), in the select list that names the columns to be returned by a SELECT statement, or to specify both operands of a binary operator such as the = equal sign. The latter restriction is necessary because it would be impossible to determine the parameter type. It's not allowed to compare marker with NULL by ? IS NULL too. In general, parameters are legal only in Data Manipulation Languange (DML) statements, and not in Data Defination Language (DDL) statements.
(c) [m]mysqli_prepare[/m]

pdo_mysql вообще тупо берет значения в кавычки потому PDO::prepare('select * from ?') с последующим PDOStatement::execute(array('table')) приводит к 'select * from "table"', на что MySQL, еcтественно, ругается матом.
 

Develar

Новичок
К сожалению, правило номер 1 неприменимо ко всем случаям жизни. да и вообще, глупость я написал
IMHO, всем этим правилам грош цена. Они могут служить только как шпора-самопроверка, выжимка мысли для профессионала, а для новичка
Чтобы это понять из первоначальной формулировки, мне её пришлось перечитать раз 5
не поможет и 20 раз прочесть, или он будет тупо применять, не понимая что делает - а это путь в никуда.
Чтобы понять что-то, делать что-то осознано - нужны статьи, учебники (которые уже написаны). Их нужно прочесть и переварить.
Если целью разработки данных правил является помощь новичкам - это не поможет. Новичок должен понять сущность объекта познания, один интерфейс данного объекта познания ему ничего не даст - инструкция по использованию бензопилы не предотвратит несчастный случай. Как только он поймет сущность объекта познания он поймет и все производные от этой сущности объекты.

Поэтому Вы вполне закономерно пришли к выводу
да и вообще, глупость я написал
потому что все что мы говорим - уже давно ясно и написано в "умных книжках" и разговор изначально является кандитатом в мусор.
 

Фанат

oncle terrible
Команда форума
кстати, о PDO и прочих плейсхолдерах.
эти механизмы реализуют механизм применения ПЕРВОЙ пары правил.
а о второй, как это ни печально, приходится думать ВСЁ РАВНО

-~{}~ 05.12.05 14:29:

вот, блин, пример жертвы плейсхолдеров.
http://phpclub.ru/talk/showthread.php?s=&threadid=77270
он В ЖИЗНИ НЕ ВИДЕЛ SQL запроса.
он знает только вопросики и стрелочки.

один вред, блин, от этих суррогатов.
 

Grumbold

Новичок
наверно, можно воспользоваться хранимыми процедурами.
передавать в нее введенные пользователем параметры и там же отслеживать корректность
я делал так в MSSQL Server. в MySQL - не знаю, не пробовал, но с 5-ой версии он (вроде бы) поддерживает триггеры и хп
 

tf

крылья рулят
Grumbold >>передавать в нее введенные пользователем параметры и там же отслеживать корректность
проверка некорретных данных объектом взлома мягко сказать некорретно
 
Сверху