PHP Tips | 文字列処理:ログ・表示向け - 表示用マスク(メール)

PHP PHP
スポンサーリンク

「表示用マスク(メール)」で何を守りたいのか

メールアドレスは、個人情報のど真ん中です。
でも業務では、ログや画面に「誰のことかは分かりたい」場面も多いですよね。

ログに「ユーザーのメールアドレス」をそのまま出したくない。
サポート画面で「完全なアドレスは見せたくないが、誰かは分かりたい」。
CSV やエラーメッセージに「一部だけ見せたい」。

そこで使うのが「表示用マスク」です。
本物のメールアドレスを、こんな感じに変形します。

user@example.comu***@example.com
tanaka.taro@example.comt*********@example.com

「本人や運用者には誰か分かるけど、丸見えではない」状態を作るのが目的です。


基本方針:ローカル部だけを部分的に見せる

メールアドレスは大きく 2 つに分かれます。

ローカル部@ドメイン部

user@example.com なら、user がローカル部、example.com がドメイン部です。
実務では、次のような方針にしておくとバランスが良いです。

ローカル部:先頭だけ少し見せて、残りを * にする。
ドメイン部:そのまま見せる(もしくは一部だけマスクする運用もあり)。

まずは「ローカル部だけマスク、ドメインはそのまま」というシンプルな形でいきます。


コアとなるマスク関数を作る

ざっくり仕様を決める

ローカル部のマスクルールを、こう決めてみます。

文字数が 1 文字なら:そのまま表示(a@example.coma@example.com)。
文字数が 2〜3 文字なら:先頭 1 文字だけ残して、残りを *
文字数が 4 文字以上なら:先頭 2 文字だけ残して、残りを *

これで、「誰かは分かる」「でも全部は見えない」というバランスになります。

実装例

function mask_email_for_display(string $email): string
{
    // 形式が怪しい場合は、そのまま返す(お好みで)
    if (!str_contains($email, '@')) {
        return $email;
    }

    [$local, $domain] = explode('@', $email, 2);

    $len = mb_strlen($local, 'UTF-8');

    if ($len <= 1) {
        // 1 文字ならそのまま
        $maskedLocal = $local;
    } elseif ($len <= 3) {
        // 2〜3 文字なら先頭 1 文字だけ残す
        $head = mb_substr($local, 0, 1, 'UTF-8');
        $maskedLocal = $head . str_repeat('*', $len - 1);
    } else {
        // 4 文字以上なら先頭 2 文字だけ残す
        $head = mb_substr($local, 0, 2, 'UTF-8');
        $maskedLocal = $head . str_repeat('*', $len - 2);
    }

    return $maskedLocal . '@' . $domain;
}
PHP

例題で挙動を確認する

シンプルな英数字の例

echo mask_email_for_display('a@example.com');
// a@example.com

echo mask_email_for_display('ab@example.com');
// a*@example.com

echo mask_email_for_display('abc@example.com');
// a**@example.com

echo mask_email_for_display('abcd@example.com');
// ab**@example.com

echo mask_email_for_display('tanaka.taro@example.com');
// ta*********@example.com
PHP

ローカル部の長さに応じて、見せる範囲が変わっているのが分かります。

日本語(マルチバイト)を含む例

echo mask_email_for_display('太郎@example.com');
// 太*@example.com

echo mask_email_for_display('山田太郎@example.com');
// 山田**@example.com
PHP

mb_strlen / mb_substr を使っているので、
日本語を含むローカル部でも「文字数ベース」でマスクできます。


実務での使いどころ

ログ出力時のマスク

エラーログやアクセスログにメールアドレスを出したいとき、
そのまま書くのではなく、マスクしてから出力します。

$email = $_POST['email'] ?? '';

$masked = mask_email_for_display($email);

error_log('Login failed for email=' . $masked);
PHP

これで、「誰のログか」は追えるけれど、
ログファイルが丸ごと漏洩してもダメージを少し抑えられます。

管理画面の一覧表示

ユーザー一覧画面などで、
「メールアドレスを全部見せるのは避けたいが、サポート担当には誰か分かってほしい」
というときに、そのまま使えます。

<td><?= htmlspecialchars(mask_email_for_display($user['email']), ENT_QUOTES, 'UTF-8') ?></td>
PHP

どこまでマスクするかは「運用ポリシー」で決める

ここまでの実装は、あくまで「一例」です。
実務では、会社やシステムごとにポリシーが違います。

ドメインも一部マスクする(example.comexa****.com)。
ローカル部は先頭 1 文字だけにする。
そもそもメールアドレスはログに出さない。

大事なのは、「ポリシーを決めて、それをコードに落とし込む」ことです。
今回のようなユーティリティ関数にマスクルールを閉じ込めておけば、
ポリシー変更があっても、その関数だけ直せば全体に反映できます。


まとめ:今日からの「表示用マスク(メール)」ユーティリティ

表示用マスク(メール)の目的は、「誰かは分かるが、丸見えではない」状態を作ることです。
そのために、

メールアドレスをローカル部とドメイン部に分ける。
ローカル部だけ、長さに応じて一部を * に置き換える。
ログや画面表示では、必ずこの関数を通した値だけを使う。

というルールを徹底します。

もう一度、コア関数を載せておきます。

function mask_email_for_display(string $email): string
{
    if (!str_contains($email, '@')) {
        return $email;
    }

    [$local, $domain] = explode('@', $email, 2);

    $len = mb_strlen($local, 'UTF-8');

    if ($len <= 1) {
        $maskedLocal = $local;
    } elseif ($len <= 3) {
        $head = mb_substr($local, 0, 1, 'UTF-8');
        $maskedLocal = $head . str_repeat('*', $len - 1);
    } else {
        $head = mb_substr($local, 0, 2, 'UTF-8');
        $maskedLocal = $head . str_repeat('*', $len - 2);
    }

    return $maskedLocal . '@' . $domain;
}
PHP

もし、あなたのプロジェクトで「ログに生のメールアドレスを出している」「一覧画面にフルのアドレスを出している」箇所があれば、そこがこの関数を差し込むべき場所です。
たった 1 行の差し替えで、「情報の見せ方」のレベルが一段上がります。

タイトルとURLをコピーしました