Шифрування в Laravel - симетричне, з ключем APP_KEY, алгоритм за замовчуванням AES-256-CBC з підписом HMAC (чи AES-GCM з вбудованою автентифікацією). Зашифроване значення не можна ні прочитати, ні непомітно змінити без ключа.
use Illuminate\Support\Facades\Crypt;
$token = Crypt::encryptString($apiToken);
$apiToken = Crypt::decryptString($token);
encryptString чи encrypt:
encryptString()/decryptString()- шифрує рядок як є;encrypt()/decrypt()(і хелпериencrypt(),decrypt()) спершу серіалізують значення черезserialize()- можна шифрувати масиви й об'єкти, але при розшифруванні викликаєтьсяunserialize(). Для рядків кращеencryptString.
Результат - base64 від JSON з полями iv, value, mac (чи tag для GCM). Він довший за вихідний рядок: для колонки бази потрібен text, а не короткий varchar.
Помилки розшифрування:
try {
$value = Crypt::decryptString($payload);
} catch (DecryptException $e) {
// значення пошкоджено, підроблено чи зашифровано іншим ключем
}
Ротація ключа. Якщо просто замінити APP_KEY, усе зашифроване старим ключем стане нечитабельним: cookie, сесії, поля з cast encrypted, збережені токени. Для плавної заміни:
APP_KEY="base64:NEW..."
APP_PREVIOUS_KEYS="base64:OLD..."
- шифрування - завжди новим ключем;
- розшифрування - спершу новим, потім по черзі старими з
APP_PREVIOUS_KEYS; - користувачі не розлогінюються, дані читаються.
Але старі ключі треба колись прибрати: дані в базі, зашифровані старим ключем, лишаються такими, доки їх не перезаписати. Після ротації - команда чи задача, що читає й зберігає ці записи заново (вони перешифровуються новим ключем), і лише потім видалення старого ключа з APP_PREVIOUS_KEYS.
Що не шифрувати через Crypt:
- паролі - їх хешують (
Hash::make), а не шифрують: розшифрувати пароль неможливо має бути навіть для вас; - поля, за якими шукаєте: зашифроване значення щоразу різне (випадковий IV), тому
where('email', ...)не спрацює. Для пошуку - окрема колонка з хешем (HMAC) значення.
Ключ - єдиний секрет усієї схеми. Витік APP_KEY разом з дампом бази - це витік усіх зашифрованих даних.