Напередодні старту нового набору на курс продовжуємо публікувати серію статей про шифрування MySQL.

У попередній статті цієї серії () ми говорили про сховища ключів. У цій статті ми розглянемо, як використовується головний ключ (master key), а також обговоримо переваги та недоліки шифрування методом конвертів (envelope encryption).
Ідея шифрування конвертів полягає в тому, що ключі (ключі табличних просторів), що використовуються для шифрування, шифруються іншим ключем (головним ключем, master key). Для шифрування даних фактично використовуються ключі табличних просторів. Графічно це можна так:

Головний ключ (master key) перебуває у сховище ключів (keyring), а ключі табличних просторів — заголовках зашифрованих табличних просторів (на сторінці 0 табличного простору).
На малюнку вище:
-
Таблиця A зашифрована ключем 1 (Key 1). Ключ 1 шифрується за допомогою головного ключа (master key) і зберігається у зашифрованому вигляді у заголовку таблиці A.
-
Таблиця B зашифрована ключем 2 (Key 2). Ключ 2 шифрується за допомогою головного ключа (masker key) і зберігається у зашифрованому вигляді у заголовку таблиці B.
-
І так далі.
Коли серверу необхідно розшифрувати таблицю A, він отримує головний ключ зі сховища, читає зашифрований ключ 1 із заголовка таблиці A і ключ 1 розшифровує. Розшифрований ключ 1 кешується в пам'яті сервера і використовується для розшифрування таблиці A.
InnoDB
В InnoDB фактичне шифрування та дешифрування виконуються на рівні вводу-виводу. Тобто, сторінка шифрується безпосередньо перед тим, як вона скидається на диск і розшифровується відразу після зчитування з диска.
У InnoDB шифрування працює лише на рівні табличних просторів. І за замовчуванням усі таблиці створюються в окремих табличних просторах (). Іншими словами, створюється табличний простір, який може містити лише одну таблицю. Хоча ви можете створювати таблиці також і в основному табличному просторі (). Але в будь-якому випадку таблиця завжди знаходиться в якомусь табличному просторі. І оскільки шифрування здійснюється на рівні табличного простору, воно або повністю зашифроване, або ні. Тобто не можна в основному табличному просторі зашифрувати лише частину таблиць.
Якщо з будь-якої причини у вас вимкнено file-per-table, то всі таблиці створюються всередині системного табличного простору (system tablespace). У можна зашифрувати системний табличний простір за допомогою змінної innodbсистемнийнастільний простірencrypt або використовуючи потоки шифрування (encryption threads), але це досі експериментальна функція. У MySQL цього немає.
Перед тим, як рухатися далі, нам потрібно розглянути структуру ідентифікатора головного ключа (master key ID). Він складається з UUID, KEYID та префікса «INNODBKey». Виглядає так: INNODBKey-UUID-KEYID.
UUID — це uuid сервер із зашифрованим табличним простором. KEYID — це значення, що постійно постійно збільшується. При первинному створенні головного ключа KEYID дорівнює 1. При ротації ключа, коли створюється новий головний ключ, KEYID = 2 і таке інше. Докладніше про ротацію головних ключів ми поговоримо у наступних статтях цієї серії.
Тепер, коли ми знаємо, як виглядає ідентифікатор головного ключа, погляньмо на заголовок зашифрованого табличного простору. Коли табличний простір шифрується, інформація про шифрування додається до заголовка. Виглядає це так:

KEY ID – це KEYID з ідентифікатора ключового ключа, який ми вже обговорювали. UUID – це uuid сервер, який також використовується в ідентифікаторі головного ключа. TABLESPACE KEY - ключ табличного простору, який складається з 256 біт, випадково згенерованих сервером. Вектор ініціалізації (IV, initialization vector) також складається з 256 випадково згенерованих бітів (хоча має бути 128 біт). IV використовується для ініціалізації шифрування та дешифрування AES (з 256 біт використовується лише 128). Наприкінці є контрольна сума CRC32 для TABLESPACE KEY і IV.
Весь цей час я трохи спрощував, говорячи, що в заголовку є зашифрований ключ табличного простору. Насправді, ключ табличного простору та вектор ініціалізації зберігаються та шифруються разом за допомогою головного ключа. Пам'ятайте, що перед шифруванням ключа табличного простору та вектора ініціалізації для них обчислюється CRC32.
Навіщо потрібний CRC32?
Якщо двома словами, то для того щоб переконатися у валідності головного ключа. Після розшифрування ключа табличного простору та вектора ініціалізації, обчислюється контрольна сума і порівнюється з CRC32, що зберігається в заголовку. Якщо контрольні суми збігаються, то ми маємо правильний головний ключ і ключ табличного простору. В іншому випадку табличний простір позначається як відсутній (ми все одно не зможемо його розшифрувати).
Ви можете спитати: в який момент здійснюється перевірка ключів? Відповідь — під час запуску сервера. Сервер із зашифрованими таблицями / табличними просторами при старті зчитує UUID, KEYID із заголовка та генерує ідентифікатор головного ключа. Потім він отримує необхідний головний ключ із сховища (keyring), розшифровує ключ табличного простору та перевіряє контрольну суму. Ще раз, якщо контрольна сума збігається, то все гаразд, ні — табличний простір позначається як відсутній.
Якщо ви читали минулу статтю цієї серії (), можливо, пам'ятайте, що при використанні серверного сховища ключів, сервер при запуску отримує тільки список ідентифікаторів ключів, а точніше, key id і user id, так як ця пара однозначно ідентифікує ключ. А тепер я кажу, що сервер при запуску отримує всі ключі, необхідні для перевірки можливості розшифровки ключів табличних просторів. Так чому при ініціалізації, у разі серверного сховища, завантажуються тільки keyid та userid, а чи не всі ключі? Тому що вам можуть бути не потрібні всі ключі. Здебільшого це пов'язано із ротацією головного ключа. При ротації головного ключа у сховищі створюється новий головний ключ, але старі ключі не видаляються. Таким чином, у серверному сховищі ключів у вас може бути багато ключів, які не потрібні серверу і, отже, не виймаються при запуску сервера.
Настав час трохи поговорити про переваги та недоліки шифрування з використанням головного ключа. Найбільшою перевагою є те, що вам потрібен лише один ключ шифрування (головний ключ), який зберігатиметься окремо від ваших зашифрованих даних. Це робить запуск сервера швидким, а сховище невеликим, що полегшує керування. І також єдиний головний ключ легко перегенерувати.
Однак шифрування за допомогою головного ключа має один великий недолік: після того, як табличний простір зашифровано за допомогою tablespace_key, воно завжди залишається зашифрованим одним і тим же ключем. Ротація головного ключа тут не допомагає. Чому це недолік? Ми знаємо, що в MySQL є баги, які можуть призвести до раптового збою та створення core-файлу. Так як core-файл містить дамп пам'яті сервера, може статися так, що в дампі буде розшифрований ключ табличного простору. Що ще гірше, дешифровані ключі табличного простору зберігаються у пам'яті, яка може звільнитися на диск. Ви можете сказати, що це не недолік, тому що вам потрібні root-права для доступу до цих файлів та розділу підкачки. Так. Але root потрібен лише на деякий час. Як тільки хтось отримає доступ до дешифрованого ключа табличного простору, він зможе продовжити використовувати його для розшифровки даних, навіть без прав root. Крім того, диск може бути вкрадений, а розділ підкачування/core-файли можна прочитати за допомогою сторонніх засобів. Мета TDE полягає в тому, щоб зробити його нечитаним, навіть якщо диск буде вкрадено. У є можливість повторного шифрування табличного простору з новими ключами, що згенерували. Ця функція називається потоками шифрування (encryption threads) і на момент написання цієї статті все ще є експериментальною.
Читати ще:
Джерело: habr.com
