Спасибо Крису Лиенерту и Гвидо Тоннаеру за любезную помощь в рецензировании этой статьи.
Из всех атак, которые могут быть организованы на веб-сайты, SQL-инъекция является одним из самых опасных и распространенных и использовалась для нанесения реального ущерба предприятиям и организациям в прошлом году. Схема была использована для нацеливания на известные организации и фирмы, включая TalkTalk , VTech , Wall Street Journal и правительство США .
Короче говоря, SQL-инъекция, также называемая SQLi, использует уязвимости во входных каналах веб-сайта для нацеливания на базу данных, которая находится в бэкэнде веб-приложения, где хранится наиболее важная и ценная информация. Схема может использоваться злоумышленниками для кражи данных или подделки данных, ограничения функциональности приложений и, в худшем случае, получения административного доступа к серверу базы данных.
Вот что вам нужно знать о внедрении SQL-кода и о том, как защитить ваш сайт от него.
Как работают SQL-инъекции
Атаки SQL-инъекций проводятся путем отправки вредоносных команд SQL на серверы баз данных через веб-запросы. Любой входной канал может использоваться для отправки вредоносных команд, включая элементы <input>
, строки запросов, файлы cookie и файлы.
Чтобы увидеть, как это работает, предположим, что у вас есть форма входа в систему, которая принимает имя пользователя и пароль:
Когда пользователи вводят свои учетные данные и нажимают кнопку «войти», информация отправляется обратно на ваш веб-сервер, где она объединяется с командой SQL. Например, в PHP код будет выглядеть примерно так:
$sql_command = "select * from users where username = '" . $_POST['username']; $sql_command .= "' AND password = '" . $_POST['password'] . "'";
Затем команда будет отправлена на сервер базы данных, и результирующий набор данных будет определять, соответствуют ли имя пользователя и пароль действительной учетной записи пользователя. Обычный пользователь, вводящий «john» в качестве имени пользователя и «123456» в качестве пароля (кстати, никогда не используйте этот пароль ), будет преобразовываться в следующую команду:
SELECT * FROM users WHERE username='john' AND password='123456'
Но что, если пользователь решит попробовать что-то еще, например, следующее:
В результате получится следующая команда, которая всегда будет возвращать непустой набор данных:
SELECT * FROM users WHERE username='john' OR 1=1; -- ' AND password='123456'
Фрагмент, возможно, позволит пользователю обойти экран входа в систему без надлежащих учетных данных.
Это одна из самых простых форм внедрения SQL. Приложив немного больше усилий, один и тот же пользователь может вставлять новые учетные записи пользователей, а также удалять или изменять существующие учетные записи пользователей. На страницах, где отображаются результаты, та же схема может использоваться для отображения записей и информации, которые в противном случае были бы ограничены для обычных посетителей, или для изменения содержимого записей.
В более серьезных случаях, когда подключение к серверу базы данных осуществляется через административную учетную запись (например, «root» в MySQL или «sa» в MS SQL Server), злоумышленник может зайти до полной компрометации операционной системы сервера. На серверах Windows это может проявиться в том, что злоумышленник выполняет расширенные хранимые процедуры, такие как xp_cmdshell
. В одном случае злоумышленники использовали уязвимость SQL-инъекций для создания учетных записей пользователей на скомпрометированном сервере, включения функции удаленного рабочего стола, настройки общих папок SMB и загрузки вредоносных программ, за исключением того, что они практически испортили все, что хранилось в базе данных.
Как защитить себя от атак SQL-инъекций
Поскольку каналы пользовательского ввода являются основным вектором атак SQL-инъекций, большинство защитных методов включают контроль и проверку пользовательского ввода для шаблонов атак.
Вот несколько мер, которые могут обеспечить безопасность ввода пользователя.
Никогда не доверяйте пользовательскому вводу
Первое правило о пользовательском вводе — « не доверяй и не проверяй », что фактически означает, что все формы пользовательского ввода должны считаться вредоносными, если не доказано иное. Это учитывает не только простые поля ввода, такие как текстовые области и текстовые поля, но и все остальное, например, скрытые входные данные, параметры строки запроса, файлы cookie и загрузки файлов.
Тот факт, что пользовательский интерфейс браузера не позволяет пользователю манипулировать вводом, не означает, что он не может быть подделан. Простые инструменты, такие как Burp Suite, позволяют пользователям захватывать HTTP-запросы и изменять что-либо, в том числе скрытые значения форм, перед отправкой их на сервер. И если вы считаете себя умным с помощью Base64, кодирующей ваши данные, они могут быть легко декодированы, изменены и перекодированы злоумышленниками.
Проверьте входные строки на стороне сервера
Проверка — это процесс проверки того, что пользователи вводят правильный тип ввода, и нейтрализации любых потенциальных вредоносных команд, которые могут быть встроены во входную строку. Например, в PHP вы можете использовать mysql\_real\_escape\_string()
для экранирования символов, которые могут изменить характер команды SQL.
Измененная версия ранее упомянутого кода входа будет выглядеть следующим образом:
$con=mysqli_connect("localhost","user","password","db"); $username = mysqli_real_escape_string($con, $_POST['username']); $password = mysqli_real_escape_string($con, $_POST['password']); $sql_command = "select * from users where username = '" . $username; $sql_command .= "' AND password = '" . $password . "'";
Эта простая модификация защитит ваш код от атаки, которая была представлена, путем добавления escape-символа (\) перед одинарными кавычками, которые были намеренно добавлены злонамеренным пользователем.
Замечание о валидации: если вы добавили функции валидации на стороне клиента, хорошо сделано. Но не полагайтесь на это как на защитную меру от атак SQL-инъекций Хотя функции на стороне клиента могут усложнить отправку злонамеренного ввода на сервер, его можно легко обойти с помощью нескольких настроек браузера и таких инструментов, как только что упомянутый. Поэтому вам необходимо дополнить его проверкой на стороне сервера.
Некоторые программные платформы, такие как ASP.NET, включают встроенные функции, которые автоматически оценивают пользовательский ввод для вредоносного контента при обратной передаче страницы. Но они могут быть обойдены хакерами с достаточным количеством нервов и изощренности, поэтому вы, тем не менее, должны выполнять ввод данных пользователем через собственные процедуры проверки безопасности. Вы никогда не можете быть слишком осторожными.
Используйте параметры команды
Лучшей альтернативой экранированию было бы использование параметров команды. Параметры команды определяются путем добавления имен заполнителей в команды SQL, которые впоследствии будут заменены пользовательским вводом. ASP.NET имеет очень интуитивно понятный и простой в использовании набор API для этой цели.
Следующий код, написанный на C #, показывает, как вы можете использовать параметры команды для защиты вашего сайта от внедрения SQL:
SqlCommand cmd = new SqlCommand ("SELECT * FROM users WHERE username=@username AND password=@password",con); SqlParameter username = new SqlParameter(); username.ParameterName = "@username"; username.value = txtUsername.Text; cmd.Parameters.Add(username); SqlParameter password = new SqlParameter(); password.ParameterName = "@password"; password.value = txtPassword.Text; cmd.Parameters.Add(password);
Вы начинаете с создания объекта SqlCommand
и использования парадигмы @parameter_name
в командной строке, куда должен быть вставлен пользовательский ввод.
Затем вы создаете экземпляры объектов SqlParameter
, в которые вы вставляете пользовательский ввод вместо прямой конкатенации его с командной строкой.
Наконец, вы добавляете объект SqlParameter
в SqlParameter
объекта SqlCommand
, которая заменит параметры предоставленным вводом. ADO.net позаботится обо всем остальном.
В PHP эквивалентом являются подготовленные операторы, которые немного сложнее, чем его аналог ASP.net. Вы можете изучить это здесь .
Явно приведите ваш вклад
Этот совет предназначен для таких языков, как PHP, которые слабо типизированы, что означает, что вы обычно не определяете типы данных для переменных, а язык автоматически заботится о преобразовании различных типов данных между собой.
Явные приведения могут действовать как ярлык для экранирования ввода, где задействованы не строковые типы. Итак, если вы ожидаете, что пользователь введет int
для параметра age
, вы можете обеспечить безопасность ввода с помощью следующего кода в PHP:
$age = (int)$_POST['age'];
Обратите внимание, что этот фрагмент проверяет только тип ввода, а не его диапазон. Поэтому вам нужно будет запустить другой код, чтобы убедиться, что пользователь не вводит отрицательный возраст — или нереальный, например 1300.
Кроме того, еще одна лучшая практика — избегать использования одинарных кавычек в командах SQL, где используется нестроковый ввод. Поэтому вместо использования следующего кода …
$sql_command = "select * from users where age = " . $age;
… было бы немного безопаснее использовать следующее:
$sql_command = "select * from users where age = '" . $age . "'";
Как устранить уязвимости SQL-инъекций
Как правило, вы должны проверять код каждой страницы на наличие мест, где вы комбинируете содержимое страницы, команды, строки и т. Д. С источниками, которые могут исходить от пользователей. Проверка вашего исходного кода на наличие уязвимостей и брешей в безопасности должна быть неотъемлемой частью вашего процесса разработки программного обеспечения.
Вы также можете использовать инструменты сканирования, такие как sqlmap, для сканирования страниц вашего сайта на предмет потенциальных уязвимостей SQL-инъекций. На самом деле, хакеры часто используют этот инструмент для поиска и использования векторов атак SQL-инъекций на целевых веб-сайтах, так почему бы не использовать его для повышения их безопасности?
Ваша последняя линия обороны
Независимо от того, насколько вы усилили безопасность вашего сайта , вы должны подготовиться к тому дню, когда SQL-инъекции все же будут иметь место. В конце концов, как это широко известно в индустрии кибербезопасности, защитники должны выигрывать каждый бой, а хакеры — только один раз.
Вот несколько советов, которые помогут вам минимизировать ущерб, когда вы станете жертвой SQL-инъекции.
Избегайте административных привилегий
Использование учетных записей «root» или «sa» для подключения веб-приложения к серверу базы данных — одна из худших ошибок, которые вы можете совершить. Как я уже упоминал, скомпрометированная административная учетная запись потенциально может дать хакерам доступ ко всей системе. Даже неадминистративные учетные записи, имеющие доступ ко всем базам данных на сервере, могут нанести ущерб, особенно если сервер баз данных используется совместно различными приложениями и базами данных.
Поэтому лучше использовать учетную запись, которая имеет только простые разрешения на чтение и запись для конкретной базы данных, которая находится за вашим веб-сайтом, поэтому в случае, если ваш сайт будет взломан посредством внедрения SQL-кода, масштаб ущерба остается в пределах этой единой базы данных.
Более продвинутый подход заключается в использовании отдельных соединений для сегментов кода, которые читают из вашей базы данных или записывают в нее, и дополнительно сокращает разрешения и роли для каждого сегмента. Например, страницы списка, которые не вносят никаких изменений в базу данных, но широко используют параметры поиска, могут быть закодированы для использования соединения с базой данных только для чтения, чтобы еще больше защитить ваш код от ошибок.
В MySQL повышайте безопасность, ограничивая доступ к учетной записи пользователя определенными диапазонами IP-адресов вместо модели «%», чтобы предотвратить доступ к скомпрометированным учетным записям из удаленных мест.
На сервере MS SQL я настоятельно рекомендую вам использовать модель аутентификации Windows, которая ограничит доступ хакеров к базе данных и сделает невозможным использование других каналов для доступа к вашей базе данных.
Кроме того, если вы не планируете использовать некоторые из расширенных функций SQL Server, предпочтительно настроить службу Windows для использования ограниченной учетной записи вместо учетной записи «Локальная система» с высоким уровнем привилегий. Это минимизирует ущерб в случае взлома учетной записи «sa».
Шифровать конфиденциальные данные
Шифровать конфиденциальные данные в вашей базе данных. Это включает пароли, секретные вопросы и ответы, финансовые данные, информацию о здоровье и другую информацию, которая может быть полезна злоумышленникам. Это гарантирует, что даже если хакеры возьмутся за ваши данные, они не смогут сразу же их использовать, что даст вам время обнаружить уязвимость, закрыть дыру и предпринять другие ответные меры, такие как принудительное восстановление пароля, что приведет к убедитесь, что украденные данные теряют свое значение, прежде чем злоумышленник расшифрует их.
Если вы хэшируете свои пароли, используйте надежные алгоритмы, такие как SHA-2, который вскоре станет отраслевым стандартом для защиты паролем . MD5 и SHA-1 устарели и могут быть отменены.
Что касается других форм шифрования, позаботьтесь о том, где вы храните ключи, и никогда не кладите все яйца в одну корзину. Нет смысла использовать шифрование, если ключи находятся рядом с зашифрованными данными, и хакеры легко получат к ним доступ, как только они скомпрометируют сервер.
Не храните конфиденциальные данные, если они вам не нужны
Всякий раз, когда вы храните информацию в своей базе данных, подумайте о том, какой ущерб она может нанести, если она попадет в чужие руки, и решите, действительно ли вам нужно ее хранить или нет. Взлом Эшли Мэдисон , который раскрыл мрачные секреты и самую интимную информацию около 37 миллионов человек в Интернете и нанес серьезный ущерб, отчасти был связан с его успехом тем, что провайдер воздержался от вытирания конфиденциальной информации из своих баз данных.
Таким образом, суть в том, что не храните конфиденциальную информацию в вашей базе данных, если это не требуется. И даже тогда удаляйте информацию, когда она больше не используется.
Последние мысли
SQL-инъекция существует уже несколько десятилетий и, вероятно, будет продолжать лидировать в таблицах уязвимостей в течение многих лет. Требуется несколько простых, но хорошо продуманных шагов, чтобы защитить себя и своих пользователей от этого, и это должно быть в числе ваших главных приоритетов при проверке исходного кода на наличие дыр в безопасности.
Во-первых, ключом к тому, чтобы не стать жертвой следующего огромного взлома данных внедрения SQL-кода, является контроль и проверка пользовательского ввода, а во-вторых, чтобы подготовиться к «когда», а не «если».