Что такое SQL инъекция и как от неё защищаться
ВступлениеЧасть первая. “Кто виноват или Надо ли защищаться от инъекций?”
Часть вторая, “Что делать или Правила форматирования”.
Комментарии (2)
Черновик текста доклада "Окончательное решение проблемы SQL инъекций" c конференции DevConf 2013.
Вступление
Для начала - небольшой дисклеймер, поскольку обманутые ожидания могут испортить впечатление от самого лучшего мероприятия. К примеру, как-то давно, в эпоху видеосалонов, я пошел на фильм, который считал боевиком, и который показался мне чудовищной халтурой и клюквой. И только на середине я догадался, что этот фильм не боевик, а пародия на боевики. И заржал в совершенно неподходящем месте.
Поэтому должен предупредить - никаких ошеломляющих открытий, зловещих инъекций и срывов покровов не будет. Моя задача - проанализировать существующие решения, выявить их сильные и слабые стороны, и предложить некоторое общее правило, которое будет работать не только на бумаге, но и в реальной жизни.
Я догадываюсь, что многие пришли настроенными довольно скептически. Мол, "ну сколько можно про инъекции? В детском саду их прошли и забыли". Проблема как раз в том, что в детском саду учатся еще не пониманием, а запоминанием.
И запоминают некоторый свод правил, который, к сожалению, работает не всегда.
Давайте для начала рассмотрим историю вопроса:
Слайд
============
Как происходит типичный диалог:
- Как защититься от инъекций?
- используй prepared statements
- а что делать если они не подходят
- нннууу... вот тебе воркараунд.
- а вот у меня другой случай, и твой воркараунд не подходит
- ннуууу... вот тебе другой воркараунд
- а вот...
===============
Как-то это выглядит не слишком заманчиво.
Методологически ничем принципиально не отличается от "искейпь входящие данные". А для всех остальных случаев - воркараунд.
Но самое ужасное, что наличие этих воракраундов - это повторение ситуации "кто в лес, кто по дрова", и в результате программист пишет воркараунды сообразуясь со своим пониманием вопроса. А понимание там часто - аховое. И этот сон разума порой рождает таких чудовищ, что хочетcя плакать от ужаса. Пример я приведу ниже.
Поэтому нам нужен более последовательный и логичный механизм.
И вот я предлагаю сначала выработать теоретические основы этого механизма, а потом подумать над тем, как его практически реализовать.
Также прошу не делать стойку на то, что я буду вначале уделять много внимания форматированию. О подготовленных выражениях, которые на данный момент считаются вершиной технической мысли в защите от инъекций, мы обязательно поговорим - но позже.
Доклад будет будет состоять из трех частей, характеризуемых извечными русскими вопросами - “кто виноват”, “что делать” и “как нам теперь со всей этой фигнёй взлететь”.
Да, и "разное". Конечно же - "разное".
Часть первая. “Кто виноват или Надо ли защищаться от инъекций?”
Несмотря на всю провокационность этого вопроса, ответ - НЕТ.
Это очень легко доказать.
Я думаю,всем знаком этот малолетний, эээ... долботряс с заковыристой фамилией? И комикс, из которого каждый разработчик уяснил себе, что пользовательский ввод надо обязательно дезинфицировать, делать безопасным?
слайд
-------------------------
$name = "Bobby';DROP TABLE users; -- ";
$query = "SELECT * FROM users WHERE name='$name'";
FAIL
-------------------------
Ну ок, уяснили. Но что если у нас решил зарегистрироваться не малолетний хакир, а честный шевалье Д’Артаньян? Уж этот-то защитник сирот и утешитель вдов никогда не позволит себе сделать какую-нибудь пакость типа инъекции. Защищаться, вроде бы, не от чего. Но зарегистрироваться у него все равно не получится.
Ещё пример. Допустим, у нас нет никакого пользователя вообще, а есть похапист... назовем его Расмус. Который вообще ничего не добавляет в запрос динамически, а тупо пишет его от руки.
слайд
-------------------------
$sql = “SELECT group FROM table ";
Снова FAIL.
------------------------
Но у него все равно ошибка. Почему? Да потому что он, как и все остальные, не отформатировал свой запрос правильно.
слайд
-------------------------
Три картинки - Бобби, Дартаньян и Расмус - что у них общего
------------------------
Фишка в том, что элементы запроса мы должны форматировать в любом случае.
От пользователя ли они пришли, или из нашей базы, или их вообще админ написал, или робот сгенерил -
Слайд
-----------
ИСТОЧНИК данных не имеет вообще никакого отношения к форматированию запросов.
-----------
Это очень важная вещь для понимания дальнейшего материала. И одновременно одно из самых больших заблуждений разработчиков - что “защищать” надо только пользовательский ввод. Та же мамаша нашего Бобби Фейсом-об-тейбл говорит про “инпут”. Но на примере Расмуса мы видим, что форматировать надо всякий элемент запроса, а не только “пользовательский ввод”.
Просто потому что
Слайд
------
SQL запрос - это программа.
-----
Нормальная программа, такая же как наш РНР скрипт. А всякая программа - я думаю, никто не будет с этим спорить - будет работать только если в ней всегда соблюдается корректный синтаксис.
И вот соблюдение корректного синтаксиса и должно являться нашей целью. А защита будет обеспечена просто в виде побочного эффекта.
Самое главное что нужно понимать - это то, что мы формируем эту программу динамически.
Страшно представить себе, что из себя представляли бы скрипты, если бы средний пользователь РНР собирал их динамически, так же, как запросы. Впрочем, даже и в статике некоторые пользователи умудряются-таки накосячить. Пример из моей богатой практики:
Слайд
-----------------
$s = fread("$f",7);
-----------------
- это написал один юзер и долго удивлялся, почему у него ничего не работает.
Это очень показательный, на самом деле, пример. Не секрет, что новички обожают обращаться к переменным, заключая их в кавычки. ПХП же, так же как и мускуль, прощает, до поры-до времени, вольное обращение с форматированием. Но когда когда не прощают - бьют прямо в темечко.
Слайд
-------------
"хорошо зафиксированный пациент в анестезии не нуждается"
-------------
Итак. Надеюсь, что смог убедить вас в том, что запросы надо не защищать, а корректно форматировать. Перефразируя известное медицинское изречение - Корректно отформатированный запрос в защите не нуждается.
Часть вторая, “Что делать или Правила форматирования”.
Сформулируем 4 правила корректного составления запросов.
1. Форматирование должно быть ПОЛНЫМ.
потому что если оно не будет полным, то полным будет пушистый зверек, который к нам придет.
Слайд:
-------------------
Типичные примеры неполного форматирования
$id = $mysqli->real_escape_string($id)
$sql = "SELECT * FROM $table = $id"
$sql = "SELECT * FROM `$table`"
---------------------------------
при этом первый пример на самом деле простителен
поскольку на протяжении многих поколений в пхп разработчиков вбивали мысль, что "mysql_real_escape_string защищает от инъекций". Вот они и защищаются. Хотя на самом деле делают дыру у себя в приложении размером с пробоину Титаника. А все потому, что
слайд
-------------------------------------
mysql(i)_real_escape_string
НЕ ИМЕЕТ ни малейшего отношения
- К SQL инъекциям
- К защите от чего бы то ни было
Имеет отношение
- к Форматированию строк
- для этого форматирования недостаточна
--------------------------------------
Что же на самом деле делает эта функция?
Разумеется, никого ни от кого она не защищает. А всего лишь только форматирует данные для использования их в строковом литерале SQL. Из чего мы можем сделать два вывода.
1. применение этой функции должно быть ВСЕГДА сопряжено с заключением обработанного текста в кавычки.
2. Без кавычек результат этой функции не имеет ни малейшего смысла, и, как следствие, никакой защиты от инъекции не даст.
В этом смысле идеальным примером может являться функция PDO::quote(), которая, единственная из всех известных мне функций АПИ, делает полное форматирование - И квотинг И искейпинг.
Но у нее все равно есть один принципиальный недостаток, о котором мы поговорим ниже.
2. Форматирование должно быть адекватным.
слайд
-----------------------------------------------------------
Типичнейший пример неадекватного форматирования
$table = $mysqli->real_escape_string($table);
$sql = "SELECT * FROM `$table`"
(картинка фейспалм)
--------------------------------------------------------------
Здесь к идентификатору применяется форматирование от строк. Результат немного предсказуем.
ещё один пример чудовищно неадекватного форматирования я обнаружил совсем недавно:
В комментариях к функции PDO::quote() в мануале почти год висела вот такая дичь, набрав аж 8 положительных оценок.
Слайд
----------------
While rewriting some application to PDO, remember that PDO->quote is adding the quotes around the whole value! Compared to mysql_real_escape_string which is quoting only the dangerous characters.
<?php
$value = "hello's world";
echo mysql_real_escape_string($value);
// hello''s world
echo $dbh->quote($value);
// 'hello''s world'
// This second quoting will break your old SQL statements which includes the quotes already. Workaround is to remove first and last character
echo substr($dbh->quote($value), 1, -1);
// hello''s world
?>
----------------------
После того, как я его обнаружил, этот коммент потерли, но это очень хорошая иллюстрация того, к чему приводит самодеятельность пхп программистов в деле защиты от инъекций.
поэтому надо четко знать - в каких случаях какое форматирование применять
вот небольшой список того, как должны форматироваться различные элементы запроса:
Слайд
------------------------
1. Строки
* могут быть добавлены через native prepared statement (работает не всегда)
или
* должны быть заключены в кавычки
* спецсимволы (грубо говоря - те же самые кавычки) должны быть экранированы
* плюс должна быть установлена правильная кодировка клиентской библиотеки.
2. Числа
* могут быть добавлены через native prepared statement (работает не всегда)
или
* должны быть отформатированы так, чтобы содержать только цифры, знак и - для соответствующего типа - точку
3. идентификаторы
* должны быть заключены в обратные кавычки
* спецсимволы (грубо говоря - те же самые обратные кавычки) должны быть экранированы
4. Операторы и ключевые слова
* тут нет специальных правил форматирования, за исключением того, что они должны быть законными операторами и ключевыми словами
-------------------
Как видим, правил не одно и даже не два. Одних типов форматирования 4 штуки (на самом деле, их ещё больше, но об этом - позже). И весь этот список необходимо постоянно держать в голове и не перепутать. Если мы не найдем подходящего решения...
Но - перейдем к следующему пункту
3. Форматирование должно быть ОБЯЗАТЕЛЬНЫМ
С одной стороны, важность этого пункта объяснять не приходится. С другой - постоянно можно слышать от ленивых (в плохом смысле слова) разработчиков - да зачем это значение форматировать - мы его и так знаем! И вот здесь надо вести понятие динамических данных.
Если для константы, для элемента запроса, прописанного в скрипте, форматирование может быть опциональным, то для динамических, ПЕРЕМЕННЫХ частей запроса, оно должно быть ОБЯЗАТЕЛЬНЫМ. Мы НЕ МОЖЕМ знать, что лежит в переменной. Программы всякие бывают. В программах бывают ошибки.
Которые могут привести к непредсказуемому значению переменной.
поэтому.
Хотя константную часть, разумеется,подвергать строгому форматированию не обязательно, переменные части запроса должны форматироваться в обязательном порядке.
4-е и последнее (по счету, но не по важности!) правило:
4. Форматирование должно производиться КАК МОЖНО БЛИЖЕ к выполнению запроса.
Это тоже на самом деле очень важный момент, если над ним задуматься.
Понимание важности этого правила начало потихоньку приходить к сообществу, но очень фрагментарно и толком не сформулированное.
Самое большое количество инъекций происходит оттого, что обработка данных для запроса и помещение их в запрос оказываются разнесены по коду. Что сразу создает почву для нарушения предыдущих трех правил.
Примеры:
В первую голову приходят, конечно, волшебные кавычки. Которые пытались форматировать данные заранее, при этом неизвестно было - ни пойдут ли они в запрос вообще, ни - в каком формате - налицо нарушение правил 1 и 2: волшебные кавычки делают неполное форматирование и вдобавок мы не можем знать, какого типа данные прйдут в запрос.
Но даже и без волшебных кавычек форматирование данных и исполнение запроса часто оказываются довольно-таки сильно разнесены в коде. И здесь мы можем придти к нарушению третьего правила
Приведу пример.
В одной компании использовался великолепный движок, в котором была могучая фильтрация входящих параметров.
Если по логике приложения от клиента приходить должна цифра - то ты мог быть уверен, что это будет цифра. Валидировал вообще ВСЁ что движется, в соответствиями требований SEO любое расхождение с ожидаемыми параметрами вызывало 404.
Все привыкли и никто по поводу инъекций не парился
Но потом пришлось написать небольшой код, который должен был запускаться до всех валидаций, и инитить одну переменную из реквеста.
а потом, сильно ниже по коду, эту переменную задействовали в запросе
и никакой валидации не сделали - привыкли же.
В системе, которую делают несколько разработчиков, риск повышается - у семи нянек дитя без глазу.
Давайте рассмотрим два примера кода
Слайд
----------------------------------
$sql = 'SELECT * FROM users WHERE email='.PDO::quote($email);
$res = $pdo->query($sql);
$sql = 'SELECT * FROM users WHERE email=?';
$res = $pdo->prepare($sql);
$res->execute(array($email));
----------------------------------
При настройках по умолчанию, эти два куска кода отправят на сервер два ИДЕНТИЧНЫХ запроса.
Но при этом первый практически не пропагандируется, а про второй вам трендят на каждом углу.
Зачем же платить больше?
А вот именно затем: плейсхолдер обеспечивает и форматирование гарантированно, и как можно ближе к исполнению.
[namw=three]Часть третья. Как нам со всей этой фигней взлететь, или типизованные плесхолдеры.[/name]
А теперь посмотрим, какие есть средства этого добиться.
Подготовленные выражения же!
НО! Совсем не то жалкое подобие левой руки на два типа данных, которое нам втюхивают производители API. А идея подготовленного выражения в целом.
Здесь я хочу разграничить понятия:
Слайд
----------
- “Родные” подготовленные выражения, поддерживаемые на уровне сервера. Данные отправляются на сервер отдельно от запроса
- сама идея подготовленного выражения в целом, когда занные представлены в запросе неким представителем, плейсхолдером, который при окончательной обработке заменяется на актуальные данные
---------------
Вообще, я должен признать, что идея родных подготовленных сама по себе отличная - поскольку она реализует фундаментальный принцип разделения кода и данных. Код (запрос) и данные передаются на сервер раздельно, и данные не имеют возможности никаким образом повлиять на код.
Но... чрезвычайная ограниченность сводит все преимущества на нет.
Еще один минус родных (т.е. - поддерживаемых безой) подготовленных выражений - то, что они работают не всегда.
Слайд
-------------------
Prepared statements не поддерживаются
- для идентификаторов
- для массив для оператора IN().
- для массив для INSERT/UPDATE.
------------------
И, самое главное - они не поддерживают все типы данных, которые мы можем отправить в запрос.
Почему нам нужны плейсхолдеры для ин и для сет?
А потому что такие штуки все равно добавляются в запрос, но делается это руками.
То есть, мы вернулись к тому, от чего ушли - ручная сборка запроса и функции!
здесь надо остановиться поподробнее. Про подготовленные выражения рассказывают много ерунды, но почти никто при этом не упоминает ни их ограниченности, ни по-настоящему сильных сторон.
И тут мы упираемся в чудовищную ограниченность родных подготовленных выражений. НА САМОМ ДЕЛЕ нам нужно гораздо больше плейсхолдеров, чем предлагают родные prepared
Если посмотреть на наши запросы не предвзято, то мы увидим, что помимо банальных скаляров, которые, в сущности, практически всегда можно прослешить и окавычить, в запрос могут попадать такие элементы, как
Не будем закрывать глаза и прятать голову в песок, воображая, что добавлять идентификатор нам никогда не понадобится. В реальной жизни - понадобится.
поэтому надо просто иметь плейсхолдер для добавления идентификаторов. Вот и всё.
Дальше интереснее. Если смотреть с точки зрения приложения(!) в запрос могут опадать и комплексные типы! Например:
Вы, конечно, по привычке скажете, что это не массив, а динамический набор переменных, для которых можно динамически сформировать запрос. Вам самим не смешно? :) За что боролись - на то и напоролись. Хотели уйти от ручного формирования запросов, и к нему же и пришли! Не говоря уже о том, что некоторые АПИ превращают такую банальную операцию в АД.
Поднимите руки, кто пробовал забиндить в mysqli IN с переменным числом параметров.
Кто не пробовал - рекомендую. Увлекательнейшее занятие по производству отборного говнокода.
И опять же - с точки зрения приложения, массив, который мы передаём в IN - это законченный блок данных. Почему мы строку можем передать через плейсхолдер, делая наш код ЧИСТЫМ, свободным от ручного форматирования, а массив - нет? зачем портить свой собственный код? Если надо добавить в запрос массив - значит, должен быть плейсхолдер, поддержэивающий такое добавление. Точка.
- массив для INSERT/UPDATE. Да-да. Это тоже вполне себе массив, ассоциативный. В ключах - имена полей, в значениях - сответственно - значения.
Передавать массивом на вставку значительно удобнее, чем собирать запрос вручную.
При этом инкапсулировать добавление этих массивов куда-нибудь подальше не получится - в АПИ нет такого понятия, как "содержимое оператора IN".
У ПДО с этим получше, сильно получше. вплоть до того, что ПДО со скрипом и оговорками можно назвать DALом. Всего-то строк 5 лишнего кода.
Вы скажете - а у нас есть прекрасная функция-хелпер.
Ну. давайте посмотрим
Слайд
----------------------------
Новенькая епонская лесопилка
$db->insert($table, $data);
$db->update($table,$data,$where);
$db->delete($where);
--------------------------
Слайд
-------------------------------
Едреная сибирская рельса:
Insert INGORE
INSERT .. ON DUPLICATE UPDATE
DELETE FROM .. JOIN
---------------------------------
И иного-много других страшных слов.
И вот наша прекрасная епонская лесопилка сделала “Хррр...”
что делаем мы? Вариантов немного - либо писать запрос руками, либо - писать к хелперу хелперы. Чувствуете? Попахивает? Это он, родимый. Говнокод!
Но - я хочу это подчеркнуть - всё равно запрос составляется по-старинке руками. Это никуда не годится. Это сразу отбрасывает нас назад, в каменный век ручного форматирования - со всеми его опасностями:
-- запрос формируется вручную. что может привести к тому, что либо данные окажутся испорчены, или не отформатированы.
-- стремясь защитить скалярные данные, при этом почти никто не думает об индентификаторах, которых тут вагон и маленькая тележка.
И родные подготовленные выражения нам совсем ни с одним из этих типов данных не помогут.
Давайте теперь обратимся к более широкому толкованию этого понятия.
И мы увидим, что подготовленные выражения как раз идеально подходят (при соблюдении некоторых условий) для тех правил, которые мы вывели во второй части:
1. при соответствующей обработке входящего значения форматирование будет всегда полным, причем вне зависимости от желания, состояния или способностей программиста.
2. при привязке значения можно указать тип.
3. форматирование будет проведено в обязательном порядке
4. и в приложении будет невозможно написать код, который будет стоять между помещением знчения в запрос и его обработкой - значение уже уехало в драйвер и больше мы его не увидим.
Плюс два второстепенных, но весьма приятных бонуса:
- prepared statement форматирует только значение, которое попадает в запрос, а не исходную переменную, которую потом можно использовать, неиспорченную, где-то ещё - вывести на экран, например.
- prepared statement может сделать наш код фантастически коротким, выполняя все операции по форматированию внутри.
Слайд
Что знает обычный человек про прерареды?
- что они "быстрее"
- что они безопасные [подразумевается - в отличие от искейпинга].
Вот это реальные преимущества ПЭ. То, что вам говорят в рекламе - по большей части туфта.
- скорость. Как выясняется, в нормальном веб-приложении повторяющиеся запросы - это, скорее признак профнепригодности программиста. Только в исключительно редких, маргинальных случаях, какого-нибудь консольного скрипта, делающего тыщи инсертов - может быть и будет какой-то прирост. А может и не будет - для инсерта план запроса примитивный, а парсинг текста на современны компьютерах происходит очень быстро.
- безопасность (подразумевается - в отличие от ). Нормально отформатированный запрос ничуть не опаснее запроса с ПЭ. Они взаимозаменяемы. БД, которая не может обеспечить безопасность стандартных запросов - это бессмыслица. Разумеется, она ее и обеспечивает. Поэтому можно использовать и тот и другой способ с одинаковой безопасностью.
Единственная проблема - как привязавать.
Ни один из предлагаемых стандартными API способов нам не подходит
Слайд
------------------
- PDO “lzay” binding: $db->execute(array($var1,$var2,$var3,$var4));
- mysqli: $db->bind_param(“issi”,$var1,$var2,$var3,$var4);
- PDO standard:
$sth->bindParam(1, $var1, PDO::PARAM_INT);
$sth->bindParam(2, $var2, PDO::PARAM_STR);
$sth->bindParam(3, $var3, PDO::PARAM_STR);
$sth->bindParam(4, $var4, PDO::PARAM_INT);
----------------------------------------
Смотрите:
- “Ленивая” привязка ПДО не подходит - она не учитывает тип, и валит все в строки. Нам это категорически не подходит, у нас типов гораздо больше.
- mysqli. уже поумнее, но если у нас массив с неизвестным числом параметров, то на горизонте маячит call user_func - и это уже становится похоже на фарс
- Стандартная привязка в столбик. СЛИШКОМ много кода
И тут нам на помощь приходит решение, которое древнее, чем … эпоха юникс!
Функция printf, которая появилась еще в языке ALGOL68, и в которой плейсхолдер САМ говорит обработчику, как его форматировать - поистине гениальная. она решает всепроблемы и убивает одним выстрелом целую стаю зайцев. Нужно всего лишь использовать тот же самый принцип
Берем обычный плейсхолдер, и приписываем к нему тип.
Парсер читает запрос, вырезает плейсхолдеры, смотрит тип, и соответсрвующим образом форматирует входящую переменную.
Слайд
-----------------------
Problems, officer?
- NOT IN(NULL)
- сложносочиненные запросы.
------------------------
А ведь в запрос можно передать просто массив, чтобы он был корректно подставлен на место плейсхолдера. Всё. Гору говнокода как корова языком слизала.
Получается, что подддержка расширенного набора плейсхолдеров - насушная необходимость.
Поэтой причине нам надо изобретать свой АПИ. Без вариантов.
Если бы не правило номер три - в принципе, можно было бы и писать горы говногода с ручным форматированием.
Но жазнь любого проекта складывается так, что постепенно код форматирования может отнести от кода исполнения запроса на значительное расстояние. Особенно стараниями программистов, которые хотят что-то улучшить.
И здесь можно пойти двумя путями.
Первый всем вам известен - это написать SQL на PHP, получив на выходе QueryBuilder. Задача почтенная, но трудновыполнимая.
Второй - сохранить SQL как есть, но дополнить его плейсхолдерами для действительно нужных в запросе типов данных.
Первый вам всем известен, поэтому посмотрим пока на второй (но потом все равно вернемся немного попинать первый ;)
Варианта реализации плейсхолдеров у нас опять же, два
Первый и сейчас активно применяется - это указывать тип передаваемых данных в операторе биндинга.
Но... Это снова превращает наш код в говнокод. Толпы привязок - это то,от чего мы хотели уйти! И вот здесь у нас получается Пятое правило, не менее важное, чем все остальные:
1. Каждый элемент запроса, помещаемыый в него динамически, должен быть корректно отформатирован.
2. Правила форматированя кардинально различаются для различных элементов запроса
3. Данные должны форматироваться настролько близко к исполнению запроса, насколько возможно.
4. По этой причине любые динамические данные должны попадать в запрос только через плейсхолдер.
5. Плесхолдер должен быть типизованным.
Эта очень простая мысль, которая прозвучала, скажем, у Котерова ещё черт знает когда - но так и не полчила распространения.
Я думаю это потому, что не была надлежащим образом сформулирована. Потому что типизованные плейсхолдеры нассматривались Котеровым как заплатки, частный случай. А не как принуипиальное ядро всей системы.
И вот здесь мы впервые подойдем к вопросу, который можно назвать защитой от SQL инъекций.
Но инъекция это не того рода, как обычно. ООт обычных мы закрыты цкликом и полностью.
При инъекции, которую я имею в виду, целостность запроса не нарушается.
Но у встроенных есть ещё и недостаток - очень ограниченная область применения.
not somewhere else, so, our safety won't rely on such unreliable sources like
- some PHP 'magic' feature which rather spoils the data than make it safe.
- good will of one (or several) programmers, who can decide to format (or not to format) our variable somewhere in the program flow. That's the point of great importance.
При этом. если статические литералы можно форматировать по потребности, то динамические - безусловно!
Вы скажете - ну зачем ещё раз форматировать, если валидатор и так все уже отвалидировал?
А вот потому. У семи нянек - дитя без глазу.
В одном проекте, с которым мне пришлось разбираться, была практически идеальная система валидации, не требовававшая никакого
ручного форматирования, для чисел. Все всегда знали, что если переменная пришла со стороны,
и она должна быть числовго типа - она и будет числового. Но тут пришлось дописать код, который бы запускался до всей валидации...
но привычка-то осталась!
БЕЛЫЕ СПИСКИ!!!!!!!
Давайте попробую объяснить.
SQL запрос - это программа. Нормальная программа, такая же как наш РНР скрипт.
Который состоит из элементов *множества* разных типов. А не тупо делится на "запрос" и "данные".
Фишка в том, что мы формируем эту программу динамически.
Страшно представить себе,
под конец котелось бы немного попинать конкурентов.
Каждый, наверное, писал функции нсерт делет, селект... а потом обо орастало и обрастало
Не. ну правда - если вам нужно только доставать по первичному ключу - не нужна вам РСУБД, используйте носк.
Но если используете скл - не загоняйте в прокрустово ложе
Тут от порядлка таблиц в джойне план запроса зависит, а вы хотите отдать его на откуп железяке.
Часть 4. “Разное”
Страшилки дядюшки Шифлетта.
слайд
--------------------------------------------------
- "blind",
-"time-delay",
-"second order"
- тысячи их
-----------------------------------------------------------
Вы наверняка слышали о всяких типах инъекций - - "blind", -"time-delay",-"second order"
Но при этом надо понимать, что способов сделать инъекцию - ровно ОДИН: нарушить целостность запроса.
А все вышеперечисленное - только следствия, способы эксплутировать тем или иным образом имеющуюся уязвимость.
Так вот - не надо заниматься глупостями, и защищаться от этих способов. Надо закрывать уязвимость в запросе. И тогда все эти многочисленные хитроумные способы превратятся в тыкву.
Слайд
-----------------------------------------
Способы защиты от инъекций
- Stored procedures (с целью защиты от инъекций)
- Заведение разных пользователей на чтение и запись
- Фильтрация разных «опасных» символов или их сочетаний
------------------------------------------
Вы уже, думаю. понимаете, что это полная ерунда
во-первых, не работает в реальной жизни
во-вторых,
Написать комментарий
Пожалуйста, воздержитесь от посылки спама.
Сообщения, содержащие гиперссылки, проходят премодерацию.