👏

漏洩リスクのある情報を持たないようにする

に公開

概要

生成AIの普及により、プログラミング知識が浅くても短時間でアプリケーションを構築できるようになりました。一方で、セキュリティの観点がおろそかになり、漏洩リスクの高いデータを扱う設計・実装が大量に生まれています。

もちろん適切なポリシー設定など正規の対応もありますが、ここでは個人的に最強の対策である「そもそも危険なデータを持たない」という対応を考えてみたいと思います。

具体的には以下4点を扱いますが、他にも良い案があればぜひ、教えてください。

  • メールアドレスを持たずに認証する
  • 生年月日を入力させず統計データを得る
  • 画像に隠れる個人を特定しうる情報の削除
  • とにかくなんでも入力可能を避ける

1.メールアドレスを持たずに認証する

課題:メールアドレスを直接保持すると、運用中のDB流出やメール誤送信時にユーザー情報が漏洩するリスクが高まる。
対策

  • OAuth/OIDCで Google, Apple, Twitter など信頼できるアイデンティティプロバイダーを利
  • ユーザーには「○○アカウントでログイン」だけを提示し、メールアドレスはプロバイダー側で管理

2.生年月日は「生まれ年」のみ取得

課題: フルの生年月日を保持すると、個人が特定できるうえ、誕生日認証や二要素認証の裏口になりうる。
対策

  • 生まれた「年」のみを入力させ、データベースには整数(例:birth_year: 1985)で保存
  • 年齢確認が必要な場合は「満◯歳以上かどうか」の判定にとどめ、詳細データは非保持

3.画像のEXIF情報を削除

課題: スマホで撮影した写真には緯度経度、撮影日時、端末情報などプライバシーを侵害するEXIFメタデータが含まれる。
対策

  • アップロード前にクライアント側(JavaScript)またはサーバー側でEXIF削除処理を実装
    ライブラリ例:piexifjs
import React from 'react';
import piexif from 'piexifjs';

export default function CompactExifStripper({ file }: { file: File }) {
  const upload = async () => {
    // 1. File→DataURL
    const dataUrl = await new Promise<string>((res, rej) => {
      const r = new FileReader();
      r.onload   = () => res(r.result as string);
      r.onerror  = () => rej(r.error);
      r.readAsDataURL(file);
    });

    // 2. piexifjs で除去
    const stripped = piexif.remove(dataUrl);

    // 3. DataURL→Blob
    const blob = await fetch(stripped).then(r => r.blob());

    // 4. アップロード
    const form = new FormData();
    form.append('image', blob, file.name);
    await fetch('/api/upload', { method: 'POST', body: form });
  };

  return <button onClick={upload}>アップロード(EXIF除去)</button>;
}

4.自由入力欄に入力させない

課題:自由入力欄にユーザーが誤って以下のような個人情報を入れてしまうことがある。
対応

  • PII検出(ブラックリスト方式)あらかじめ定義した正規表現で「これは個人情報っぽい」と見つけたらエラー/警告
// src/utils/detectPii.js
export const piiPatterns = {
  email:   /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
  phone:   /0\d{1,4}-\d{1,4}-\d{4}/,                   // 090-1234-5678 等
  postal:  /\d{3}-\d{4}/,                              // 123-4567
  address: /(東京都|北海道|.{2,3}).+(|||).+/, // 簡易的な日本の住所検出
};

export function detectPII(text) {
  return Object.entries(piiPatterns)
    .filter(([, regex]) => regex.test(text))
    .map(([key]) => key);
}

import React, { useState } from 'react';
import { detectPII } from './utils/detectPii';

export function FreeTextInput() {
  const [error, setError] = useState('');

  const handleBlur = (e) => {
    const value = e.target.value;
    const found = detectPII(value);
    if (found.length) {
      setError(`${found.join('、')} が入力されています。個人情報は入力しないでください。`);
    } else {
      setError('');
    }
  };

  return (
    <div>
      <textarea
        placeholder="ご意見・ご要望など"
        onBlur={handleBlur}
        rows={4}
        style={{ width: '100%' }}
      />
      {error && <p style={{ color: 'red', marginTop: 4 }}>{error}</p>}
    </div>
  );
}

5.最後に

安全で楽しい開発をしましょう!

Discussion