#[SensitiveParameter] の挙動の確認
SensitiveParameter アトリビュートとはなにか
関数やメソッドのパラメータに #[SensitiveParameter]
アトリビュートを付与することで、そのパラメータの値をスタックトレースから隠蔽することができる機能です。
例えば、PDO のコンストラクタでは$password
を受け取っていますが、コンストラクタを呼び出した時に行われるデータベースへの接続で失敗すると、スタックトレースにデータベースのパスワードが出力されてしまいます。
これらの課題を解決するために、 #[\SensitiveParameter]
アトリビュートは PHP 8.2 から導入されました。
挙動の確認
こちらのコミットのテストを読んでいきます。
スタックトレースの出力は隠蔽される
debug_print_backtrace
やdebug_backtrace
、Exception::getTrace
などのスタックトレース中では値が隠蔽される。
--FILE--
<?php
function test(#[SensitiveParameter] $sensitive)
{
debug_print_backtrace();
}
test('sensitive');
?>
--EXPECTF--
#0 %ssensitive_parameter.php(10): test(Object(SensitiveParameterValue))
スタックトレースではない出力は隠蔽されない
var_dump
やprint_r
などのスタックトレースではない出力では値は隠蔽されない。
--FILE--
<?php
function test(#[SensitiveParameter] $sensitive)
{
var_dump($sensitive);
}
test('sensitive');
?>
--EXPECTF--
string(8) "sensitive"
可変長引数にも対応している
...$args
のような可変長引数の場合でも#[SensitiveParameter]
は全てにつきます。
--FILE--
<?php
function test(
#[SensitiveParameter] ...$args
) {
debug_print_backtrace();
}
test('foo', 'bar', 'baz');
?>
--EXPECTF--
#0 %ssensitive_parameter_variadic_arguments.php(12): test(Object(SensitiveParameterValue), Object(SensitiveParameterValue), Object(SensitiveParameterValue))
#[SensitiveParameter]
はその関数内でしか有効ではない
呼び出し元のメソッドは#[SensitiveParameter]
を付与していても、呼び出し先のメソッドは付与していない場合、呼び出し先のメソッドでは値は隠蔽されない。
その逆も同様。
--FILE--
<?php
function test(#[SensitiveParameter] $sensitive)
{
test2($sensitive);
}
function test2($sensitive)
{
debug_print_backtrace();
}
test('sensitive');
?>
--EXPECTF--
#0 %ssensitive_parameter.php(13): test2('sensitive')
#1 %ssensitive_parameter.php(21): test(Object(SensitiveParameterValue))
--FILE--
<?php
function test($sensitive)
{
test2($sensitive);
}
function test2(#[SensitiveParameter] $sensitive)
{
debug_print_backtrace();
}
test('sensitive');
?>
--EXPECTF--
#0 %ssensitive_parameter.php(13): test2(Object(SensitiveParameterValue))
#1 %ssensitive_parameter.php(21): test('sensitive')
#[SensitiveParameter]
は有効
配列やオブジェクトでも引数に配列やオブジェクトを渡した場合、debug_print_backtrace
ではArray
やObject
と表示される。
しかし、debug_backtrace
のargs
を表示すると隠蔽したい値も表示されてしまう。
--FILE--
readonly class Password
{
public function __construct(
#[SensitiveParameter] public string $sensitive,
) {}
}
function test($sensitive)
{
debug_print_backtrace();
var_dump(debug_backtrace()[0]['args'][0]);
}
test(['password' => 'sensitive']);
test(new Password('sensitive'));
?>
--EXPECTF--
#0 %ssensitive_parameter.php(24): test(Array)
array(1) {
["password"]=>
string(9) "sensitive"
}
#0 %ssensitive_parameter.php(25): test(Object(Password))
object(Password)#2 (1) {
["sensitive"]=>
string(9) "sensitive"
}
ちゃんと#[SensitiveParameter]
を付けることで、debug_backtrace
のargs
でも隠蔽される。
--FILE--
readonly class Password
{
public function __construct(
#[SensitiveParameter] public string $sensitive,
) {}
}
function test(#[SensitiveParameter] $sensitive)
{
debug_print_backtrace();
var_dump(debug_backtrace()[0]['args'][0]);
}
test(['password' => 'sensitive']);
test(new Password('sensitive'));
?>
--EXPECTF--
#0 %ssensitive_parameter.php(24): test(Array)
object(SensitiveParameterValue)#2 (0) {
}
#0 %ssensitive_parameter.php(25): test(Object(Password))
object(SensitiveParameterValue)#2 (0) {
}
使われどころ
接続情報の隠蔽
PDOなど、データベース接続時のクレデンシャル情報を隠蔽する。
public PDO::__construct(
string $dsn,
?string $username = null,
#[\SensitiveParameter] ?string $password = null,
?array $options = null
)
セキュリティ関連のライブラリの平文の値を隠蔽
OpenSSLやSodiumなどのセキュリティ関連のライブラリで、平文の値を隠蔽する。
openssl_encrypt(
#[\SensitiveParameter] string $data,
string $cipher_algo,
#[\SensitiveParameter] string $passphrase,
int $options = 0,
string $iv = "",
string &$tag = null,
string $aad = "",
int $tag_length = 16
): string|false
hash_equals(#[\SensitiveParameter] string $known_string, #[\SensitiveParameter] string $user_string): bool
トークンなど認証情報の隠蔽
SymfonyやLaravelなどのフレームワークで、トークン等の認証情報を隠蔽する。
public function validate(#[\SensitiveParameter] array $credentials = [])
{
return ! is_null((new static(
$this->callback, $credentials['request'], $this->getProvider()
))->user());
}
おわり
PHP 8.2 から追加された #[\SensitiveParameter]
アトリビュートは、スタックトレースに出力される値を隠蔽することが出来ます。
機密情報を扱う関数やメソッドでは可能な限り #[\SensitiveParameter]
を付与することがオススメです。
また、PHP標準のExtensionや、ライブラリ・フレームワークなどで、#[SensitiveParameter]
が使われている関数を使用する際は、呼び出し元となるメソッドにも#[SensitiveParameter]
を付与するようにしましょう。
Discussion