Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як шифрувати чутливі поля в базі через cast encrypted і які в цього обмеження?

Для полів, витік яких особливо шкідливий (токени сторонніх API, секрети 2FA, номери документів, медичні нотатки), Laravel має касти, що шифрують значення на рівні застосунку:

protected function casts(): array
{
    return [
        'two_factor_secret' => 'encrypted',
        'api_credentials' => 'encrypted:array',
        'medical_notes' => 'encrypted',
        'settings' => AsEncryptedArrayObject::class,
    ];
}

У базі зберігається зашифрований рядок (AES-256 з APP_KEY і MAC для перевірки цілісності). Модель автоматично шифрує при записі й розшифровує при читанні.

Від чого це захищає:

  • дамп чи бекап бази потрапив не в ті руки;
  • доступ до бази без доступу до застосунку (SQL-ін'єкція, що читає таблиці, скомпрометований обліковий запис адміністратора бази, репліка для аналітики);
  • логи запитів до бази містять лише шифротекст.

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

Обмеження, про які треба знати:

  • не можна шукати й сортувати: where('passport_number', $value) не знайде запис - кожне шифрування дає різний шифротекст (випадковий IV). Якщо пошук потрібен - окрема колонка з «сліпим індексом»: HMAC від значення з окремим ключем, і пошук за ним;
  • не можна індексувати, агрегувати, використовувати в unique-обмеженнях бази;
  • розмір колонки: шифротекст (base64 з IV і MAC) значно довший за значення - колонка text, а не varchar(50);
  • ротація APP_KEY вимагає перешифрування всіх таких полів; без старого ключа в APP_PREVIOUS_KEYS дані втрачено;
  • продуктивність: розшифрування при кожному читанні - помітно на великих вибірках.

Окремий ключ для шифрування даних: можна вказати власний шифрувальник для моделей (Model::encryptUsing($encrypter)), щоб ключ даних був окремо від APP_KEY і ротувався незалежно.

Не шифрувати те, що має бути хешованим: паролі й одноразові токени - хеш (їх не потрібно розшифровувати), а шифрування - для даних, які застосунку треба прочитати у відкритому вигляді.

Докладніше в документації: Laravel: шифровані касти

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання