Статьи

Укрепление PHP: magic_quotes_gpc — Ложное чувство безопасности


Написание безопасных приложений с нуля требует от программиста полного понимания всех функций, которые он использует для защиты своего кода от уязвимостей.
Современные языки предоставляют множество способов облегчить кодировщикам усиление кода. Вы можете полагаться на встроенные библиотеки для фильтрации входных переменных, экранирования выходных данных в HTML и т. Д.

Однако оставаться в безопасности не так просто — вам нужно знать все ограничения и предостережения ваших инструментов, потому что иногда они обещают вам что-то, но не делают не доставлять — как в случае с волшебными цитатами.

Магические цитаты

PHP
magic_quotes_gpc иногда рекомендуется в качестве защиты от
внедрения SQL. Когда этот параметр ini включен, все переменные GET / POST / COOKIE автоматически запускаются через
функцию
addlashes () , в основном экранируя все символы кавычек с помощью »
\ «.

Все хорошо

Давайте посмотрим на пример, где эта защита будет работать:

<?php
// some admin login functionality
$logged_in = mysql_query("SELECT 1 FROM users WHERE login='admin' AND password=sha1('" . $_POST['password'] . "')");
// process $logged_in

Когда
magic_quotes_gpc включены, внедрение переменной PASSWORD не будет работать. Простейший вектор атаки «
ИЛИ 1 = 1 — » трансформируется в


ВЫБЕРИТЕ 1 ИЗ ПОЛЬЗОВАТЕЛЕЙ, ГДЕ логин = ‘admin’ И пароль = sha1 (‘\’ ИЛИ ​​1 = 1 — ‘)

Это совершенно экранированный SQL-запрос, который не может быть введен.
magic_quotes_gpc избежать опасной одиночной кавычки для нас. Итак — прощай SQL инъекция?
НЕПРАВИЛЬНО!

Магические кавычки только вставляют обратную косую черту перед несколькими символами, не более того. Это защищает вас от внедрения SQL-кода
только в некоторых конкретных случаях, таких как описанные выше, и только по совпадению. Чтобы доказать это, давайте проанализируем следующий скрипт.

Так много для магии …

<?php
// display a single post based on id
$post_data = mysql_query("SELECT title, content FROM posts WHERE post_id={$_GET['id']}");
// display $post

То же «
ИЛИ 1 = 1 — » преобразуется в неверный запрос:


ВЫБЕРИТЕ заголовок, содержание ОТ сообщений, ГДЕ post_id = \ ‘ИЛИ 1 = 1 —

и если у вас включено display_errors, вы просто порадовали злоумышленника тем, что данные вашей базы данных были выведены прямо на его глазах. Даже если вы этого не сделаете, все еще существует возможность
слепой инъекции SQL .

Но что, если злоумышленник установит параметр id в один из них:

  • 1 И (ВЫБЕРИТЕ СЧЕТЧИК (*) из другого имени таблицы) МЕЖДУ 0 И 100
  • -10000 union выбирает user_password из пользователей, где user_login = CHAR (97,100,109,105,110) (администратор)

Вы не получите никакой защиты от этих векторов — они проскальзывают прямо под глазами 
magic_quotes_gpc — они не содержат кавычек.

В этом случае единственный параметр запроса mysql, который остался незащищенным, может привести к тому, что весь контент вашей базы данных будет сброшен злоумышленнику (я не шучу — посмотрите
sqlmap и попробуйте сами).

Знай свой контекст

Основная проблема с
magic_quotes_gpc заключается в том, что они ничего не знают о
контексте . Они не знают, используете ли вы данные, чтобы вставить их в MySQL, Oracle или пишете в файл. Может быть, вы отправляете его через SOAP или отображаете в HTML? Или, может быть, все это. Им просто не хватает информации, только вы это знаете. Экранирование значений зависит от контекста, в котором они используются.
Вы должны отключить магические кавычки сейчас также по следующим причинам:

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

Но, тем не менее, вам необходимо скрыть свои данные. Следуйте этим простым правилам:

  • для вывода в HTML — используйте htmlspecialchars ()
  • чтобы избежать строки в MySQL — используйте mysql_real_escape_string ()
  • для экранирования строки в Postgresql — используйте pg_escape_string () 
  • Когда вы ожидаете целое число в запросе SQL — просто приведите к int
  • ВСЕГДА используйте готовые операторы при запросах к базам данных.

Если вы хотите узнать больше об обходе магических кавычек и SQL-инъекций в целом, я рекомендую:

Есть какие-либо комментарии по теме, чтобы поделиться? Пожалуйста, сделайте это, это мой первый пост, связанный с безопасностью, и я хотел бы услышать ваше мнение.