Безпека та СУБД: про що треба пам'ятати, підбираючи засоби захисту

Безпека та СУБД: про що треба пам'ятати, підбираючи засоби захисту

Мене звуть Денис Рожков, я керівник розробки ПЗ у компанії «Газінформсервіс», у команді продукту Ятоба. Законодавство та корпоративні норми накладають певні вимоги щодо безпеки зберігання даних. Ніхто не хоче, щоб треті особи отримали доступ до конфіденційної інформації, тому для будь-якого проекту важливими є такі питання: ідентифікація та автентифікація, управління доступами до даних, забезпечення цілісності інформації в системі, реєстрація подій безпеки. Тому я хочу розповісти про деякі цікаві моменти щодо безпеки СУБД.

Статтю підготовлено за виступом на @Databases Meetup, організованому Mail.ru Cloud Solutions. Якщо не хочете читати, можна подивитися:


У статті буде три частини:

  • Як захищати підключення
  • Що таке аудит дій та як фіксувати, що відбувається з боку бази даних та підключення до неї.
  • Як захищати дані у самій базі даних та які для цього є технології.

Безпека та СУБД: про що треба пам'ятати, підбираючи засоби захисту
Три складові безпеки СУБД: захист підключень, аудит дій та захист даних

Захист підключень

Підключатися до бази даних можна як безпосередньо, так і опосередковано через веб-програми. Як правило, користувач з боку бізнесу, тобто людина, яка працює із СУБД, взаємодіє з нею не безпосередньо.

Перед тим як говорити про захист з'єднань, потрібно відповісти на важливі питання, від яких залежить, як вибудовуватимуться заходи безпеки:

  • чи еквівалентний один бізнес-користувач одному користувачеві СУБД;
  • чи забезпечується доступ до даних СУБД лише через API, який ви контролюєте, чи є доступ до таблиць безпосередньо;
  • чи виділено СУБД в окремий захищений сегмент, хто і як із ним взаємодіє;
  • чи використовується pooling/proxy та проміжні шари, які можуть змінювати інформацію про те, як побудовано підключення та хто використовує базу даних.

Тепер подивимося, які інструменти можна застосувати для захисту підключень:

  1. Використовуйте рішення класу database firewall. Додатковий шар захисту, як мінімум, підвищить прозорість того, що відбувається в СУБД, як максимум, ви зможете забезпечити додатковий захист даних.
  2. Використовуйте парольні політики. Їх застосування залежить від того, як збудована ваша архітектура. У будь-якому випадку одного пароля в конфігураційному файлі веб-програми, що підключається до СУБД, мало для захисту. Є низка інструментів СУБД, що дозволяють контролювати, що користувач та пароль потребують актуалізації.

    Детальніше про функції оцінки користувачів можна тут, так само про MS SQL Vulnerability Assessmen можна дізнатися тут

  3. Збагачуйте контекст сесії необхідною інформацією. Якщо сесія непрозора, ви не розумієте, хто в її рамках працює в СУБД, можна в рамках операції доповнити інформацію про те, хто, що і навіщо робить. Цю інформацію можна побачити в аудиті.
  4. Налаштуйте SSL, якщо у вас немає мережевого розмежування СУБД від кінцевих користувачів, вона не в окремому VLAN. У разі обов'язково захищати канал між споживачем і самої СУБД. Інструменти захисту є в тому числі серед open source.

Як це вплине на продуктивність СУБД?

Подивимося на прикладі PostgreSQL, як SSL впливає на навантаження CPU, збільшення таймінгів та зменшення TPS, чи не піде занадто багато ресурсів, якщо його включити.

Навантажуємо PostgreSQL, використовуючи pgbench – це проста програма для запуску тестів продуктивності. Вона багаторазово виконує одну послідовність команд, можливо, в паралельних сеансах бази даних, а потім обчислює середню швидкість транзакцій.

Тест 1 без SSL та з використанням SSL - З'єднання встановлюється при кожній транзакції:

pgbench.exe --connect -c 10 -t 5000 "host=192.168.220.129 dbname=taskdb user=postgres sslmode=require 
sslrootcert=rootCA.crt sslcert=client.crt sslkey=client.key"

vs

pgbench.exe --connect -c 10 -t 5000 "host=192.168.220.129 dbname=taskdb user=postgres"

Тест 2 без SSL та з використанням SSL - Всі транзакції виконуються в одне з'єднання:

pgbench.exe -c 10 -t 5000 "host=192.168.220.129 dbname=taskdb user=postgres sslmode=require
sslrootcert=rootCA.crt sslcert=client.crt sslkey=client.key"

vs

pgbench.exe -c 10 -t 5000 "host=192.168.220.129 dbname=taskdb user=postgres"

Інші налаштування:

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

tps excluding connections establishing
64.084546
58.725846

центральний процесор
24%
28%

Усі транзакції виконуються в одне з'єднання

latency average
6.722 мс
6.342 мс

tps including connections establishing
1587.657278
1576.792883

tps excluding connections establishing
1588.380574
1577.694766

центральний процесор
17%
21%

При невеликих навантаженнях вплив 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 проводимо три тести навантаження, використовуючи команди:

$ pgbench -p 3389 -U postgres -i -s 150 benchmark
$ pgbench -p 3389 -U postgres -c 50 -j 2 -P 60 -T 600 benchmark
$ pgbench -p 3389 -U postgres -c 150 -j 2 -P 60 -T 600 benchmark

Результати тестування:

Без логування
З логуванням

Підсумковий час наповнення БД
43,74 сек
53,23 сек

ОЗУ
24%
40%

центральний процесор
72%
91%

Тест 1 (50 коннектів)

Кількість транзакцій за 10 хв
74169
32445

Транзакцій/сек
123
54

Середня затримка
405 мс
925 мс

Тест 2 (150 коннектів при 100 можливих)

Кількість транзакцій за 10 хв
81727
31429

Транзакцій/сек
136
52

Середня затримка
550 мс
1432 мс

Про розміри

Розмір БД
2251 МБ
2262 МБ

Розмір логів БД
0 Мб
4587 Мб

Зрештою: повний аудит — це не дуже добре. Даних від аудиту вийде за обсягом, як даних у самій базі даних, а то й більше. Такий обсяг журналування, що генерується під час роботи з СУБД, — звичайна проблема на продуктивності.

Дивимося інші параметри:

  • Швидкість не змінюється: без логування — 43,74 сек, з логуванням — 53,23 сек.
  • Продуктивність по ОЗУ і CPU просідатиме, оскільки потрібно сформувати файл з аудитом. Це також помітно на продуктивності.

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

У корпораціях з аудитом ще складніше:

  • даних багато;
  • аудит потрібен як через syslog в SIEM, а й у файли: раптом з syslog щось станеться, має бути близько до бази файл, у якому збережуться дані;
  • для аудиту потрібна окрема полиця, щоб не просісти по I/O дисків, оскільки він займає багато місця;
  • буває, що співробітникам ІБ потрібні скрізь ДСТУ, вони вимагають гостову ідентифікацію.

Обмеження доступу до даних

Подивимося на технології, які використовують для захисту даних та доступу до них у комерційних СУБД та open source.

Що загалом можна використовувати:

  1. Шифрування та обфускація процедур і функцій (Wrapping) — тобто окремі інструменти та утиліти, які з коду, що читається, роблять нечитаний. Щоправда, потім його не можна ні змінити, ні зарефакторити назад. Такий підхід іноді потрібний як мінімум на боці СУБД — логіка ліцензійних обмежень чи логіка авторизації шифрується саме на рівні процедури та функції.
  2. Обмеження видимості даних рядків (RLS) — це коли різні користувачі бачать одну таблицю, але різний склад рядків у ній, тобто комусь щось не можна показувати лише на рівні рядків.
  3. Редагування даних, що відображаються (Masking) — це коли користувачі в одній колонці таблиці бачать або дані, або тільки зірочки, тобто для якихось користувачів інформація буде закрита. Технологія визначає, якому користувачеві що показувати з урахуванням рівня доступу.
  4. Розмежування доступу Security DBA/Application DBA/DBA - це, швидше, про обмеження доступу до самої СУБД, тобто співробітників ІБ можна відокремити від database-адміністраторів та application-адміністраторів. У open source таких технологій небагато, у комерційних СУБД їх вистачає. Вони потрібні, коли багато користувачів з доступом до серверів.
  5. Обмеження доступу до файлів на рівні файлової системи. Можна видавати права, привілеї доступу до каталогів, щоб кожен адміністратор отримував доступ лише до потрібних даних.
  6. Мандатний доступ та очищення пам'яті – ці технології застосовують рідко.
  7. End-to-end encryption безпосередньо СУБД - це client-side шифрування з керуванням ключами на серверній стороні.
  8. Шифрування даних. Наприклад, колонкове шифрування - коли ви використовуєте механізм, який шифрує окрему колонку бази.

Як це впливає на продуктивність СУБД?

Подивимося з прикладу колонкового шифрування в 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'));

Далі спробуємо зробити з кожної таблиці вибірку даних та подивимося на таймінги виконання.

Вибірка з таблиці без функції шифрування:

psql -c "timing" -c "select * from t1 limit 1000;" "host=192.168.220.129 dbname=taskdb
user=postgres sslmode=disable" > 1.txt

Секундомір увімкнено.

  ID | text1 | text2
——+——-+——-
1 | 1 | 1
2 | 2 | 2
3 | 3 | 3
...
997 | 997 | 997
998 | 998 | 998
999 | 999 | 999
1000 | 1000 | 1000
(1000 рядків)

Час: 1,386 мс

Вибір з таблиці з функцією шифрування:

psql -c "timing" -c "select id, decrypt(text1, 'key'::bytea, 'bf'),
decrypt(text2, 'key'::bytea, 'bf') from t2 limit 1000;"
"host=192.168.220.129 dbname=taskdb user=postgres sslmode=disable" > 2.txt

Секундомір увімкнено.

  ID | decrypt | decrypt
——+—————+————
1 | x31 | x31
2 | x32 | x32
3 | x33 | x33
...
999 | x393939 | x393939
1000 | x31303030 | x31303030
(1000 рядків)

Час: 50,203 мс

Результати тестування:

 
Без шифрування
Pccrypto (decrypt)

Вибірка 1000 рядків
1,386 мс
50,203 мс

центральний процесор
15%
35%

ОЗУ
 
+ 5%

Шифрування дуже впливає на продуктивність. Видно, що зріс таймінг, оскільки операції дешифрації зашифрованих даних (а дешифрація зазвичай ще обернена у вашу логіку) вимагають значних ресурсів. Тобто ідея зашифрувати всі колонки, які містять якісь дані, загрожує зниженням продуктивності.

При цьому шифрування не срібна куля, яка вирішує всі питання. Розшифровані дані та ключ дешифрування в процесі розшифровування та передачі даних знаходяться на сервері. Тому ключі можуть бути перехоплені тим, хто має повний доступ до сервера бази даних, наприклад системним адміністратором.

Коли на всю колонку для всіх користувачів один ключ (навіть якщо не для всіх, а для клієнтів обмеженого набору) це не завжди добре і правильно. Саме тому почали робити end-to-end шифрування, в СУБД почали розглядати варіанти шифрування даних з боку клієнта і сервера, з'явилися ті самі key-vault сховища - окремі продукти, які забезпечують керування ключами на стороні СУБД.

Безпека та СУБД: про що треба пам'ятати, підбираючи засоби захисту
Приклад такого шифрування в MongoDB

Засоби безпеки в комерційних та open source СУБД

Функції
Тип
Правила пароля
Аудит
Захист вихідного коду процедур та функцій
RLS
Шифрування

оракул
Комерційна
+
+
+
+
+

MsSql
Комерційна
+
+
+
+
+

Ятоба
Комерційна
+
+
+
+
Розширення

PostgreSQL
Безкоштовна
Розширення
Розширення
-
+
Розширення

MongoDB
Безкоштовна
-
+
-
-
Доступно в MongoDB Enterprise only

Таблиця далеко не повна, але ситуація така: у комерційних продуктах завдання безпеки вирішуються давно, в open source, як правило, для безпеки використовують якісь надбудови, багатьох функцій не вистачає, іноді доводиться щось дописувати. Наприклад, парольні політики — у PostgreSQL багато різних розширень (1, 2, 3, 4, 5), які реалізують парольні політики, але всі потреби вітчизняного корпоративного сегменту, як на мене, жодне не покриває.

Що робити, якщо ніде немає того, що потрібно? Наприклад, хочеться використовувати певну СУБД, у якій немає функцій, які вимагає замовник.

Тоді можна використовувати сторонні рішення, які працюють із різними СУБД, наприклад, «Крипто БД» або «Гарда БД». Якщо мова про рішення з вітчизняного сегменту, то там про ДСТУ знають краще, ніж у open source.

Другий варіант - самостійно написати, що потрібно, реалізувати на рівні процедур доступ до даних та шифрування у додатку. Щоправда, із ГОСТом буде складніше. Але в цілому ви можете приховати дані, як потрібно, скласти в СУБД, потім дістати і розшифрувати як треба, прямо на рівні application. При цьому відразу думайте, як ви будете ці алгоритми на application захищати. На наш погляд, це потрібно робити на рівні СУБД, бо так працюватиме швидше.

Ця доповідь вперше прозвучала на @Databases Meetup by Mail.ru Cloud Solutions. Дивіться відео інших виступів та підписуйтесь на анонси заходів у Telegram Навколо Kubernetes у Mail.ru Group.

Що ще почитати на тему:

  1. Більше ніж Ceph: блочне сховище хмари MCS.
  2. Як вибрати базу даних для проекту, щоб не вибирати знову.

Джерело: habr.com

Додати коментар або відгук