コンテンツにスキップ
検索語を入力してください

    PII 保護

    Debug derive や span フィールドは、意図せず個人データや資格情報をログに載せてしまう。型でラップし、露出はアダプターに閉じる設計にしないと、可観測性がそのまま漏洩面になる。

    ログとメトリクスの実装は ロギングとメトリクス、資格情報の扱いは クレートガイド(secrecy)、テストでの検証は テストデータ を参照する。

    ログに載せにくい sensitive データにする

    Section titled “ログに載せにくい sensitive データにする”

    個人データはデフォルトで redacting wrapper または typed value object を使う。資格情報、API key、token、password、暗号 material には secrecy::SecretString または SecretBox<T> に限定する。名前やメールなど一般 PII は Redacted<T> または safe Debug 付き domain newtype が通常で、secrecy ではない。

    PII の例: 氏名、メール、電話、住所、政府 ID、支払識別子、健康データ、IP、精密位置。

    pub struct Redacted<T>(T);
    pub struct Patient {
    id: PatientId,
    email: EmailAddress,
    diagnosis: Redacted<DiagnosisCode>,
    }

    raw PII を含む struct に Debug derive しない。Debug が必要なら sensitive field を手動 redact するか、redact する wrapper の Debug に依存。

    資格情報と secret には secrecy 型:

    use secrecy::SecretString;
    pub struct PaymentGatewayCredentials {
    api_key: SecretString,
    }
    関心推奨理由
    API key、password、token、private keysecrecy::SecretString / SecretBoxdrop 時 zeroize。Debug はデフォルト非表示
    氏名、メール、電話、住所、政府 IDRedacted<T> または domain newtypePII は crypto 意味の secret ではないが log に出してはならない
    ops log で安全な opaque surrogate IDsafe Display 付き plain newtypeロギングとメトリクス 参照
    UI または audit export に表示する値domain 型 + 明示 expose_for_*露出は意図的かつ命名される

    secrecy は資格情報処理とメモリ衛生向け。Redacted<T> は個人データの accidental log 防止向け。すべてのメールを SecretString に包まない。長寿命 PII を Debug derive だけで守らない。

    メール配信、決済、暗号 adapter、audit export など本当に必要な境界でのみ sensitive 値を露出。露出を伝えるメソッド名を優先:

    pub fn expose_for_delivery(&self) -> &EmailAddress {
    &self.email
    }

    domain error や log に sensitive 値を format しない。

    user_idpassenger_id というフィールド名が safe を決めない。ロギングとメトリクス のルール:

    • デフォルト safe: opaque surrogate 集約 ID、correlation ID、内部 job/transaction ID、有界 domain enum
    • ログ禁止: secret、政府 ID、支払識別子、連絡先 identity、人物記述、健康データ、精密位置、ネットワーク tracking ID
    • 条件付き: プロジェクトが opaque surrogate と safe Display/Debug と文書化した person-linked ID(user_idcustomer_idpatient_iddevice_id、partner ref)

    決定を型に符号化。一般 log に出してはならない ID は Redacted<T>、制限 formatting、adapter のみ露出で accidental emission を防ぐ。

    tracing は span/event に付いた field 値を記録する。PII はデフォルトで span に入れない。

    #[tracing::instrument(
    name = "send_receipt",
    skip(patient),
    fields(patient_id = %patient.id())
    )]
    pub async fn send_receipt(patient: &Patient) -> Result<(), SendError> {
    // ...
    Ok(())
    }

    PII を含む struct や引数全体は skip。safe と分類した surrogate ID のみ log。

    impl std::fmt::Display for Redacted<EmailAddress> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    write!(f, "[redacted email]")
    }
    }

    structured field が必要なときだけ tracing::Value を impl。human-readable trace では redacted Display をデフォルト。

    多 crate が tracing 経由で log するとき、OTLP や stdout 前に subscriber layer で既知 sensitive key(emailphonessn)を strip または hash。layer はソース redacted 型の代わりにならない。コンプライアンスで belt-and-suspenders が必要なら両方。

    API response と audit export ではシリアライズを明示制御。raw PII を含む domain struct を response DTO が redact しない限り serialize しない。

    fn redact_email<S>(value: &EmailAddress, serializer: S) -> Result<S::Ok, S::Error>
    where
    S: serde::Serializer,
    {
    serializer.serialize_str("[redacted]")
    }
    #[derive(serde::Serialize)]
    pub struct PatientResponse {
    id: PatientId,
    #[serde(serialize_with = "redact_email")]
    email: EmailAddress,
    }

    大半が safe な struct では、フィールドごとの serialize_with より別の response DTO を優先する。それ以外は safe な struct のうち 1 フィールドだけマスキングが必要なときに serialize_with を使う。

    ユーザー向けテキストと開発者診断が異なるとき impl を分ける:

    impl std::fmt::Debug for EmailAddress {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    f.write_str("EmailAddress([redacted])")
    }
    }
    impl std::fmt::Display for EmailAddress {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    // Only used at boundaries that intentionally show the address
    f.write_str(self.as_str())
    }
    }
    • Debug: PII 型はデフォルト redact。log、test、tracing debug 出力の {:?} を保護
    • Display: 意図的なユーザー向け表示、またはアダプター出力用。呼び出し箇所を狭く保つ

    すべての to_string() が log に漏れるなら PII 型に Display derive しない。adapter では expose_for_delivery()&str を返す形を優先。

    debug 出力に raw PII が含まれないことを assert:

    #[test]
    fn patient_debug_does_not_leak_email() {
    let patient = Patient::fixture_with_email("patient@example.com");
    let debug = format!("{patient:?}");
    assert!(!debug.contains("patient@example.com"));
    assert!(debug.contains("redacted") || !debug.contains('@'));
    }

    secrecy 型:

    #[test]
    fn credentials_debug_is_hidden() {
    let creds = PaymentGatewayCredentials {
    api_key: SecretString::new("super-secret".into()),
    };
    let debug = format!("{creds:?}");
    assert!(!debug.contains("super-secret"));
    }

    assert が決定論的になるよう既知値の fixture builder。テストデータ で合成データ慣習。

    スタックPII パターン
    secrecy + adapterpayment/auth adapter のみ ExposeSecret
    tracing + redacted newtypesspan で skip、domain 型は safe Debug
    serde + response DTOsserialize_with または別 PatientResponse
    thiserror + PIIerror variant は field 名のみ、raw 値なし

    レビューでは、error の #[error(...)] への raw email / phone / 政府 ID、redaction なしの #[derive(Debug)]、patient / user struct への skip なし tracing::instrument、非資格情報 PII への一律 SecretString、ドメイン entity への無制限 Serialize を指摘する。

    Debug やログで機密データが露出しないか — High

    Section titled “Debug やログで機密データが露出しないか — High”

    生の機密値を含む #[derive(Debug)]tracing フィールド、整形エラー、ログを指摘する。

    メトリクス、スパン属性、監査イベント、パニックメッセージ、検証エラーにも生の PII やシークレットがないか確認する。

    PII とシークレットはラップされているか — High

    Section titled “PII とシークレットはラップされているか — High”

    メール、電話、住所、氏名、政府 ID、決済データ、健康データ、IP アドレス、精密位置、トークン、パスワードを運ぶ素の StringVec<u8>、プリミティブフィールドを指摘する。

    secrecy::SecretStringSecretBox<T>、またはプロジェクトローカルのマスキングラッパを提案する。

    すべての PII 値に SecretString を必須としない。表示名、メール、粗い IP など非シークレット識別子は、Debug、ログ、シリアライズがマスキングされるか意図的に公開されるならドメイン newtype でよい。

    人物に紐づく ID は条件付きで、自動的に安全とはみなさない — High

    Section titled “人物に紐づく ID は条件付きで、自動的に安全とはみなさない — High”

    ロギングとメトリクス の「ログに載せる ID」の節も照合する。不透明なサロゲートである根拠なしに user_idpassenger_idcustomer_idpatient_iddevice_id、パートナー参照をログする箇所を指摘する。

    request_idorder_idcorrelation_id のような内部集約 ID で、明らかにサロゲートキーかつ安全な整形である場合は指摘しない。

    可観測性はデフォルトでマスキングされているか — High

    Section titled “可観測性はデフォルトでマスキングされているか — High”

    マスキング方針、許可リストフィールド、明示的な安全表示ラッパなしに、任意のドメインオブジェクトや DTO を受け取るログ / メトリクスヘルパを指摘する。

    平文露出は狭く名前付きか — Medium

    Section titled “平文露出は狭く名前付きか — Medium”

    機密値向けの email(&self) -> &str のような広いゲッターを指摘する。アダプタ専用の露出メソッドやラッパを提案する。