вступление

Сегодня мы узнаем, как провести атаку SQL Injection и как ее предотвратить.

Знаете ли вы, что хакеры крадут миллиарды долларов каждый год?

Знаете ли вы, что почти каждые 30 секунд происходит новая хакерская атака?

Если мы разработчики, мы всегда должны заботиться о безопасности нашего кода (хотя бы немного). Неважно, делаем ли мы фронтенд или бэкэнд, оба они уязвимы.

Сегодня я хотел бы немного рассказать вам об атаке SQL Injection, что это такое, как это сделать, чем это опасно и как защитить от этого ваше приложение.

Давайте начнем!

Если вы предпочитаете видео, вот версия для YouTube:

Что такое SQL-инъекция

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

Это похоже на ситуацию, когда мы можем запушить какие-то пользовательские и нежелательные команды в базу данных SQL.

Например, когда у нас есть ввод имени пользователя, мы можем поместить пользовательские команды.

Например, мы можем использовать удаление целых таблиц, получение данных из других таблиц базы данных или автоматическую разблокировку учетной записи администратора.

Почему SQL-инъекция опасна

Утечка данных

С помощью SQL Injection злоумышленник может быстро получить доступ к данным, которые никогда не должны быть доступны обычному пользователю.

Например, это могут быть ваши личные сообщения, банковские транзакции, конфиденциальные личные данные, такие как ваш идентификатор или место вашего проживания.

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

Возможные повреждения

Этот тип атаки может дать возможность запустить любую команду SQL, а не только получение данных.

Например, злоумышленник может перевести деньги с вашего счета на свой, изменить баланс вашего счета или удалить все записи.

Это может быть очень болезненно, особенно когда нет резервной копии.

Несанкционированный доступ

Когда мы создаем приложение, очень часто у нас есть какое-то разрешение для роли x.

Например, только администратор может удалять или редактировать записи, запрос в друзья должен быть принят приглашенным человеком и т. д.

Что, если бы злоумышленник мог зайти в БД и отправить сообщения из вашей учетной записи, добавить свою учетную запись в качестве проверенного друга или отредактировать сообщения из вашего профиля в социальной сети?

Давайте выполним атаку SQL Injection

Теперь мы проведем простую атаку, чтобы получить доступ к чьей-либо учетной записи.

Мы создали банковское приложение, которое вы можете протестировать на предмет атаки, проверить код и ответы, чтобы полностью понять, как оно работает.

Требования для проведения атаки SQL Injection:

Загрузите наш внутренний код:

Вот ссылка на код серверной части Golang для банковского приложения:

https://github.com/Duomly/go-bank-backend

Клонируйте его и заходите в эту папку.

Настройте базу данных PostgreSQL:

Вам нужно создать новую БД Postgres.

Назовите его bankapp и используйте пользователя Postgres, или вы можете использовать любого другого пользователя.

В этом случае вам нужно будет изменить строку подключения.

Настройка соединения во внутреннем коде:

Вам необходимо настроить строку подключения в двух файлах, уязвимых-db.go и migrations.go

Начать перенос:

Теперь вам нужно перейти на main.go, прокомментировать код API и раскомментировать миграцию.

Ваш код основной функции должен выглядеть так.

func main() {
migrations.Migrate()
// api.StartApi()
}

Загрузите наш интерфейсный код отсюда:

На этом шаге мы должны перейти по URL-адресу:

https://github.com/Duomly/angular9-tailwind-bank-frontend

Клонируйте приложение и перейдите в папку.

Затем мы должны установить наши зависимости с помощью npm install и запустить приложение с помощью npm start.

Приступим к веселью:

На последнем шаге конфига мы должны раскомментировать изменения, которые мы сделали ранее, и запустить API.

Код нашей основной функции на main.go должен выглядеть так:

func main() {
// migrations.Migrate()
api.StartApi()
}

Последний шаг — запустить main.go, набрав в терминале:

go run main.go

Поздравляем, вы готовы начать взлом!

Стандартные учетные данные:

Мы создали двух разных пользователей, и стандартные учетные данные для них:

Пользователь 1:

user: Martin
password: Martin

Пользователь 2:

user: Michael
password: Michael

Что мы будем делать:

Как вы могли заметить, у нас простое хеширование и поиск пароля, который уже хеширован.

Таким образом, все приемы, которые мы будем вводить в поле ввода пароля, будут преобразованы в хеш (даже если мы добавим туда какие-то SQL-команды), а значит, SQL не увидит их как SQL-команды.

В этом случае нам нужно сосредоточиться на вводе имени пользователя.

Это может сработать, потому что он входит в SQL как чистая строка.

Я специально создал это, чтобы быть уязвимым там.

Вы не должны делать это в своем собственном приложении.

В следующем разделе статьи я расскажу, как это сделать правильно.

Найти пользователя по имени пользователя

Чтобы получить пользователя по имени пользователя, мы можем использовать одну из этих строк в поле ввода имени пользователя.

Конечно, есть еще много методов, которые вы можете использовать.

Martin’ or username=’Martin’ AND 1 = 1 --

or

xx’ or username=’Martin’ AND 1 = 1 --

Это работает вроде как получить пользователя по имени Мартин или по имени Мартин и правда, если мы изменим первого Мартина на Майкла, мы получим оба профиля.

Второй работает как получение пользователя с именем пользователя xx или именем пользователя Martin и true.

Получить всех пользователей

Используя эту строку при вводе имени пользователя, мы сможем получить все записи из таблицы с именем users.

Martin’ or 1 = 1 --

Этот метод работает так же, как получение пользователей с именем пользователя Martin или true.

Это означает, что «или верно» получат все остальные пользователи, потому что условие пройдено.

Получить пользователя по идентификатору

Мы можем взять пользователя по его идентификатору, когда используем эту комбинацию в поле ввода имени пользователя.

Это особенно полезно, когда мы ищем администратора (очень часто по умолчанию администраторы имеют идентификатор 1).

xx’ or id=2 AND 1 = 1 --

Этот один из способов работает так же, как получить пользователя с именем пользователя xx или идентификатором 2, и это правда.

Что означают эти символы:

OR 1=1

Это означает, что 1 равно 1, что верно. Это как пройти условие.

'

Эта одна метка похожа на побег из веревки.

Это дает нам возможность экранировать строку в SQL и начать вызывать правильную команду SQL.

--

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

Это очень полезно, например, когда у нас есть больше полей, которые мы также отправляем, например, пароль.

Когда мы используем эту отметку, наш SQL также игнорирует информацию о том, что пароль должен быть проверен.

Как защитить приложение от SQL Injection

Внешняя проверка формы

Конечно, у умного злоумышленника не должно быть так много проблем, чтобы избежать проверки переднего плана.

Тем не менее, это то, что будет первым препятствием.

Вы можете добавить специальную проверку к своим формам.

Это может проверить, совпадает ли ваша электронная почта с электронной почтой, если ваше имя пользователя содержит какие-либо специальные символы или длина не слишком велика.

Если вы обнаружите подозрительные комбинации, вы можете заблокировать форму.

Вы можете отправить красный флаг на серверную часть о том, что пользователь с этим IP/учетными данными пытался совершить какую-либо атаку.

Вы можете, например, заблокировать его IP на время или навсегда.

Опять же, злоумышленник будет знать, как избежать вашего бана.

Тем не менее, это новое препятствие, и некоторые люди могут отказаться от того, чтобы тратить больше времени на ваше приложение.

Проверка внутренних переменных

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

Это может быть очень полезно, потому что пройти внутреннюю проверку гораздо сложнее, чем внешнюю.

Это полезно, особенно если вы добавите ограничения на количество звонков, которые пользователи могут сделать сразу.

Дополнительное сравнение проходов, например CompareHashAndPassword

Этот метод может помочь вам остановить отправку данных обратно злоумышленнику.

Конечно, злоумышленник может нанести ущерб, например, удалить что-то или изменить записи, если вы позволите ему сделать SQL-инъекцию.

Тем не менее, вы можете, например, найти запись пользователя x в БД.

Затем выполните аутентификацию учетных данных с помощью bcrypt.CompareHashAndPassword.

Приложение не вернет запрошенные данные клиенту обратно и должно выдать ошибку, не связанную с аутентификацией.

Используйте библиотеки/фреймворки SQL

Использование некоторых фреймворков, таких как gorm для golang или sequenceize для node.js, может сильно помочь вам с безопасностью.

В большинстве из них есть дополнительный уровень безопасности.

Это проверит правильность параметров и создаст правильные запросы из данных, которые пользователь отправляет на сервер.

Объявить типы

Это очень важно. Объявив жесткие типы, вы избежите многих проблем, не только с безопасностью.

Если вы правильно настроите все интерфейсы и типы, практически невозможно отправить неверные данные обратно.

Все данные будут отправлены в формате 100%, который вы хотели бы вернуть конечному клиенту (пользователю).

Вывод

Поздравляем!

Теперь вы знаете, как выполнить атаку SQL Injection и как защитить свое приложение от нее.

Я надеюсь, что это будет очень полезно, когда вы создаете свое собственное программное обеспечение.

Вы должны помнить, что использование его против приложений, на которые у вас нет разрешения от владельцев, является незаконным.

В любом случае, вы можете загрузить наш код, создать собственное приложение или найти виртуальные лаборатории, где вы сможете это сделать и протестировать.

Подпишитесь на нас, чтобы получить больше руководств по программированию.

Вот мой учебник по SQL Join:

SQL Join с примерами учебника

Спасибо за чтение,

Радек из Дуомли