Впровадження шифрування персональних даних на сайті
Шифрування персональних даних (ПДн) у базі даних - обов'язковий елемент захисту при обробці чутливої інформації. Навіть при компрометації БД зловмисник отримує зашифровані дані, непридатні без ключів.
Що та як шифрувати
Дані, які вимагають шифрування:
- ІНН, СНІЛС, серія/номер паспорта
- Медичні дані, діагнози
- Фінансові дані, номери карт
- Біометрія
Дані, які треба лише хешувати (необоротньо):
- Паролі → bcrypt, Argon2id
- Секретні токени, API-ключі
Дані, які потребують пошуку:
- Вимагають детерміністичного шифрування або токенізації
Алгоритми шифрування
AES-256-GCM — симетричне шифрування з аутентифікацією. Стандарт для шифрування даних у спокої.
RSA-OAEP — асиметричне. Використовується для шифрування симетричних ключів.
ChaCha20-Poly1305 — альтернатива AES на платформах без апаратного прискорення AES.
Шифрування на рівні додатку (Laravel)
class EncryptedCast implements CastsAttributes
{
public function get($model, string $key, $value, array $attributes): ?string
{
if (is_null($value)) return null;
try {
return Crypt::decryptString($value);
} catch (DecryptException) {
return null;
}
}
public function set($model, string $key, $value, array $attributes): ?string
{
if (is_null($value)) return null;
return Crypt::encryptString($value);
}
}
class Patient extends Model
{
protected $casts = [
'passport_number' => EncryptedCast::class,
'medical_notes' => EncryptedCast::class,
'snils' => EncryptedCast::class,
];
}
$patient->passport_number = '4510 123456';
$decrypted = $patient->passport_number;
Управління ключами
HashiCorp Vault:
$vault = new Vault([
'address' => 'https://vault.internal:8200',
'token' => env('VAULT_TOKEN'),
]);
$keyData = $vault->read('secret/data/app-encryption-key');
$encryptionKey = $keyData['data']['key'];
AWS KMS:
$kms = new KmsClient(['region' => 'eu-west-1']);
$result = $kms->encrypt([
'KeyId' => 'arn:aws:kms:eu-west-1:123456:key/abc-123',
'Plaintext' => $sensitiveData,
]);
$encryptedData = base64_encode($result['CiphertextBlob']);
Envelope Encryption — найкраща практика: дані шифруються Data Encryption Key (DEK), DEK шифруються Key Encryption Key (KEK), KEK зберігається в KMS/Vault.
Детерміністичне шифрування для пошуку
Звичайний AES-GCM генерує різний шифртекст для одного значення. Пошук по зашифрованому полю неможливий. Рішення:
Варіант 1: Хеш для пошуку + шифрування для зберігання:
class PersonalDataRepository
{
public function findByPassport(string $passport): ?Patient
{
$hash = hash_hmac('sha256', $passport, config('app.search_key'));
return Patient::where('passport_hash', $hash)->first();
}
public function store(string $passport): void
{
Patient::create([
'passport_data' => Crypt::encryptString($passport),
'passport_hash' => hash_hmac('sha256', $passport, config('app.search_key')),
]);
}
}
Варіант 2: PostgreSQL pgcrypto:
INSERT INTO patients (passport)
VALUES (pgp_sym_encrypt('4510 123456', current_setting('app.encryption_key')));
SELECT pgp_sym_decrypt(passport::bytea, current_setting('app.encryption_key'))
FROM patients WHERE id = 1;
Ротація ключів
class RotateEncryptionKeyCommand extends Command
{
public function handle(): void
{
$oldKey = config('app.old_encryption_key');
$newKey = config('app.key');
Patient::chunk(100, function ($patients) use ($oldKey, $newKey) {
foreach ($patients as $patient) {
$decrypted = Crypt::decryptString($patient->getRawOriginal('passport_number'));
$patient->updateQuietly([
'passport_number' => Crypt::encryptString($decrypted),
]);
}
});
}
}
Шифрування файлів
class EncryptedFileStorage
{
public function store(UploadedFile $file): string
{
$content = file_get_contents($file->getPathname());
$encrypted = Crypt::encrypt($content);
$path = 'encrypted/' . Str::uuid() . '.enc';
Storage::put($path, $encrypted);
return $path;
}
public function retrieve(string $path): string
{
$encrypted = Storage::get($path);
return Crypt::decrypt($encrypted);
}
}
Тривалість реалізації
- Шифрування на рівні моделі (Cast) для основних полів: 2–3 дні
- Інтеграція Vault/KMS + envelope encryption: 5–7 днів
- Детерміністичне шифрування + пошук: +3 дні
- Ротація ключів + аудит доступу: +2–3 дні







