Я читал вчера вечером о предотвращении инъекций SQL, и я наткнулся на этот ответ:
Как я могу предотвратить SQL-инъекцию в PHP?
Комментарии от «Your Common Sense» заставили его звучать так, как будто это было неблагополучным / небезопасным. Тем не менее, в моем (хотя и ограниченном) тестировании я обнаружил, что «bin2hex ($ var)» php «работал с чем-либо, что я ему набросал – буквальным числом, числовой строкой, строкой текста – даже при сопоставлении числового (tinyint) столбца.
Мой вопрос заключается в следующем: есть ли способ внедрить SQL, когда каждый пользовательский ввод подвергается санированию с помощью его прошивки? По существу, всякий раз, когда запрос был сделан, он выглядел бы примерно так:
$query="SELECT * FROM table WHERE someidentifier=UNHEX('".bin2hex($unsafe_user_input)."') LIMIT 1"
В основном перевод:
SELECT * FROM table WHERE someidentifier=UNHEX('0b99f') LIMIT 1
Есть ли дыры в этом типе безопасности?
PS – Я не просто ищу ответы, например: «Почему бы просто не использовать PDO или MySQLi с подготовленными операторами?» Это может подпасть под огромное зло упреждающей оптимизации, но я бы предпочел не удвоить мои накладные расходы (и да, я понимаю, что это может быть быстрее с несколькими идентичными запросами, но это не та ситуация, с которой я часто сталкиваюсь).
Есть ли способ внедрить SQL, когда каждый пользовательский ввод подвергается дезинфекции, используя его?
Если вы знаете, почему происходит SQL-инъекция, вы сможете ответить на этот вопрос самостоятельно.
Посмотрим. CWE описывает инъекции SQL (CWE-89) следующим образом:
Программное обеспечение создает всю или часть команды SQL, используя входной сигнал с внешним воздействием […], но не нейтрализует или неправильно нейтрализует специальные элементы, которые могут изменить предполагаемую команду SQL […]
Более того:
Без достаточного удаления или цитирования синтаксиса SQL в управляемых пользователем входах сгенерированный SQL-запрос может заставить эти входы интерпретироваться как SQL вместо обычных пользовательских данных.
Таким образом, в основном: входные данные с внешним воздействием в сгенерированном SQL-запросе не интерпретируются как предназначенные. Важная часть здесь: не интерпретируется, как предполагалось .
Если пользовательский ввод предназначен для интерпретации как строковый литерал MySQL, но это не так, это SQL-инъекция. Но почему это происходит?
Ну, строковые литералы имеют определенный синтаксис, с помощью которого они идентифицируются синтаксическим анализатором SQL:
Строка представляет собой последовательность байтов или символов, заключенных в символы одиночной кавычки ("
'
") или двойные кавычки (""
").
Дополнительно:
Внутри строки определенные последовательности имеют особое значение […]. Каждая из этих последовательностей начинается с обратного слэша («
\
»), известного как escape-символ. MySQL распознает escape-последовательности, показанные в таблице 9.1, «Специальные последовательности escape-символов» .
Кроме того, чтобы иметь возможность использовать кавычки в строковых литералах:
Существует несколько способов включения символов кавычек в строку:
- A "
'
внутри строки, указанной в'
", может быть записано как''
."
" Внутри строки, указанной в ""
", может быть записано как"""
".- Представьте символ кавычки символом escape ("
\
").- «Внутри строки, указанной в«
"
« нет необходимости в специальном обращении, и ее не нужно удваивать или избегать. Точно так же «» внутри строки, указанной с помощью «», не нуждается в особой обработке.
Поскольку все эти последние упомянутые последовательности являются особыми для строковых литералов, необходимо, чтобы любые данные, предназначенные для интерпретации как строковый литерал, надлежащим образом обрабатывались для соответствия этим правилам. Это означает, в частности: если какой-либо из упомянутых символов предназначен для использования в строковом литерале, они должны быть написаны как один из указанных способов.
Поэтому, если вы посмотрите на это с этой точки зрения, это даже не вопрос безопасности, а просто обработка данных, чтобы они интерпретировались как предназначенные .
То же самое относится к другим литералам, а также к другим аспектам SQL.
Так как насчет вашего вопроса?
Мой вопрос заключается в следующем: есть ли способ внедрить SQL, когда каждый пользовательский ввод подвергается санированию с помощью его прошивки? По существу, всякий раз, когда запрос был сделан, он выглядел бы примерно так:
$query="SELECT * FROM table WHERE someidentifier=UNHEX('".bin2hex($unsafe_user_input)."') LIMIT 1"
Да, это было бы безопасно от SQL-инъекций. bin2hex
возвращает строку, содержащую только шестнадцатеричные символы. И ни один из этих символов не требует специальной обработки при использовании их в строковом литерале MySQL.
Но серьезно, почему кто-то хочет использовать эти громоздкие методы форматирования, когда там библиотеки и фреймворки, которые поставляют удобные методы, такие как параметризованные / подготовленные заявления?
Хотя я не знаком с hexing, я успешно использовал Base64 для предотвращения инъекций mysql в прошлом из разных сценариев.
Есть ли дыры в этом типе безопасности?
Нет никаких отверстий, но нет никаких преимуществ. Обычное форматирование строк одинаково безопасно, но без всего этого бесполезного разметки / нечего.
Таким образом, раздувание ваших запросов с помощью этого unhex-материала просто лишнее.
Что касается ответа на этот вопрос, изначально он был написан без разгерметизации и, таким образом, с цифрами, что сделало его непригодным. Хотя после добавления unhex он становится просто бесполезным и лишним.
$ query = "SELECT * FROM table WHERE someidentifier = UNHEX ('". bin2hex ($ unsafe_user_input). "
Это простой и определенный ответ для защиты от SQL-инъекций с использованием php и mysql.
Я видел комментарии, которые предполагают, что все еще возможно быть открытым для SQL-инъекции с подготовленным или параметризованным SQL. Я не вижу никаких оснований суетиться со всем этим, когда это решение прост и оно работает.
Я видел аргументы о времени использования памяти и памяти, но так как это обычно используется для ввода пользователем, введенного на экране, который заботится об использовании ОЗУ или циклах процессора (gasp!). Пользователь вводит 500 символов, шестнадцатеричная версия – тысяча символов. Если ваш сервер не имеет сотни тысяч человек, которые делают это в тот же момент, вы не увидите большой разницы.
Создание четкого, очевидного, поддерживаемого кода стоит нескольких циклов процессора и некоторой ОЗУ.
И техника настолько проста, ее легко запомнить. Кроме того, он не может разрывать или развивать дыры, поскольку PHP продолжает развиваться.