Маскування даних
Ядро приховує чутливі значення перед записом у логи, debug-панелі та інші місця, де дані
можуть потрапити до сторонніх очей. DataMasker рекурсивно обробляє масиви,
об’єкти та рядки за правилами ключів і regex.
Реєстрація: DataMaskerServiceProvider у
провайдерах HTTP (перед
LogServiceProvider, щоб логер отримав маскер).
Правила за замовчуванням — у config/masking.php
(див. конфігурація, Конфігурація → masking.php).
Архітектура
| Клас | Роль |
|---|---|
DataMaskerInterface | Контракт: mask(), clearRules() |
DataMasker | Оркестратор правил, рекурсія по структурах |
RegexDataMaskerRule | Regex для рядків і шаблонів ключів (з config/masking.php) |
DataMaskerRuleInterface | Власне правило (apply, isSensitiveKey) |
За замовчуванням DataMaskerServiceProvider створює DataMasker з одним
правилом RegexDataMaskerRule з патернами з конфігурації. Сервіс — shared singleton.
config/masking.php
У skeleton файл config/masking.php задає три групи налаштувань.
DataMaskerServiceProvider читає їх через ConfigInterface
(ConfigKey::MASKING_PATTERNS, MASKING_KEY_PATTERNS, MASKING_RULES)
і будує один RegexDataMaskerRule плюс додаткові класи з masking.rules:
<?php declare(strict_types=1);
return [
'masking' => [
// Regex для рядків (лог-повідомлення, scalar values)
'patterns' => [
'/[a-z0-9_\-\+\.]+@[a-z0-9\-]+\.[a-z]{2,}/i' => '***@***.***',
'/\d{4}-\d{4}-\d{4}-\d{4}/' => '****-****-****-****',
'/(password|token|api_key|...)[:=]+([^\s,;]+)/i' => '$1=*****',
],
// Regex для імен ключів у масивах/об'єктах → значення стає ***
'key_patterns' => [
'/.*password.*/i',
'/.*token.*/i',
'/.*_csrf_token.*/i',
'/api_key/i',
],
// Класи DataMaskerRuleInterface — резолвяться з DI
'rules' => [
// MyCustomMaskerRule::class,
],
],
];
patterns—RegexDataMaskerRule::apply()для рядків (email, карти,password=…у тексті)key_patterns—isSensitiveKey(): збіг імені ключа →DataMasker::MASK_CHARS(***)rules— додаткові правила; клас має реалізуватиDataMaskerRuleInterface
Зміни в masking.php не потребують правок PHP — достатньо перезапуску запиту.
Правила за замовчуванням (skeleton)
Те, що дає stock config/masking.php у Concept Skeleton:
Ключі (key_patterns) — значення поля замінюється на ***:
- імена з
password,token,_csrf_token,secret api_key,authorization
Рядки (patterns) — regex-заміна в тексті:
- email →
***@***.*** - номер картки
9999-9999-9999-9999→ зірочки - пари на кшталт
password=...,token=...,api_key=...→ значення замінюється на*****
Інтеграція з логером
LogServiceProvider передає DataMaskerInterface у
Concept\Core\Services\Logger\Logger. Monolog-процесор маскує
$record->context перед записом у файл або stderr.
$logger->info('User updated', [
'email' => 'user@example.com',
'password' => 'secret123', // у лог потрапить ***
]);
Повідомлення ($message) не маскується автоматично — не вставляйте паролі та токени
у текст повідомлення, лише в context.
Ручне використання
use Concept\Core\Services\DataMasker\Contracts\DataMaskerInterface;
/** @var DataMaskerInterface $masker */
$masker = $container->get(DataMaskerInterface::class);
$safe = $masker->mask([
'login' => 'oleh',
'password' => 'hunter2',
'card' => '4111-1111-1111-1111',
]);
Метод mask() для масивів і об’єктів спочатку робить deepClone, щоб
не змінювати оригінал. maskRecursive() змінює передану структуру на місці — корисно,
коли клонування зайве.
Власні правила
Переважно достатньо розширити config/masking.php (див. вище).
Якщо потрібен повний контроль — у власному провайдері (після DataMaskerServiceProvider)
можна перевизначити binding:
use Concept\Core\Services\DataMasker\Contracts\DataMaskerInterface;
use Concept\Core\Services\DataMasker\DataMasker;
use Concept\Core\Services\DataMasker\RegexDataMaskerRule;
$masker = new DataMasker();
$masker->addRule(new RegexDataMaskerRule(
patterns: ['/iban=\d+/i' => 'iban=***'],
keyPatterns: ['/.*_pin$/i']
));
$container->add(DataMaskerInterface::class, fn () => $masker)->setShared(true);
Або додайте клас у masking.rules у конфігурації — провайдер підключить його через DI.
Для складнішої логіки реалізуйте DataMaskerRuleInterface.
DebugBar та інші компоненти
Компонент DebugBar інжектує DataMaskerInterface у колектор запиту — у панелі
$_POST, $_SESSION тощо показуються вже замасковані значення.
Будь-який власний інструмент діагностики варто будувати так само.
Маскування не замінює шифрування в БД і не прибирає чутливі поля з HTTP-відповідей. Воно знижує ризик витоку через логи та dev-інструменти.