3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

String::Secretのご紹介

Posted at

Perl Advent Calenderなんと2024年になってもやってます。本当にめでたいですね!

さて、掲題のString::Secretは2020年にリリースしたっきりのCPANモジュールですが、(たぶん)そういえば紹介してなかったなと思ったのでこの機会に紹介しようと思います。完全に忘れていてネタがなかったんです。

SYNOPSIS

なにしてくれるやつなのよということでSYNOPSIS。

use String::Secret;
use String::Compare::ConstantTime;
use JSON::PP ();
my $secret = String::Secret->new('mysecret');
# safe secret for logging
MyLogger->warn("invalid secret: $secret"); # oops! but the secret is hidden: "invalid secret: ********"
# and safe secret for serialization
# MyLogger->warn("invalid secret: ".JSON::PP->new->convert_blessed->encode({ secret => $secret })); # oops! but the secret is hidden: invalid secret: {"secret":"********"}
unless (String::Compare::ConstantTime::equals($secret->unwrap, SECRET)) {
    die "secret mis-match";
}
# and can it convert to serializable
MyDB->credentials->new(
    id     => 'some id',
    secret => $secret->to_serializable, # or $secret->unwrap
)->save();

要はパスワードとかメールアドレスとか下手にうっかり永続化されてほしくないシークレットな情報を扱うとき、それらがうっかりログなどに残らないようサポートしてくれるくんです。

"password: $password"みたいにしちゃったとき、$passwordがString::Secretのインスタンスだったら"password: ********"相当にマスクしてくれます。

同様に、JSONに埋めてエンコードしちゃったときにconvert_blessedをつけてたら{ secret => $secret }{"secret":"********"}にしてくれるし、同様にallow_blessedなら{"secret":null}にしてくれます。allow_tagsでも{"secret":("String::Secret")[********]}と同様にマスクしてくれるので安心安全です。

同様に、CBOR、Serial、Storableに対してもマスクした値をシリアライズするため安全です。

もちろん、Data::DumperやData::Printer(DDP)に対しても安全です。たとえば、Dumper $secret$VAR1 = bless( do{\(my $o = '********')}, 'String::Secret' ); になります。

こんな感じで、出力に絡むだいたいのものに対して対応しています。

なお、$secret->unwrapのようにunwrapメソッドを呼び出すことで本当の中身を取り出すことができます。

仕組み

インサイドアウトオブジェクト、演算子オーバーロードというテクニックを使います。

インサイドアウトオブジェクト

この記事が詳しいので説明を譲ります。

要は、このテクニックを使うと外側からは特殊な黒魔術を駆使したりでもしない限りはアクセスできない領域にインスタンスの持つ値を保存することができるので、Data::Dumperとかでも中身が漏れない。という感じです。

演算子オーバーロード

Perlの演算子オーバーロードではblessされたオブジェクトを特定のコンテキストで評価したときに、任意のメソッドを呼び出すといった処理が記述できます。

use overload
    '""' => 'to_string',
    fallback => 1;

こんな感じで記述することによって文字列コンテキストで評価されるとto_stringメソッドが呼び出されるようになります。

あとはto_string"********"を返してあげれば文字列展開されてもマスクされてる感のあるテキストになってくれて安心というわけです。

永続化層のサポート

いうて永続化層に保存したいときまでマスクされては困る。という場面もあるでしょう。
そんなときのために String::Secret::Serializable というやつも用意しています。

これは中身を保ったままシリアライズできるという点だけが異なります。Data::Dumperや文字列展開に対しては同様に保護ができます。

それぞれ、$secret->to_serializableあるいはString::Secret->from_serializable($secret)というような感じで相互変換ができます。

たとえば永続化層への保存をする場面でto_serializableして、永続化層から取り出したらfrom_serializableするといった使い方が可能です。

まとめ

Perlはこういうの簡単に作れて便利!明日は @mackee_w さんです!

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?