mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-11 19:20:01 +08:00
Fix #20295: Add an ability to have wildcards in yii\log\Target::$maskVars array
This commit is contained in:
@@ -173,6 +173,23 @@ return [
|
|||||||
При задании значением свойства `logVars` пустого массива, общая информация не будет выводиться.
|
При задании значением свойства `logVars` пустого массива, общая информация не будет выводиться.
|
||||||
Для определения собственного алгоритма подключения общей информации, следует переопределить метод [[yii\log\Target::getContextMessage()]].
|
Для определения собственного алгоритма подключения общей информации, следует переопределить метод [[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>
|
### Уровень отслеживания выполнения кода <span id="trace-level"></span>
|
||||||
|
|
||||||
|
|||||||
@@ -217,14 +217,20 @@ Or if you want to implement your own way of providing context information, you m
|
|||||||
[[yii\log\Target::getContextMessage()]] method.
|
[[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),
|
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 `***`:
|
you may additionally configure `maskVars` property, which can contain both exact values and (case-insensitive) patterns. By default,
|
||||||
`$_SERVER[HTTP_AUTHORIZATION]`, `$_SERVER[PHP_AUTH_USER]`, `$_SERVER[PHP_AUTH_PW]`, but you can set your own:
|
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
|
```php
|
||||||
[
|
[
|
||||||
'class' => 'yii\log\FileTarget',
|
'class' => 'yii\log\FileTarget',
|
||||||
'logVars' => ['_SERVER'],
|
'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"
|
||||||
|
]
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ Yii Framework 2 Change Log
|
|||||||
- Bug #20140: Fix compatibility with PHP 8.4: calling `session_set_save_handler()` (Izumi-kun)
|
- Bug #20140: Fix compatibility with PHP 8.4: calling `session_set_save_handler()` (Izumi-kun)
|
||||||
- New #20185: Add `BackedEnum` support to `AttributeTypecastBehavior` (briedis)
|
- New #20185: Add `BackedEnum` support to `AttributeTypecastBehavior` (briedis)
|
||||||
- Bug #17365: Fix "Trying to access array offset on null" warning (xcopy)
|
- 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 #20296: Fix broken enum test (briedis)
|
||||||
- Bug #20300: Clear stat cache in `FileCache::setValue()` (rob006)
|
- Bug #20300: Clear stat cache in `FileCache::setValue()` (rob006)
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use Yii;
|
|||||||
use yii\base\Component;
|
use yii\base\Component;
|
||||||
use yii\base\InvalidConfigException;
|
use yii\base\InvalidConfigException;
|
||||||
use yii\helpers\ArrayHelper;
|
use yii\helpers\ArrayHelper;
|
||||||
|
use yii\helpers\StringHelper;
|
||||||
use yii\helpers\VarDumper;
|
use yii\helpers\VarDumper;
|
||||||
use yii\web\Request;
|
use yii\web\Request;
|
||||||
|
|
||||||
@@ -91,6 +92,11 @@ abstract class Target extends Component
|
|||||||
* - `var` - `var` will be logged as `***`
|
* - `var` - `var` will be logged as `***`
|
||||||
* - `var.key` - only `var[key]` 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
|
* @since 2.0.16
|
||||||
*/
|
*/
|
||||||
public $maskVars = [
|
public $maskVars = [
|
||||||
@@ -161,6 +167,54 @@ abstract class Target extends Component
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
* Generates the context information to be logged.
|
||||||
* The default implementation will dump user information, system variables, etc.
|
* The default implementation will dump user information, system variables, etc.
|
||||||
@@ -169,9 +223,12 @@ abstract class Target extends Component
|
|||||||
protected function getContextMessage()
|
protected function getContextMessage()
|
||||||
{
|
{
|
||||||
$context = ArrayHelper::filter($GLOBALS, $this->logVars);
|
$context = ArrayHelper::filter($GLOBALS, $this->logVars);
|
||||||
|
$items = self::flatten($context);
|
||||||
foreach ($this->maskVars as $var) {
|
foreach ($this->maskVars as $var) {
|
||||||
if (ArrayHelper::getValue($context, $var) !== null) {
|
foreach ($items as $key => $value) {
|
||||||
ArrayHelper::setValue($context, $var, '***');
|
if (StringHelper::matchWildcard($var, $key, ['caseSensitive' => false])) {
|
||||||
|
ArrayHelper::setValue($context, $key, '***');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$result = [];
|
$result = [];
|
||||||
@@ -292,7 +349,7 @@ abstract class Target extends Component
|
|||||||
*/
|
*/
|
||||||
public function formatMessage($message)
|
public function formatMessage($message)
|
||||||
{
|
{
|
||||||
list($text, $level, $category, $timestamp) = $message;
|
[$text, $level, $category, $timestamp] = $message;
|
||||||
$level = Logger::getLevelName($level);
|
$level = Logger::getLevelName($level);
|
||||||
if (!is_string($text)) {
|
if (!is_string($text)) {
|
||||||
// exceptions may not be serializable if in the call stack somewhere is a Closure
|
// exceptions may not be serializable if in the call stack somewhere is a Closure
|
||||||
|
|||||||
@@ -345,6 +345,45 @@ class TargetTest extends TestCase
|
|||||||
$logger->log('token.b', Logger::LEVEL_PROFILE_END, 'category');
|
$logger->log('token.b', Logger::LEVEL_PROFILE_END, 'category');
|
||||||
$logger->log('token.a', 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
|
class TestTarget extends Target
|
||||||
|
|||||||
Reference in New Issue
Block a user