Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wildcards in yii\log\Target::$maskVars array #20297

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)

2.0.51 July 18, 2024
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 @@
* - `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 @@
}
}

/**
* 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
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure this method should be here.

Copy link
Member

Choose a reason for hiding this comment

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

Looks like a good candidate for array helper.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can I leave as is for now and then handle it in a separate PR? (dedicated to new ArrayHelper::flatten() method)

Copy link
Member

Choose a reason for hiding this comment

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

Yes.

{
$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 @@
protected function getContextMessage()
{
$context = ArrayHelper::filter($GLOBALS, $this->logVars);
$items = self::flatten($context);
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, '***');

Check warning on line 230 in framework/log/Target.php

View check run for this annotation

Codecov / codecov/patch

framework/log/Target.php#L230

Added line #L230 was not covered by tests
}
}
}
$result = [];
Expand Down Expand Up @@ -292,7 +349,7 @@
*/
public function formatMessage($message)
{
list($text, $level, $category, $timestamp) = $message;
[$text, $level, $category, $timestamp] = $message;

Check warning on line 352 in framework/log/Target.php

View check run for this annotation

Codecov / codecov/patch

framework/log/Target.php#L352

Added line #L352 was not covered by tests
$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
Loading