テストで秘匿情報のマスク漏れをチェックしよう
APIサーバでは個々のリクエストについて、リクエストを受信してから、レスポンスを返すまで、アドレス、ヘッダー、リクエストパラメータ、内部処理など、様々なタイミングでログに記録されています。情報漏えいを防ぐために、このログへのアクセスは、Googl Cloud Platform projectのアクセス制限下にあり、限られたエンジニアのみ閲覧権限が与えられています。加えて、秘匿情報はログに平文で出力しない、ことを規約として定めています。また、開発環境と本番環境を分離し、開発環境でログのマスク漏れを検知する仕組みを導入し、本番リリース前に検知・対応できるような体制をとっています。
ログデータはGoogl Cloud Loggingで管理され、分析、モニタリング、調査などに活用されます。ここで、ログは調査で利用することもあり、利便性の観点も踏まえて、全ての値ではなく秘匿情報に限りマスクしています。あらかじめマスクするキー文字列を定義し、ログを出力する直前に、ログテキスト内でマッチするキーを検索、値をマスク文字列に置換してから出力します。これは一般的なキーマッチです。また、ログに出力される全てタイミングで、秘匿情報が一括してマスクされるよう定義・処理しています。
キーマッチによるマスク処理ですので、キーが正しく定義されていない場合、マスク漏れが発生する恐れがあります。例えば、次のようなケースで、マスク漏れ・情報漏洩が発生する危険性が高くなります。
これらのケースはヒューマンエラーです。
人に依らず、マスク漏れ発生をチェックし、コーディングからリリースまでのフローを一時停止させる仕組みとして、マスク漏れをチェックするユニットテストを考えました。
masking_field_struct.go
1 package maskingtest
2
3 // テスト用構造体
4 type MaskingFieldTestStruct struct{
5 ///////////// 秘匿フィールドを追加する ///////////////
6 }
コードのサンプルです。
1
2 // 例えば、このような構造体の秘匿フィールドを、テスト用構造体のフィールドに追加する
3 type maskingFiledTestString struct {
4 KanaName []string `masking:"true"`
5 PhoneNumber string `masking:"true"`
6 Latitude string `masking:"true"`
7 }
8
9 // マスク後のパターン(json形式)
10 var maskingRegexp = regexp.MustCompile(`^[a-zA-Z,_\[\]"\{\}\:\*\s]*$`)
11
12 func TestMaskingFiledStruct(t *testing.T) {
13 // テスト用構造体のインスタンス
14 obj := maskingtest.MaskingFieldTestStruct{}
15 // 初期値を入れる(全てマスクされる)
16 maskingtest.FakeData(&obj)
17 // ログテキストを取得
18 tmp, err := json.Marshal(&obj) // ここでは、json形式に
19 require.NoError(t, err)
20
21 // 正規化
22 jsonByte := maskingtest.ConvertToSnakeCaseJSON(tmp)
23 // マスク処理
24 r := Masking(jsonByte)
25
26 // 判定
27 if !maskingRegexp.Match(r) {
28 t.Errorf("%s", string(r))
29 }
30 require.Equal(t, true, maskingRegexp.Match(r))
31 }
どうやるかはケースバイケースでしょうが、秘匿フィールドの検索には、例えば次のようなやり方があります。
また、カスタムタグの付け方も、ブラックリスト/ホワイトリスト方式があります。ここではブラックリスト方式を前提に書きましたが、ヒューマンエラー「定義するのを忘れてた」を検知、作業を一時停止させるためには、ホワイトリスト方式のほうがフェールセーフです。ホワイトリスト方式の場合、導入時に全ての非秘匿フィールドにタグ打ちするタスクも発生します。
ブラックリスト方式では、「カスタムタグの定義忘れ」というヒューマンエラーを完全に防ぐことはできません。しかし、次の2つのフローがあったとして、
後者が、マスクキーの定義・ログ・検知の通知など確認箇所が分散しているのに対して、前者は秘匿フィールドの定義とカスタムタグの付与が同じファイル・行に着目すればよいことから、作業漏れが発生しにくい状態にはなるでしょう。
テストでマスク漏れをチェックする仕組みについて検討しました。実際のところ、私の場合は心配性なので、結局、
をやりそうですが。
興味のある方は 採用ページ も見ていただけると嬉しいです。
Twitter @mot_techtalk のフォローもよろしくお願いします!