mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-03 05:48:11 +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` пустого массива, общая информация не будет выводиться.
|
||||
Для определения собственного алгоритма подключения общей информации, следует переопределить метод [[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>
|
||||
|
||||
|
||||
@ -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"
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ use Yii;
|
||||
use yii\base\Component;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\helpers\ArrayHelper;
|
||||
use yii\helpers\StringHelper;
|
||||
use yii\helpers\VarDumper;
|
||||
use yii\web\Request;
|
||||
|
||||
@ -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 = [
|
||||
@ -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.
|
||||
* The default implementation will dump user information, system variables, etc.
|
||||
@ -169,9 +223,12 @@ abstract class Target extends Component
|
||||
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, '***');
|
||||
}
|
||||
}
|
||||
}
|
||||
$result = [];
|
||||
@ -292,7 +349,7 @@ abstract class Target extends Component
|
||||
*/
|
||||
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
|
||||
|
||||
@ -345,6 +345,45 @@ class TargetTest extends TestCase
|
||||
$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
|
||||
|
||||
Reference in New Issue
Block a user