Skip to content

Commit

Permalink
Fix #20295: Add an ability to have wildcards in `yii\log\Target::$mas…
Browse files Browse the repository at this point in the history
…kVars` array
  • Loading branch information
xcopy authored Jan 1, 2025
1 parent a8586fc commit 3fc7e71
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 6 deletions.
17 changes: 17 additions & 0 deletions docs/guide-ru/runtime-logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,23 @@ return [
При задании значением свойства `logVars` пустого массива, общая информация не будет выводиться.
Для определения собственного алгоритма подключения общей информации, следует переопределить метод [[yii\log\Target::getContextMessage()]].

Если некоторые из полей вашего запроса содержат конфиденциальную информацию, которую вы не хотели бы логировать (например, пароли, токены доступа),
вы можете дополнительно настроить свойство `maskVars`, которое может содержать как точные значения, так и шаблоны (без учета регистра).
По умолчанию следующие параметры запроса будут замаскированы с помощью `***`:
`$_SERVER[HTTP_AUTHORIZATION]`, `$_SERVER[PHP_AUTH_USER]`, `$_SERVER[PHP_AUTH_PW]`, но вы можете задать свои собственные. Например:

```php
[
'class' => 'yii\log\FileTarget',
'logVars' => ['_SERVER'],
'maskVars' => [
'_SERVER.HTTP_X_PASSWORD',
'_SERVER.*_SECRET', // соответствует всем, заканчивающимся на "_SECRET"
'_SERVER.SECRET_*', // соответствует всем, начинающимся с "SECRET_"
'_SERVER.*SECRET*', // соответствует всем содержащим "SECRET"
]
]
```

### Уровень отслеживания выполнения кода <span id="trace-level"></span>

Expand Down
12 changes: 9 additions & 3 deletions docs/guide/runtime-logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,14 +217,20 @@ Or if you want to implement your own way of providing context information, you m
[[yii\log\Target::getContextMessage()]] method.

In case some of your request fields contain sensitive information you would not like to log (e.g. passwords, access tokens),
you may additionally configure `maskVars` property. By default, the following request parameters will be masked with `***`:
`$_SERVER[HTTP_AUTHORIZATION]`, `$_SERVER[PHP_AUTH_USER]`, `$_SERVER[PHP_AUTH_PW]`, but you can set your own:
you may additionally configure `maskVars` property, which can contain both exact values and (case-insensitive) patterns. By default,
the following request parameters will be masked with `***`:
`$_SERVER[HTTP_AUTHORIZATION]`, `$_SERVER[PHP_AUTH_USER]`, `$_SERVER[PHP_AUTH_PW]`, but you can set your own. For example:

```php
[
'class' => 'yii\log\FileTarget',
'logVars' => ['_SERVER'],
'maskVars' => ['_SERVER.HTTP_X_PASSWORD']
'maskVars' => [
'_SERVER.HTTP_X_PASSWORD',
'_SERVER.*_SECRET', // matches all ending with "_SECRET"
'_SERVER.SECRET_*', // matches all starting with "SECRET_"
'_SERVER.*SECRET*', // matches all containing "SECRET"
]
]
```

Expand Down
1 change: 1 addition & 0 deletions framework/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Yii Framework 2 Change Log
- Bug #20140: Fix compatibility with PHP 8.4: calling `session_set_save_handler()` (Izumi-kun)
- New #20185: Add `BackedEnum` support to `AttributeTypecastBehavior` (briedis)
- Bug #17365: Fix "Trying to access array offset on null" warning (xcopy)
- Enh #20295: Add an ability to have wildcards in `yii\log\Target::$maskVars` array (xcopy)
- Bug #20296: Fix broken enum test (briedis)
- Bug #20300: Clear stat cache in `FileCache::setValue()` (rob006)

Expand Down
63 changes: 60 additions & 3 deletions framework/log/Target.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use yii\base\Component;
use yii\base\InvalidConfigException;
use yii\helpers\ArrayHelper;
use yii\helpers\StringHelper;
use yii\helpers\VarDumper;
use yii\web\Request;

Expand Down Expand Up @@ -91,6 +92,11 @@ abstract class Target extends Component
* - `var` - `var` will be logged as `***`
* - `var.key` - only `var[key]` will be logged as `***`
*
* In addition, this property accepts (case-insensitive) patterns. For example:
* - `_SERVER.*_SECRET` matches all ending with `_SECRET`, such as `$_SERVER['TOKEN_SECRET']` etc.
* - `_SERVER.SECRET_*` matches all starting with `SECRET_`, such as `$_SERVER['SECRET_TOKEN']` etc.
* - `_SERVER.*SECRET*` matches all containing `SECRET` i.e. both of the above.
*
* @since 2.0.16
*/
public $maskVars = [
Expand Down Expand Up @@ -161,6 +167,54 @@ public function collect($messages, $final)
}
}

/**
* Flattens a multidimensional array into a one-dimensional array.
*
* This method recursively traverses the input array and concatenates the keys
* to form a new key in the resulting array.
*
* Example:
*
* ```php
* $array = [
* 'A' => [1, 2],
* 'B' => [
* 'C' => 1,
* 'D' => 2,
* ],
* 'E' => 1,
* ];
* $result = \yii\log\Target::flatten($array);
* // result will be:
* // [
* // 'A.0' => 1
* // 'A.1' => 2
* // 'B.C' => 1
* // 'B.D' => 2
* // 'E' => 1
* // ]
* ```
*
* @param array $array the input array to be flattened.
* @param string $prefix the prefix to be added to each key in the resulting array.
*
* @return array the flattened array.
*/
private static function flatten($array, $prefix = ''): array
{
$result = [];

foreach ($array as $key => $value) {
if (is_array($value)) {
$result = array_merge($result, self::flatten($value, $prefix . $key . '.'));
} else {
$result[$prefix . $key] = $value;
}
}

return $result;
}

/**
* Generates the context information to be logged.
* The default implementation will dump user information, system variables, etc.
Expand All @@ -169,9 +223,12 @@ public function collect($messages, $final)
protected function getContextMessage()
{
$context = ArrayHelper::filter($GLOBALS, $this->logVars);
$items = self::flatten($context);

This comment has been minimized.

Copy link
@lubosdz

lubosdz Jan 1, 2025

Contributor

ArrayHelper::flatten() ?

foreach ($this->maskVars as $var) {
if (ArrayHelper::getValue($context, $var) !== null) {
ArrayHelper::setValue($context, $var, '***');
foreach ($items as $key => $value) {
if (StringHelper::matchWildcard($var, $key, ['caseSensitive' => false])) {
ArrayHelper::setValue($context, $key, '***');
}
}
}
$result = [];
Expand Down Expand Up @@ -292,7 +349,7 @@ public static function filterMessages($messages, $levels = 0, $categories = [],
*/
public function formatMessage($message)
{
list($text, $level, $category, $timestamp) = $message;
[$text, $level, $category, $timestamp] = $message;
$level = Logger::getLevelName($level);
if (!is_string($text)) {
// exceptions may not be serializable if in the call stack somewhere is a Closure
Expand Down
39 changes: 39 additions & 0 deletions tests/framework/log/TargetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,45 @@ public function testFlushingWithProfilingEnabledAndOverflow()
$logger->log('token.b', Logger::LEVEL_PROFILE_END, 'category');
$logger->log('token.a', Logger::LEVEL_PROFILE_END, 'category');
}

public function testWildcardsInMaskVars()
{
$keys = [
'PASSWORD',
'password',
'password_repeat',
'repeat_password',
'repeat_password_again',
'1password',
'password1',
];

$password = '!P@$$w0rd#';

$items = array_fill_keys($keys, $password);

$GLOBALS['_TEST'] = array_merge(
$items,
['a' => $items],
['b' => ['c' => $items]],
['d' => ['e' => ['f' => $items]]],
);

$target = new TestTarget([
'logVars' => ['_SERVER', '_TEST'],
'maskVars' => [
// option 1: exact value(s)
'_SERVER.DOCUMENT_ROOT',
// option 2: pattern(s)
'_TEST.*password*',
]
]);

$message = $target->getContextMessage();

$this->assertStringContainsString("'DOCUMENT_ROOT' => '***'", $message);
$this->assertStringNotContainsString($password, $message);
}
}

class TestTarget extends Target
Expand Down

2 comments on commit 3fc7e71

@lubosdz
Copy link
Contributor

@lubosdz lubosdz commented on 3fc7e71 Jan 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it not be better to move flatten() into ArrayHelper::flatten() ?

@samdark
Copy link
Member

@samdark samdark commented on 3fc7e71 Jan 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely. In the issue itself @xcopy asked to do it separately and that's OK.

Please sign in to comment.