如何在 PHP 的 debug_backtrace 中仅隐藏敏感参数?

问题描述 投票:0回答:3

这个问题是在 2021 年 6 月提出的,早在 PHP 8.2 发布之前(2022 年 12 月)。对于 PHP 8.2+,请参阅 Joshanswer。对于 PHP <8.2, no answer solves the question (包括我自己的)。我在答案中发布的代码最接近符合我需求的解决方案。

考虑以下代码。如果发生异常,跟踪(将被记录并存储在数据库中)将包括敏感的

password
数据。在这种情况下,如何隐藏敏感数据,同时允许其他非敏感参数?

<?php
$user = 'john';
$pass = 'secret';

function auth($user, $pass) {
    // authentication logic
}

function login($user, $pass) {
    throw new Exception('Unexpected error');

    // various logic
    auth($user, $pass);
    // various logic
}

try {
    login($user, $pass);
} catch (Throwable $e) {
    send_to_log($e->getTrace()); // This reveals the password "secret"
}
php security logging php-7 credentials
3个回答
14
投票

从 PHP 版本 8.2(2022 年 12 月)开始,有一个名为“编辑回溯中的参数”的功能。这将从 PHP 应用程序中的任何堆栈跟踪中隐藏该参数。

这是来自 RFC 的示例:

<?php
 
function test(
    $foo,
    #[\SensitiveParameter] $bar,
    $baz
) {
    throw new \Exception('Error');
}
 
test('foo', 'bar', 'baz');
 
/*
Fatal error: Uncaught Exception: Error in test.php:8
Stack trace:
#0 test.php(11): test('foo', Object(SensitiveParameterValue), 'baz')
#1 {main}
  thrown in test.php on line 8
*/

5
投票

免责声明:我(有点)假设您从未真正将

var_dump
的结果通过管道返回给您的用户。很明显(再一次),最终用户很少关心引擎的内部结构,因此向他们显示跟踪路由几乎从来都不是处理服务器错误的好方法。但你是对的;由于各种原因,即使记录此信息实际上也可能不是一个好主意。

因此,回答最初的问题:好吧,您可以强制异常日志记录完全丢弃参数 - 或限制它们的长度:

请注意,PHP 7.4 引入了设置

zend.exception_ignore_args
, 这允许完全从异常中删除参数信息 (在
getTrace()
getTraceAsString()
等)。

设置

zend.exception_string_param_max_len=0
仍然提供比完全禁用跟踪参数更多的信息(您仍然知道参数是字符串,以及非字符串的类型)。

但这可能会使其他情况的调试变得复杂。 PHP 8.0 通过引入

zend.exception_string_param_max_len
config param:

在一定程度上缓解了这种情况

zend.exception_string_param_max_len 是一个新的 INI 指令,用于设置 字符串化堆栈跟踪的参数中的最大字符串长度。

其背后的想法(上面引用)除其他外,是在记录异常时限制可能暴露的敏感数据的数量,而不会实际损害调试问题所需的数据。

请注意,此设置仅影响

getTraceAsString()
结果(您应该考虑使用它而不是 getTrace 的 var_dumping 结果)。


0
投票

我最终在处理记录到文件/数据库的代码中添加了逻辑,以清除跟踪中显示的特定函数的参数:

<?php
function send_to_log(Throwable $e) {
    $noArgs = [
        'login' => true,
        'auth' => true,
        // ...
    ];

    $trace = $e->getTrace();
    foreach ($trace as &$err) {
        if (isset($noArgs[$err['function'] ?? ''])) {
            $cnt = count($err['args'] ?? []);
            if ($cnt > 0) {
                $err['args'] = array_fill(0, $cnt, 'REDACTED');
            }
        }
    }
    unset($err);

    var_dump($trace); /* This now shows "REDACTED" for all arguments
    to functions specified in the $noArgs array */

    // logging logic
}
© www.soinside.com 2019 - 2024. All rights reserved.