Используйте подготовленные операторы и параметризованные запросы. Это операторы SQL, которые отправляются и анализируются сервером базы данных отдельно от любых параметров. Таким образом, злоумышленник не сможет внедрить вредоносный SQL.
У вас есть два варианта для достижения этой цели:
Использование PDO (для любого поддерживаемого драйвера базы данных):
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
$stmt->execute([ 'name' => $name ]);
foreach ($stmt as $row) {
// Do something with $row
}
Использование MySQLi (для MySQL):
$stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');
$stmt->bind_param('s', $name); // 's' specifies the variable type => 'string'
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
// Do something with $row
}
Если вы подключаетесь к базе данных, отличной от MySQL, существует вторая опция для драйвера, к которой вы можете обратиться (например, pg_prepare()
и pg_execute()
для PostgreSQL). PDO - это универсальный вариант.
Правильная настройка соединения
Обратите внимание, что при использовании PDO
для доступа к базе данных MySQL реально подготовленные операторы не используются по умолчанию . Чтобы это исправить, вы должны отключить эмуляцию подготовленных операторов. Пример создания соединения с использованием PDO:
$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'password');
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
В приведенном выше примере режим ошибки не является строго необходимым, но рекомендуется добавить его . Таким образом, скрипт не остановится, Fatal Error
когда что-то пойдет не так. И это дает разработчику возможность catch
любых ошибок, которые throw
n как PDOException
s.
Однако обязательной является первая setAttribute()
строка, которая указывает PDO отключить эмулированные подготовленные операторы и использовать реально подготовленные операторы. Это гарантирует, что оператор и значения не будут проанализированы PHP перед отправкой его на сервер MySQL (не давая возможности злоумышленнику внедрить вредоносный SQL).
Хотя вы можете установить charset
в параметрах конструктора, важно отметить, что «старые» версии PHP (до 5.3.6) молча игнорировали параметр charset в DSN.
объяснение
Выражение SQL, которое вы передаете, prepare
анализируется и компилируется сервером базы данных. Задавая параметры ( ?
или именованный параметр, как :name
в примере выше), вы указываете ядру базы данных, где вы хотите фильтровать. Затем при вызове execute
подготовленный оператор объединяется с указанными вами значениями параметров.
Здесь важно то, что значения параметров объединяются с скомпилированным оператором, а не строкой SQL. SQL-инъекция работает, обманывая скрипт, добавляя в него вредоносные строки, когда он создает SQL для отправки в базу данных. Таким образом, отправляя фактический SQL отдельно от параметров, вы ограничиваете риск того, что вы не захотите.
Любые параметры, которые вы отправляете при использовании подготовленного оператора, будут просто обрабатываться как строки (хотя ядро базы данных может выполнить некоторую оптимизацию, поэтому, конечно, параметры могут также оказаться числами). В приведенном выше примере, если $name
переменная содержит 'Sarah'; DELETE FROM employees
результат, это будет просто поиск строки "'Sarah'; DELETE FROM employees"
, и вы не получите пустую таблицу .
Еще одним преимуществом использования подготовленных операторов является то, что если вы выполняете один и тот же оператор много раз в одном и том же сеансе, он будет проанализирован и скомпилирован только один раз, что даст вам некоторое увеличение скорости.
Да, и так как вы спросили о том, как сделать это для вставки, вот пример (с использованием PDO):
$preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');
$preparedStatement->execute([ 'column' => $unsafeValue ]);
Можно ли использовать подготовленные операторы для динамических запросов?
Хотя вы все еще можете использовать подготовленные операторы для параметров запроса, структура самого динамического запроса не может быть параметризована, а некоторые функции запроса не могут быть параметризованы.
Для этих конкретных сценариев лучше всего использовать фильтр белого списка, который ограничивает возможные значения.
// Value whitelist
// $dir can only be 'DESC', otherwise it will be 'ASC'
if (empty($dir) || $dir !== 'DESC') {
$dir = 'ASC';
}
Если вы используете последнюю версию PHP,
mysql_real_escape_string
описанная ниже опция больше не будет доступна (хотяmysqli::escape_string
это современный эквивалент). В наши дни этотmysql_real_escape_string
вариант имеет смысл только для устаревшего кода на старой версии PHP.У вас есть два варианта - экранирование специальных символов
unsafe_variable
или использование параметризованного запроса. Оба защитят вас от внедрения SQL. Параметризованный запрос считается лучшей практикой, но перед его использованием потребуется перейти на более новое расширение MySQL в PHP.Мы покроем нижнюю ударную струну, избегая первой.
Смотрите также, детали
mysql_real_escape_string
функции.Чтобы использовать параметризованный запрос, вам нужно использовать MySQLi, а не функции MySQL . Чтобы переписать ваш пример, нам нужно что-то вроде следующего.
Там будет ключевая функция, о которой вы захотите прочитать
mysqli::prepare
.Кроме того, как другие предложили, вам может быть полезно / проще увеличить уровень абстракции чем-то вроде PDO .
Обратите внимание, что дело, о котором вы спрашивали, является довольно простым, и что более сложные случаи могут потребовать более сложных подходов. В частности:
mysql_real_escape_string
. В этом случае вам лучше передать ввод пользователя через белый список, чтобы обеспечить пропуск только «безопасных» значений.mysql_real_escape_string
подход, вы будете страдать от проблемы, описанной Полиномом в комментариях ниже. Этот случай сложнее, потому что целые числа не будут заключены в кавычки, так что вы могли бы справиться, проверив, что пользовательский ввод содержит только цифры.источник
mysql_real_escape_string
достаточно или я должен использовать параметризованный тоже?htmlentities
напримерmysql_real_escape_string()
для полноты, но я не фанат перечисления наиболее подверженных ошибкам подхода в первую очередь. Читатель может просто быстро взять первый пример. Хорошо, что это устарело сейчас :)mysql_*
функции устарели. Они были заменены аналогичнымиmysqli_*
функциями, такими какmysqli_real_escape_string
.Каждый ответ здесь охватывает только часть проблемы. Фактически, есть четыре различных части запроса, которые мы можем динамически добавить в SQL:
И подготовленные заявления охватывают только два из них.
Но иногда мы должны сделать наш запрос еще более динамичным, добавив также операторы или идентификаторы. Итак, нам понадобятся разные методы защиты.
В общем, такой подход к защите основан на белых списках .
В этом случае каждый динамический параметр должен быть жестко задан в вашем скрипте и выбран из этого набора. Например, чтобы сделать динамическое упорядочение:
Чтобы упростить процесс, я написал вспомогательную функцию белого списка, которая выполняет всю работу в одной строке:
Есть еще один способ защиты идентификаторов - экранирование, но я предпочитаю использовать белые списки как более надежный и явный подход. Тем не менее, пока у вас есть идентификатор в кавычках, вы можете избежать символа кавычки, чтобы сделать его безопасным. Например, по умолчанию для mysql вы должны удвоить символ кавычки, чтобы избежать его . Для других других СУБД правила выхода будут другими.
Тем не менее, существует проблема с ключевыми словами синтаксиса SQL (такими как
AND
,DESC
и тому подобное), но белый список кажется единственным подходом в этом случае.Таким образом, общая рекомендация может быть сформулирована как
Обновить
Хотя существует общее согласие с лучшими практиками, касающимися защиты от SQL-инъекций, все еще существует много плохих практик. И некоторые из них слишком глубоко укоренились в сознании пользователей PHP. Например, на этой самой странице (хотя и невидимо для большинства посетителей) более 80 удаленных ответов - все они удалены сообществом из-за плохого качества или из-за пропаганды плохой и устаревшей практики. Хуже того, некоторые плохие ответы не удаляются, а процветают.
Например, (1) есть (2) еще (3) много (4) ответов (5) , включая второй ответ с наибольшим количеством голосов, предлагающий вам ручное экранирование строк - устаревший подход, который, как доказывают, небезопасен.
Или есть немного лучший ответ, который предлагает просто другой метод форматирования строки и даже может похвастаться этим как окончательной панацеей. Хотя, конечно, это не так. Этот метод ничем не лучше обычного форматирования строк, но при этом он сохраняет все свои недостатки: он применим только к строкам и, как и любое другое ручное форматирование, по сути является необязательной, необязательной мерой, подверженной человеческим ошибкам любого рода.
Я думаю, что все это из-за одного очень старого суеверия, поддерживаемого такими авторитетами, как OWASP или руководство по PHP , которое провозглашает равенство между любыми «выходами» и защитой от SQL-инъекций.
Независимо от того, что руководство PHP говорило целую вечность,
*_escape_string
ни в коем случае не делает данные безопасными и никогда не предназначалось для этого. Помимо бесполезности для любой части SQL, кроме строки, ручное экранирование является неправильным, поскольку оно является ручным, в отличие от автоматического.И OWASP делает это еще хуже, подчеркивая необходимость избежать пользовательского ввода что является полной ерундой: в контексте защиты от инъекций не должно быть таких слов. Каждая переменная потенциально опасна - независимо от источника! Или, другими словами - каждая переменная должна быть должным образом отформатирована для помещения в запрос - независимо от источника снова. Это пункт назначения, который имеет значение. В тот момент, когда разработчик начинает отделять овец от коз (думая, является ли какая-то конкретная переменная «безопасной» или нет), он / она делает свой первый шаг к катастрофе. Не говоря уже о том, что даже формулировка предполагает массовый выход в точке входа, напоминающий очень магическую функцию кавычек - уже презирали, осуждали и удаляли.
Таким образом, в отличие от любого «выхода», подготовленные операторы - это мера, которая действительно защищает от внедрения SQL (когда это применимо).
источник
Я бы рекомендовал использовать PDO (объекты данных PHP) для запуска параметризованных запросов SQL.
Это не только защищает от внедрения SQL, но и ускоряет запросы.
И с помощью PDO , а не
mysql_
,mysqli_
иpgsql_
функции, вы сделаете ваше приложение немного абстрагируется из базы данных, в редком возникновении что вы должны поставщикам база данных коммутаторов.источник
Используйте
PDO
и подготовленные запросы.(
$conn
этоPDO
объект)источник
Как видите, люди советуют вам использовать максимально подготовленные высказывания. Это не так, но когда ваш запрос выполняется только один раз за процесс, это может привести к небольшому снижению производительности.
Я столкнулся с этой проблемой, но думаю, что решил ее очень изощренным способом - способом, который используют хакеры, чтобы избежать использования кавычек. Я использовал это в сочетании с подготовленными утверждениями. Я использую его , чтобы предотвратить все виды возможных атак с внедрением SQL.
Мой подход:
Если вы ожидаете, что ввод будет целочисленным, убедитесь, что он действительно целочисленный. В языке переменных типов, таких как PHP, это очень важно. Например, вы можете использовать это очень простое, но мощное решение:
sprintf("SELECT 1,2,3 FROM table WHERE 4 = %u", $input);
Если вы ожидаете что-то еще от целого числа, заклейте его . Если вы это сделаете, вы полностью избежите ввода. В C / C ++ есть функция
mysql_hex_string()
, которую вы можете использоватьbin2hex()
.Не беспокойтесь о том, что экранированная строка будет иметь 2-кратный размер по сравнению с первоначальной длиной, потому что даже если вы используете
mysql_real_escape_string
, PHP должен выделять((2*input_length)+1)
такую же емкость , которая одинакова.Этот шестнадцатеричный метод часто используется при передаче двоичных данных, но я не вижу причин, почему бы не использовать его для всех данных, чтобы предотвратить атаки с использованием SQL-инъекций. Обратите внимание, что вы должны предварительно добавить данные
0x
или использовать функцию MySQLUNHEX
.Так, например, запрос:
Станет:
или
Гекс это идеальный побег. Нет способа ввести.
Разница между функцией UNHEX и префиксом 0x
В комментариях была некоторая дискуссия, поэтому я, наконец, хочу прояснить это. Эти два подхода очень похожи, но они немного отличаются в некоторых отношениях:
Префикс ** 0x ** можно использовать только для столбцов данных, таких как char, varchar, text, block, binary и т . Д.
Кроме того, его использование немного сложнее, если вы собираетесь вставить пустую строку. Вам придется полностью заменить его
''
, иначе вы получите ошибку.UNHEX () работает на любом столбце; вам не нужно беспокоиться о пустой строке.
Шестнадцатеричные методы часто используются как атаки
Обратите внимание, что этот шестнадцатеричный метод часто используется как атака SQL-инъекции, где целые числа похожи на строки и экранированы только с помощью
mysql_real_escape_string
. Тогда вы можете избежать использования цитат.Например, если вы просто делаете что-то вроде этого:
атака может сделать вам инъекцию очень легко . Рассмотрим следующий внедренный код, возвращаемый из вашего скрипта:
а теперь просто извлеките структуру таблицы:
А затем просто выберите все данные, которые хотите. Разве это не круто?
Но если кодировщик сайта для инъекций закодирует его, никакая инъекция не будет возможна, потому что запрос будет выглядеть так:
SELECT ... WHERE id = UNHEX('2d312075...3635')
источник
+
но сCONCAT
. И на производительность: я не думаю, что это влияет на производительность, потому что mysql должен анализировать данные, и не имеет значения, является ли источник строковым или шестнадцатеричным'root'
или вы можете использовать шестнадцатеричный код0x726f6f74
НО, если вам нужно число и отправить его как строку, вы, вероятно, напишите '42', а не CHAR (42 ) ... '42' в0x3432
0x42
SELECT title FROM article WHERE id = UNHEX(' . bin2hex($_GET["id"]) . ')
Предотвращение инъекций - mysql_real_escape_string ()
PHP имеет специально созданную функцию для предотвращения этих атак. Все, что вам нужно сделать, это использовать полный набор функций
mysql_real_escape_string
.mysql_real_escape_string
принимает строку, которая будет использоваться в запросе MySQL, и возвращает ту же строку со всеми попытками внедрения SQL, безопасно избежавшими По сути, он заменит те неприятные кавычки ('), которые пользователь может ввести, заменой, безопасной для MySQL, - экранированной кавычкой \'.ПРИМЕЧАНИЕ: вы должны быть подключены к базе данных, чтобы использовать эту функцию!
// Подключаемся к MySQL
Вы можете найти более подробную информацию в MySQL - SQL Injection Prevention .
источник
mysql_real_escape_string
цель состоит в том, чтобы позволить построить правильный запрос SQL для каждой входной строки данных. Профилактика sql-инъекций является побочным эффектом этой функции.mysql_real_escape_string()
не является непогрешимым .mysql_real_escape_string
теперь считается устаревшим, поэтому его больше нельзя использовать. В будущем он будет удален из PHP. Лучше всего перейти на то, что рекомендуют PHP или MySQL.Вы можете сделать что-то простое, как это:
Это не решит всех проблем, но это очень хорошая ступенька. Я упустил очевидные элементы, такие как проверка существования переменной, формат (цифры, буквы и т. Д.).
источник
$q = "SELECT col FROM tbl WHERE x = $safe_var";
к примеру. Установка$safe_var
для1 UNION SELECT password FROM users
работы в этом случае из-за отсутствия котировок. Также возможно ввести строки в запрос, используяCONCAT
иCHR
.mysql_real_escape_string()
не является непогрешимым .mysql_real_escape_string
теперь считается устаревшим, поэтому его больше нельзя использовать. В будущем он будет удален из PHP. Лучше всего перейти на то, что рекомендуют PHP или MySQL.Что бы вы ни делали в конечном итоге, убедитесь, что вы проверяете, что ваши данные еще не были искажены
magic_quotes
или каким-либо другим благонамеренным мусором, и, если необходимо, пропустите егоstripslashes
или что-то еще, чтобы очистить его.источник
Параметризованный запрос И проверка ввода - это путь. Существует много сценариев, при которых может происходить внедрение SQL, даже если
mysql_real_escape_string()
оно использовалось.Эти примеры уязвимы для внедрения SQL:
или
В обоих случаях вы не можете использовать
'
для защиты инкапсуляции.Источник : Неожиданный SQL-инъекция (когда побега недостаточно)
источник
На мой взгляд, лучший способ вообще предотвратить внедрение SQL в ваше PHP-приложение (или, если на то пошло, любое веб-приложение) - это подумать об архитектуре вашего приложения. Если единственный способ защитить себя от внедрения SQL-кода - это не забывать использовать специальный метод или функцию, которая выполняет правильные действия каждый раз, когда вы обращаетесь к базе данных, вы делаете это неправильно. Таким образом, это просто вопрос времени, пока вы не забудете правильно отформатировать свой запрос в какой-то момент кода.
Принятие шаблона MVC и инфраструктуры, такой как CakePHP или CodeIgniter , вероятно, является правильным решением: общие задачи, такие как создание безопасных запросов к базе данных, были решены и централизованно реализованы в таких платформах. Они помогают разумно организовать ваше веб-приложение и заставляют задуматься о загрузке и сохранении объектов, а не о безопасном построении отдельных запросов SQL.
источник
Я предпочитаю хранимые процедуры ( MySQL имеет поддержку хранимых процедур с 5.0 ) с точки зрения безопасности - преимущества -
Недостатки -
источник
Существует много способов предотвращения SQL-инъекций и других SQL-хаков. Вы можете легко найти его в Интернете (поиск Google). Конечно, PDO - одно из хороших решений. Но я хотел бы предложить вам хорошую защиту ссылок от SQL-инъекций.
Что такое SQL-инъекция и как ее предотвратить?
Руководство по PHP для внедрения SQL
Microsoft объяснение SQL инъекций и предотвращения в PHP
И некоторые другие, такие как предотвращение SQL-инъекций с MySQL и PHP .
Теперь, почему вам нужно предотвратить ваш запрос от внедрения SQL?
Я хотел бы сообщить вам: почему мы пытаемся предотвратить внедрение SQL с помощью короткого примера ниже:
Запрос на совпадение аутентификации при входе:
Теперь, если кто-то (хакер) ставит
и пароль ничего ....
Запрос будет обработан в системе только до:
Другая часть будет отброшена. Итак, что будет? Неавторизованный пользователь (хакер) сможет войти в систему как администратор, не имея своего пароля. Теперь он / она может делать все, что может делать администратор / сотрудник электронной почты. Видите, это очень опасно, если внедрение SQL не предотвращается.
источник
Я думаю, если кто-то хочет использовать PHP и MySQL или какой-либо другой сервер базы данных:
(int)$foo
. Подробнее о типе переменных в PHP читайте здесь . Если вы используете библиотеки, такие как PDO или MySQLi, всегда используйте PDO :: quote () и mysqli_real_escape_string () .Примеры библиотек:
---- PDO
--- MySQLi
PS :
ЗОП выигрывает эту битву с легкостью. Благодаря поддержке двенадцати различных драйверов баз данных и именованных параметров мы можем игнорировать небольшую потерю производительности и привыкнуть к ее API. С точки зрения безопасности, они оба безопасны, если разработчик использует их так, как они должны использоваться.
Но хотя PDO и MySQLi работают довольно быстро, MySQLi работает незначительно быстрее в тестах - ~ 2,5% для неподготовленных операторов и ~ 6,5% для подготовленных.
И, пожалуйста, проверяйте каждый запрос к вашей базе данных - это лучший способ предотвратить инъекцию.
источник
Если возможно, приведите типы ваших параметров. Но он работает только с простыми типами, такими как int, bool и float.
источник
Если вы хотите воспользоваться механизмами кэширования, такими как Redis или Memcached , возможно, DALMP может быть выбором. Он использует чистый MySQLi . Проверьте это: Уровень абстракции базы данных DALMP для MySQL с использованием PHP.
Кроме того, вы можете «подготовить» свои аргументы перед подготовкой запроса, чтобы вы могли строить динамические запросы и в конце получить полностью подготовленный запрос операторов. Уровень абстракции базы данных DALMP для MySQL с использованием PHP.
источник
Для тех, кто не знает, как использовать PDO (исходя из
mysql_
функций), я сделал очень, очень простую оболочку PDO, которая представляет собой один файл. Он существует, чтобы показать, как легко выполнять все обычные задачи, которые необходимо выполнять приложениям. Работает с PostgreSQL, MySQL и SQLite.В принципе, читать его в то время как вы читаете руководство , чтобы увидеть , как поставить функции PDO для использования в реальной жизни , чтобы сделать его простым для хранения и извлечения значений в формате вы хотите.
источник
Используя эту функцию PHP,
mysql_escape_string()
вы можете быстро получить хорошее предупреждение.Например:
mysql_escape_string
- экранирует строку для использования в mysql_queryДля большей профилактики, вы можете добавить в конце ...
Наконец вы получите:
источник
Несколько рекомендаций по экранированию специальных символов в операторах SQL.
Не используйте MySQL . Это расширение устарело. Вместо этого используйте MySQLi или PDO .
MySQLi
Для ручного экранирования специальных символов в строке вы можете использовать функцию mysqli_real_escape_string . Функция не будет работать должным образом, если правильный набор символов не установлен с помощью mysqli_set_charset .
Пример:
Для автоматического экранирования значений с подготовленными выражениями используйте mysqli_prepare и mysqli_stmt_bind_param, где для соответствующего преобразования должны быть предоставлены типы для соответствующих переменных связывания:
Пример:
Независимо от того, используете ли вы подготовленные заявления или
mysqli_real_escape_string
, вам всегда нужно знать тип входных данных, с которыми вы работаете.Поэтому, если вы используете подготовленный оператор, вы должны указать типы переменных для
mysqli_stmt_bind_param
функции.И использование
mysqli_real_escape_string
для, как следует из названия, экранирования специальных символов в строке, поэтому оно не сделает целые числа безопасными. Цель этой функции - предотвратить разрыв строк в операторах SQL и повреждение базы данных, которое она может вызвать.mysqli_real_escape_string
полезная функция при правильном использовании, особенно в сочетании сsprintf
.Пример:
источник
Простую альтернативу этой проблеме можно решить, предоставив соответствующие разрешения в самой базе данных. Например: если вы используете базу данных MySQL, войдите в базу данных через терминал или предоставленный пользовательский интерфейс и просто выполните следующую команду:
Это ограничит пользователя только ограниченным указанным запросом. Удалите разрешение на удаление, чтобы данные никогда не удалялись из запроса, запущенного со страницы PHP. Второе, что нужно сделать, это сбросить привилегии, чтобы MySQL обновил разрешения и обновления.
больше информации о флеше .
Чтобы увидеть текущие привилегии для пользователя, запустите следующий запрос.
Узнайте больше о GRANT .
источник
Что касается многих полезных ответов, я надеюсь добавить некоторую ценность этой теме.
SQL-инъекция - это атака, которая может быть осуществлена через пользовательские вводы (вводы, которые заполняются пользователем, а затем используются внутри запросов). Шаблоны SQL-инъекций - это правильный синтаксис запросов, хотя мы можем его назвать: плохие запросы по плохим причинам, и мы предполагаем, что может быть плохой человек, который пытается получить секретную информацию (в обход контроля доступа), которая затрагивает три принципа безопасности (конфиденциальность) , целостность и доступность).
Теперь наша цель - предотвратить угрозы безопасности, такие как атаки с использованием SQL-инъекций, задать вопрос (как предотвратить атаку с использованием SQL-кода с использованием PHP), быть более реалистичным, фильтрация или очистка входных данных - это тот случай, когда пользовательские данные вводятся внутрь. такой запрос, использующий PHP или любой другой язык программирования, не соответствует действительности, или как многие люди рекомендуют использовать современные технологии, такие как подготовленные операторы или любые другие инструменты, которые в настоящее время поддерживают предотвращение SQL-инъекций, считаете, что эти инструменты больше не доступны? Как вы защищаете свое приложение?
Мой подход против внедрения SQL-кода: очистка данных, вводимых пользователем, перед отправкой в базу данных (перед использованием в любом запросе).
Фильтрация данных для (преобразования небезопасных данных в безопасные данные)
Учтите, что PDO и MySQLi недоступны. Как вы можете защитить свое приложение? Вы заставляете меня использовать их? А как насчет других языков, кроме PHP? Я предпочитаю давать общие идеи, так как они могут быть использованы для более широкой границы, а не только для конкретного языка.
ПРАВИЛО: не создавайте одного пользователя базы данных для всех привилегий. Для всех операций SQL вы можете создать свою схему, такую как (deluser, selectuser, updateuser) в качестве имен пользователей для простоты использования.
Смотрите принцип наименьших привилегий .
Фильтрация данных: перед созданием любого пользовательского ввода запроса его следует проверить и отфильтровать. Для программистов важно определить некоторые свойства для каждой пользовательской переменной: тип данных, шаблон данных и длина данных . Поле, которое является числом между (x и y), должно быть точно проверено с использованием точного правила, а для поля, которое является строкой (текст): шаблон имеет место, например, имя пользователя должно содержать только несколько символов, давайте скажем [a-zA-Z0-9_-.]. Длина варьируется между (x и n), где x и n (целые числа, x <= n). Правило: создание точных фильтров и правил проверки - лучшие практики для меня.
Используйте другие инструменты: Здесь я также согласен с вами в том, что подготовлены оператор (параметризованный запрос) и хранимые процедуры. Недостатки здесь в том, что эти способы требуют продвинутых навыков, которых нет у большинства пользователей. Основная идея здесь состоит в том, чтобы различать SQL-запрос и данные, которые используются внутри. Оба подхода могут использоваться даже с небезопасными данными, потому что вводимые пользователем данные здесь ничего не добавляют к исходному запросу, например (any или x = x).
Для получения дополнительной информации, пожалуйста, прочитайте OWASP Шпаргалку по предотвращению инъекций .
Теперь, если вы опытный пользователь, начните использовать эту защиту по своему усмотрению, но для новичков, если они не могут быстро реализовать хранимую процедуру и подготовить оператор, лучше отфильтровать входные данные, насколько это возможно.
Наконец, давайте рассмотрим, что пользователь отправляет этот текст ниже вместо ввода своего имени пользователя:
Этот вход можно проверить заранее без каких-либо подготовленных операторов и хранимых процедур, но для большей безопасности их использование начинается после фильтрации и проверки пользовательских данных.
Последний пункт - обнаружение неожиданного поведения, которое требует больших усилий и сложности; это не рекомендуется для обычных веб-приложений.
Неожиданным поведением в вышеприведенном вводе пользователя является SELECT, UNION, IF, SUBSTRING, BENCHMARK, SHA и root. Как только эти слова обнаружены, вы можете избежать ввода.
ОБНОВЛЕНИЕ 1:
Пользователь прокомментировал, что этот пост бесполезен, хорошо! Вот что предоставил OWASP.ORG :
Как вы, возможно, знаете, утверждение статьи должно быть подтверждено действительным аргументом, хотя бы одной ссылкой! В противном случае это считается атакой и плохим требованием!
Обновление 2:
Из руководства по PHP, PHP: Подготовленные заявления - Руководство :
Обновление 3:
Я создал контрольные примеры, чтобы узнать, как PDO и MySQLi отправляют запрос на сервер MySQL при использовании подготовленного оператора:
PDO:
Журнал запросов:
MySQLi:
Журнал запросов:
Понятно, что готовое заявление также ускользает от данных, ничего больше.
Как также упоминалось в приведенном выше заявлении,
Следовательно, это доказывает, что проверка данных, например,
intval()
является хорошей идеей для целочисленных значений перед отправкой любого запроса. Кроме того, предотвращение злонамеренных пользовательских данных перед отправкой запроса является правильным и корректным подходом .Пожалуйста, посмотрите этот вопрос для более подробной информации: PDO отправляет необработанный запрос в MySQL, в то время как Mysqli отправляет подготовленный запрос, оба дают одинаковый результат.
Ссылки:
источник
Я использую три различных способа предотвращения уязвимости моего веб-приложения для внедрения SQL-кода.
mysql_real_escape_string()
, которое является предварительно определенной функцией в PHP , и этот код оного обратный слеш следующих символы:\x00
,\n
,\r
,\
,'
,"
и\x1a
. Передайте входные значения в качестве параметров, чтобы минимизировать вероятность внедрения SQL.Я надеюсь, что это поможет вам.
Рассмотрим следующий запрос:
$iId = mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";
mysql_real_escape_string () не будет защищать здесь. Если вы используете одинарные кавычки ('') вокруг переменных внутри запроса, это то, что защищает вас от этого. Вот решение ниже для этого:
$iId = (int) mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";
Этот вопрос имеет несколько хороших ответов по этому поводу.
Я предлагаю использовать PDO - лучший вариант.
Редактировать:
mysql_real_escape_string()
устарел начиная с PHP 5.5.0. Используйте либо MySQL, либо PDO.Альтернативой mysql_real_escape_string () является
Пример:
источник
Простым способом было бы использовать PHP-фреймворк, такой как CodeIgniter или Laravel, который имеет встроенные функции, такие как фильтрация и активная запись, так что вам не придется беспокоиться об этих нюансах.
источник
Предупреждение: подход, описанный в этом ответе, применим только к очень конкретным сценариям и небезопасен, поскольку атаки с использованием SQL-инъекций зависят не только от возможности внедрения
X=Y
.Если злоумышленники пытаются взломать форму с помощью
$_GET
переменной PHP или строки запроса URL-адреса, вы сможете их перехватить, если они не защищены.Потому что
1=1
,2=2
,1=2
,2=1
,1+1=2
и т.д. ... являются общими вопросами к базе данных SQL злоумышленника. Возможно также он используется многими хакерскими приложениями.Но вы должны быть осторожны, чтобы не переписывать безопасный запрос со своего сайта. Приведенный выше код дает вам подсказку переписать или перенаправить (зависит от вас) эту строку динамического запроса, специфичную для взлома, на страницу, на которой будет храниться IP-адрес злоумышленника , или ДАЖЕ ИХ КУКИ, историю, браузер или любой другой конфиденциальный информация, так что вы можете иметь дело с ними позже, заблокировав их учетную запись или связавшись с властями.
источник
1-1=0
? :)([0-9\-]+)=([0-9]+)
.Есть много ответов на PHP и MySQL , но вот код для PHP и Oracle для предотвращения внедрения SQL, а также регулярное использование драйверов oci8:
источник
Хорошая идея - использовать объектно-реляционный маппер, такой как Idiorm :
Это спасает не только от SQL-инъекций, но и от синтаксических ошибок! Он также поддерживает коллекции моделей с цепочкой методов для фильтрации или применения действий к нескольким результатам одновременно и нескольким соединениям.
источник
Использование PDO и MYSQLi - хорошая практика для предотвращения SQL-инъекций, но если вы действительно хотите работать с функциями и запросами MySQL, было бы лучше использовать
mysql_real_escape_string
Есть больше возможностей предотвратить это: например, определить - если входные данные представляют собой строку, число, символ или массив, существует так много встроенных функций, чтобы обнаружить это. Также было бы лучше использовать эти функции для проверки входных данных.
is_string
is_numeric
И гораздо лучше использовать эти функции для проверки входных данных
mysql_real_escape_string
.источник
mysql_real_escape_string()
не является непогрешимым .mysql_real_escape_string
теперь считается устаревшим, поэтому его больше нельзя использовать. Он будет удален из PHP в будущем. Лучше всего перейти на то, что рекомендуют PHP или MySQL.Я написал эту маленькую функцию несколько лет назад:
Это позволяет запускать операторы в однострочном C # -ish String.Format, например:
Он избегает, учитывая тип переменной. Если вы попытаетесь параметризировать имена таблиц и столбцов, произойдет сбой, поскольку каждая строка будет заключена в кавычки, что является недопустимым синтаксисом.
ОБНОВЛЕНИЕ БЕЗОПАСНОСТИ: Предыдущая
str_replace
версия допускала инъекции, добавляя токены {#} в пользовательские данные. Этаpreg_replace_callback
версия не вызывает проблем, если замена содержит эти токены.источник