first commit

This commit is contained in:
brusnitsyn
2026-06-24 17:20:43 +09:00
commit 43499acf1c
165 changed files with 25929 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
<?php
namespace App\Services\Pdn;
use RuntimeException;
/**
* Псевдонимизация и маскирование персональных данных.
*
* Мера ФСТЭК / 152-ФЗ ст. 3 п.9: псевдонимизация для аналитики и логов,
* чтобы исключить прямые идентификаторы (раздел 5.3 гайда).
*/
class PdnAnonymizer
{
/**
* Детерминированный псевдоним субъекта (HMAC-SHA256).
* Один и тот же вход даёт один и тот же псевдоним пригодно для join'ов
* в аналитике без раскрытия исходного идентификатора.
*/
public function pseudonym(string $value): string
{
$key = (string) config('security.encryption.pseudonym_key');
if ($key === '') {
throw new RuntimeException(
'Не задан SECURITY_PSEUDONYM_KEY для псевдонимизации ПДн.'
);
}
return hash_hmac('sha256', $value, $this->normalizeKey($key));
}
/**
* Маскирование значения для отображения (например в журналах/UI оператора).
*
* Пример: "Иванов" -> "И****", "ivan@mail.ru" -> "iv***@mail.ru".
*/
public function mask(string $value, int $visible = 2): string
{
if (str_contains($value, '@')) {
[$local, $domain] = explode('@', $value, 2);
return $this->mask($local, $visible).'@'.$domain;
}
$length = mb_strlen($value);
if ($length <= $visible) {
return str_repeat('*', max($length, 1));
}
return mb_substr($value, 0, $visible).str_repeat('*', $length - $visible);
}
private function normalizeKey(string $key): string
{
if (str_starts_with($key, 'base64:')) {
return (string) base64_decode(substr($key, 7), true);
}
return $key;
}
}