Безпека та СУБД: про що треба пам'ятати, підбираючи засоби захисту
Мене звуть Денис Рожков, я керівник розробки ПЗ у компанії «Газінформсервіс», у команді продукту Ятоба. Законодавство та корпоративні норми накладають певні вимоги щодо безпеки зберігання даних. Ніхто не хоче, щоб треті особи отримали доступ до конфіденційної інформації, тому для будь-якого проекту важливими є такі питання: ідентифікація та автентифікація, управління доступами до даних, забезпечення цілісності інформації в системі, реєстрація подій безпеки. Тому я хочу розповісти про деякі цікаві моменти щодо безпеки СУБД.
Статтю підготовлено за виступом на @Databases Meetup, організованому Mail.ru Cloud Solutions. Якщо не хочете читати, можна подивитися:
У статті буде три частини:
Як захищати підключення
Що таке аудит дій та як фіксувати, що відбувається з боку бази даних та підключення до неї.
Як захищати дані у самій базі даних та які для цього є технології.
Три складові безпеки СУБД: захист підключень, аудит дій та захист даних
Захист підключень
Підключатися до бази даних можна як безпосередньо, так і опосередковано через веб-програми. Як правило, користувач з боку бізнесу, тобто людина, яка працює із СУБД, взаємодіє з нею не безпосередньо.
Перед тим як говорити про захист з'єднань, потрібно відповісти на важливі питання, від яких залежить, як вибудовуватимуться заходи безпеки:
чи еквівалентний один бізнес-користувач одному користувачеві СУБД;
чи забезпечується доступ до даних СУБД лише через API, який ви контролюєте, чи є доступ до таблиць безпосередньо;
чи виділено СУБД в окремий захищений сегмент, хто і як із ним взаємодіє;
чи використовується pooling/proxy та проміжні шари, які можуть змінювати інформацію про те, як побудовано підключення та хто використовує базу даних.
Тепер подивимося, які інструменти можна застосувати для захисту підключень:
Використовуйте рішення класу database firewall. Додатковий шар захисту, як мінімум, підвищить прозорість того, що відбувається в СУБД, як максимум, ви зможете забезпечити додатковий захист даних.
Використовуйте парольні політики. Їх застосування залежить від того, як збудована ваша архітектура. У будь-якому випадку одного пароля в конфігураційному файлі веб-програми, що підключається до СУБД, мало для захисту. Є низка інструментів СУБД, що дозволяють контролювати, що користувач та пароль потребують актуалізації.
Детальніше про функції оцінки користувачів можна тут, так само про MS SQL Vulnerability Assessmen можна дізнатися тут.
Збагачуйте контекст сесії необхідною інформацією. Якщо сесія непрозора, ви не розумієте, хто в її рамках працює в СУБД, можна в рамках операції доповнити інформацію про те, хто, що і навіщо робить. Цю інформацію можна побачити в аудиті.
Налаштуйте SSL, якщо у вас немає мережевого розмежування СУБД від кінцевих користувачів, вона не в окремому VLAN. У разі обов'язково захищати канал між споживачем і самої СУБД. Інструменти захисту є в тому числі серед open source.
Як це вплине на продуктивність СУБД?
Подивимося на прикладі PostgreSQL, як SSL впливає на навантаження CPU, збільшення таймінгів та зменшення TPS, чи не піде занадто багато ресурсів, якщо його включити.
Навантажуємо PostgreSQL, використовуючи pgbench – це проста програма для запуску тестів продуктивності. Вона багаторазово виконує одну послідовність команд, можливо, в паралельних сеансах бази даних, а потім обчислює середню швидкість транзакцій.
Тест 1 без SSL та з використанням SSL - З'єднання встановлюється при кожній транзакції:
scaling factor: 1
query mode: simple
number of clients: 10
number of threads: 1
number of transactions per client: 5000
number of transactions actually processed: 50000/50000
Результати тестування:
NO SSL SSL
Встановлюється з'єднання кожної трансакції
latency average
171.915 мс
187.695 мс
tps including connections establishing
58.168112
53.278062
При невеликих навантаженнях вплив SSL можна порівняти з похибкою вимірювання. Якщо обсяг даних, що передаються, дуже великий, ситуація може бути інша. Якщо ми встановлюємо одне з'єднання на кожну транзакцію (це буває рідко, зазвичай з'єднання ділять між користувачами), у вас велика кількість підключень/вимкнень, вплив може бути трохи більшим. Тобто ризики зниження продуктивності можуть бути, однак різниця не настільки велика, щоб не використовувати захист.
Зверніть увагу — сильна відмінність є, якщо порівнювати режими роботи: в рамках однієї сесії ви працюєте чи різних. Це зрозуміло: створення кожного з'єднання витрачаються ресурси.
У нас був кейс, коли ми підключали Zabbix в режимі trust, тобто md5 не перевіряли, аутентифікації не було необхідності. Потім замовник попросив увімкнути режим MD5-аутентифікації. Це дало велике навантаження на CPU, продуктивність просіла. Почали шукати шляхи оптимізації. Одне з можливих рішень проблеми — реалізувати мережне обмеження, зробити для СУБД окремі VLAN, додати налаштування, щоб було зрозуміло, хто і звідки підключається і прибрати аутентифікацію. автентифікації впливає продуктивність і вимагає враховувати ці чинники під час проектування обчислювальних потужностей серверів (заліза) для СУБД.
Висновок: у ряді рішень навіть невеликі нюанси на аутентифікації можуть сильно позначитися на проекті і погано, коли це стає зрозумілим лише при впровадженні в продуктив.
Аудит дій
Аудит може бути не лише СУБД. Аудит - це отримання інформації про те, що відбувається на різних сегментах. Це може бути і database firewall, і операційна система, де будується СУБД.
У комерційних СУБД рівня Enterprise з аудитом все гаразд, в open source — не завжди. Ось що є в PostgreSQL:
default log - вбудоване логування;
extensions: pgaudit - якщо вам не вистачає дефолтного логування, можна скористатися окремими налаштуваннями, які вирішують частину завдань.
Додаток до доповіді у відео:
Базова реєстрація операторів може бути забезпечена стандартним засобом ведення журналу з log_statement = all.
Це прийнятно для моніторингу та інших видів використання, але не забезпечує рівень деталізації, який зазвичай необхідний для аудиту.
Недостатньо мати список усіх операцій, які виконуються з базою даних.
Також має бути можливість знайти конкретні твердження, які становлять інтерес для аудитора.
Стандартний засіб ведення журналу показує те, що запитав користувач, а pgAudit фокусується на деталях того, що сталося, коли база даних виконувала запит.
Наприклад, аудитор може захотіти переконатися, що конкретну таблицю було створено у задокументованому вікні обслуговування.
Це може здатися простим завданням для базового аудиту та grep, але що, якщо вам представиться щось на зразок цього (навмисно заплутаного) прикладу:
DO $$
ПОЧАТИ
EXECUTE 'CREATE TABLE import' || 'ant_table (id INT)';
END $$;
Стандартне ведення журналу дасть вам це:
LOG: statement: DO $$
ПОЧАТИ
EXECUTE 'CREATE TABLE import' || 'ant_table (id INT)';
END $$;
Схоже, що для пошуку таблиці, що цікавить, може знадобитися деяке знання коду в тих випадках, коли таблиці створюються динамічно.
Це не ідеально, тому що було б краще просто шукати на ім'я таблиці.
Ось де буде корисний pgAudit.
Для того самого введення він видасть цей висновок у журналі:
AUDIT: SESSION,33,1,FUNCTION,DO,,,«DO $$
ПОЧАТИ
EXECUTE 'CREATE TABLE import' || 'ant_table (id INT)';
END $$;"
AUDIT: SESSION,33,2,DDL,CREATE TABLE,TABLE,public.important_table,CREATE TABLE important_table (id INT)
Реєструється не тільки блок DO, а й повний текст CREATE TABLE з типом оператора, типом об'єкта та повним ім'ям, що полегшує пошук.
Під час ведення журналу операторів SELECT та DML pgAudit можна налаштувати для реєстрації окремого запису для кожного відношення, на яке є посилання в операторі.
Не потрібний синтаксичний аналіз, щоб знайти всі оператори, які стосуються конкретної таблиці(*) ».
Як це вплине на продуктивність СУБД?
Давайте проведемо тести з включенням повного аудиту та подивимося, що буде з продуктивністю PostgreSQL. Включимо максимальне логування БД за всіма параметрами.
У конфігураційному файлі майже нічого не змінюємо, з важливого – включаємо режим debug5, щоб отримати максимум інформації.
postgresql.conf
log_destination = 'stderr'
logging_collector = on
log_truncate_on_rotation = on
log_rotation_age = 1d
log_rotation_size = 10MB
log_min_messages = налагодження5
log_min_error_statement = налагодження5
log_min_duration_statement = 0
debug_print_parse = on
debug_print_rewritten = on
debug_print_plan = on
debug_pretty_print = on
log_checkpoints = увімкнено
log_connections = увімкнено
log_disconnections = увімкнено
log_duration = on
log_hostname = on
log_lock_waits = увімкнено
log_replication_commands = on
log_temp_files = 0
log_timezone = 'Europe/Moscow'
На СУБД PostgreSQL з параметрами 1 CPU, 2,8 ГГц, 2 Гб ОЗУ, 40 Гб HDD проводимо три тести навантаження, використовуючи команди:
Зрештою: повний аудит — це не дуже добре. Даних від аудиту вийде за обсягом, як даних у самій базі даних, а то й більше. Такий обсяг журналування, що генерується під час роботи з СУБД, — звичайна проблема на продуктивності.
Дивимося інші параметри:
Швидкість не змінюється: без логування — 43,74 сек, з логуванням — 53,23 сек.
Продуктивність по ОЗУ і CPU просідатиме, оскільки потрібно сформувати файл з аудитом. Це також помітно на продуктивності.
При збільшенні числа коннектів, природно, показники трохи погіршуватимуться.
У корпораціях з аудитом ще складніше:
даних багато;
аудит потрібен як через syslog в SIEM, а й у файли: раптом з syslog щось станеться, має бути близько до бази файл, у якому збережуться дані;
для аудиту потрібна окрема полиця, щоб не просісти по I/O дисків, оскільки він займає багато місця;
буває, що співробітникам ІБ потрібні скрізь ДСТУ, вони вимагають гостову ідентифікацію.
Обмеження доступу до даних
Подивимося на технології, які використовують для захисту даних та доступу до них у комерційних СУБД та open source.
Що загалом можна використовувати:
Шифрування та обфускація процедур і функцій (Wrapping) — тобто окремі інструменти та утиліти, які з коду, що читається, роблять нечитаний. Щоправда, потім його не можна ні змінити, ні зарефакторити назад. Такий підхід іноді потрібний як мінімум на боці СУБД — логіка ліцензійних обмежень чи логіка авторизації шифрується саме на рівні процедури та функції.
Обмеження видимості даних рядків (RLS) — це коли різні користувачі бачать одну таблицю, але різний склад рядків у ній, тобто комусь щось не можна показувати лише на рівні рядків.
Редагування даних, що відображаються (Masking) — це коли користувачі в одній колонці таблиці бачать або дані, або тільки зірочки, тобто для якихось користувачів інформація буде закрита. Технологія визначає, якому користувачеві що показувати з урахуванням рівня доступу.
Розмежування доступу Security DBA/Application DBA/DBA - це, швидше, про обмеження доступу до самої СУБД, тобто співробітників ІБ можна відокремити від database-адміністраторів та application-адміністраторів. У open source таких технологій небагато, у комерційних СУБД їх вистачає. Вони потрібні, коли багато користувачів з доступом до серверів.
Обмеження доступу до файлів на рівні файлової системи. Можна видавати права, привілеї доступу до каталогів, щоб кожен адміністратор отримував доступ лише до потрібних даних.
Мандатний доступ та очищення пам'яті – ці технології застосовують рідко.
End-to-end encryption безпосередньо СУБД - це client-side шифрування з керуванням ключами на серверній стороні.
Шифрування даних. Наприклад, колонкове шифрування - коли ви використовуєте механізм, який шифрує окрему колонку бази.
Як це впливає на продуктивність СУБД?
Подивимося з прикладу колонкового шифрування в PostgreSQL. Там є модуль pgcrypto, він дозволяє у зашифрованому вигляді зберігати обрані поля. Це корисно, коли цінність представляють лише деякі дані. Щоб прочитати зашифровані поля, клієнт передає ключ, що дешифрує, сервер розшифровує дані і видає їх клієнту. Без ключа з вашими даними, ніхто нічого не зможе зробити.
Проведемо тест c pgcrypto. Створимо таблицю із зашифрованими даними та із звичайними даними. Нижче команди для створення таблиць, в першому рядку корисна команда - створення самого extension з реєстрацією СУБД:
CREATE EXTENSION pgcrypto;
CREATE TABLE t1 (id integer, text1 text, text2 text);
CREATE TABLE t2 (id integer, text1 bytea, text2 bytea);
INSERT INTO t1 (id, text1, text2)
VALUES (generate_series(1,10000000), generate_series(1,10000000)::text, generate_series(1,10000000)::text);
INSERT INTO t2 (id, text1, text2) VALUES (
generate_series(1,10000000),
encrypt(cast(generate_series(1,10000000) AS text)::bytea, 'key'::bytea, 'bf'),
encrypt(cast(generate_series(1,10000000) AS text)::bytea, 'key'::bytea, 'bf'));
Далі спробуємо зробити з кожної таблиці вибірку даних та подивимося на таймінги виконання.
Шифрування дуже впливає на продуктивність. Видно, що зріс таймінг, оскільки операції дешифрації зашифрованих даних (а дешифрація зазвичай ще обернена у вашу логіку) вимагають значних ресурсів. Тобто ідея зашифрувати всі колонки, які містять якісь дані, загрожує зниженням продуктивності.
При цьому шифрування не срібна куля, яка вирішує всі питання. Розшифровані дані та ключ дешифрування в процесі розшифровування та передачі даних знаходяться на сервері. Тому ключі можуть бути перехоплені тим, хто має повний доступ до сервера бази даних, наприклад системним адміністратором.
Коли на всю колонку для всіх користувачів один ключ (навіть якщо не для всіх, а для клієнтів обмеженого набору) це не завжди добре і правильно. Саме тому почали робити end-to-end шифрування, в СУБД почали розглядати варіанти шифрування даних з боку клієнта і сервера, з'явилися ті самі key-vault сховища - окремі продукти, які забезпечують керування ключами на стороні СУБД.
PostgreSQL
Безкоштовна
Розширення
Розширення
-
+
Розширення
MongoDB
Безкоштовна
-
+
-
-
Доступно в MongoDB Enterprise only
Таблиця далеко не повна, але ситуація така: у комерційних продуктах завдання безпеки вирішуються давно, в open source, як правило, для безпеки використовують якісь надбудови, багатьох функцій не вистачає, іноді доводиться щось дописувати. Наприклад, парольні політики — у PostgreSQL багато різних розширень (1, 2, 3, 4, 5), які реалізують парольні політики, але всі потреби вітчизняного корпоративного сегменту, як на мене, жодне не покриває.
Що робити, якщо ніде немає того, що потрібно? Наприклад, хочеться використовувати певну СУБД, у якій немає функцій, які вимагає замовник.
Тоді можна використовувати сторонні рішення, які працюють із різними СУБД, наприклад, «Крипто БД» або «Гарда БД». Якщо мова про рішення з вітчизняного сегменту, то там про ДСТУ знають краще, ніж у open source.
Другий варіант - самостійно написати, що потрібно, реалізувати на рівні процедур доступ до даних та шифрування у додатку. Щоправда, із ГОСТом буде складніше. Але в цілому ви можете приховати дані, як потрібно, скласти в СУБД, потім дістати і розшифрувати як треба, прямо на рівні application. При цьому відразу думайте, як ви будете ці алгоритми на application захищати. На наш погляд, це потрібно робити на рівні СУБД, бо так працюватиме швидше.