Cover image for How to anonymise sensitive data in PDF documents with Python

Jason Farrar

銀行明細書を誰かと共有したことはありますか? トラブルシューティングのためにプロジェクトのユーザーに共有してもらったことがあるかもしれません。

まさに同じ問題に直面しました。私は英国の銀行明細書をリレーショナルデータベースに変換する拡張可能なツールを開発していますが、自分の銀行の明細書にしかアクセスできません。他の銀行の明細書にアクセスするには、どうすれば人々に機密性の高い個人情報(PII)を送ってもらわずに済むでしょうか?

レイアウトとフォントエンコーディングを維持し、元の明細書と同じ方法で処理できる匿名化された銀行明細書が必要でした。また、デフォルトですべてをスクランブルしつつ、日付と取引タイプの保護を有効にできるようにしたいと思いました。最後に、同じ口座からの複数の明細書をスクランブルする場合、同じ偽の値に常にスクランブルするよう設定できると便利です!

そこで、機密データをスクランブルしつつPDFの見た目を完全に同じに保つPythonツールを開発しました。

PDF編集の問題点

従来の編集ツールは通常、次の2つのいずれかを行います:

  1. 黒いボックス — 不透明な矩形を重ねる。テキストはまだ下に存在する(パーサーが処理すればすぐに表示される)。実際には安全ではない。
  2. テキスト置換 — テキストを入れ替えるが、フォントエンコーディングやレイアウト、あるいはその両方が破損する。PDFの見た目がおかしいだけでなく、明細書の構成がわずかに変わるだけで設定ファイルが無効になり、使用できなくなる可能性がある。

どちらも理想的ではありません。必要なのは、PDFのコンテンツストリーム(PDFビューアーに何を描画するかを指示する生の命令)のバイトを実際に置き換え、フォントエンコーディングと位置情報を保持することでした。

なぜpikepdfか?

3つのPython PDFライブラリを調べました:

ライブラリ レベル なぜ機能しなかったか
PyPDF2 高レベル マージ、分割、抽出 — コンテンツストリームへのアクセスなし
pdfplumber 高レベル テキスト抽出にはすでに使用しているが、コンテンツストリームは変更できない
pikepdf 低レベル コンテンツストリームの演算子とフォントエンコーディングへの直接アクセス

pikepdfは生のPDF演算子(Tj(テキスト表示)、TJ(位置指定付きテキスト表示)、Tm(テキストマトリックス設定))へのアクセスを提供します。これが実際のテキストが存在する場所であり、変更が必要な場所です。

仕組み

基本的な考え方はシンプルです:

  1. PDFのコンテンツストリームを演算子にパースする
  2. 機密パターン(ソートコード、口座番号、IBAN、カード番号)をスキャンする
  3. 一致するバイトをスクランブルされた代替テキストに置き換える
  4. 変更したコンテンツストリームを書き戻す

ここで難しいのがPDFのフォントエンコーディングです。銀行によって異なるエンコーディング戦略が使用されています:

  • Latin-1(1バイト、直線的)
  • ToUnicode CMap(文字コードをUnicodeにマッピング — 現代のPDFで一般的)
  • Identity-H(CIDフォント、マルチバイト — 一部の銀行ソフトウェアで使用)

このツールは3つすべてを処理するため、銀行のPDF生成ツールに関係なくスクランブルされたテキストが正しく表示されます。

使い方

1つの関数、1つのインポート:

from bank_statement_anonymiser import anonymise_pdf

anonymise_pdf("statement.pdf", "anonymised.pdf")

Enter fullscreen mode Exit fullscreen mode

これだけです。出力PDFは入力と同じ見た目ですが、機密データがスクランブルされています。

匿名化される内容

このツールは以下のパターンを対象としています:

  • ソートコード(英国特有:XX-XX-XX形式)
  • 口座番号(英国の8桁口座)
  • IBAN(国際銀行口座番号)
  • カード番号(Visa、Mastercardのパターン)
  • 加盟店名(設定ファイルで設定可能)

匿名化されない内容

  • 取引金額(依存プロジェクトが取引明細の金額を明細書全体の変動と照合するため)
  • 日付(取引日と明細書の日付をカバーする各種形式)
  • 取引タイプ(対応銀行の既知の取引タイプを含むnever_anonymise_system.tomlで指定)

設定

独自のTOML設定ファイルを渡すことで、匿名化する内容をさらにカスタマイズできます:

# always_anonymise.toml — これらのパターンを強制的に置換
"12-12-12" = "99-99-99"
"Jason Farrar" = "John Doe"

Enter fullscreen mode Exit fullscreen mode

# never_anonymise.toml — これらのフレーズを保護
exclude = [
    "Balance Brought Forward",
    "Account Summary",
]

Enter fullscreen mode Exit fullscreen mode

このシステムは除外ベースのアプローチを使用しています:デフォルトですべてがスクランブルされ、その後保護する内容を指定します。

制限事項

これは英国特有です。ソートコード、口座番号、IBAN形式の正規表現パターンは英国の銀行向けに含まれています。現在、以下の銀行で正常にテストされています:

  • HSBC
  • Natwest
  • TSB
  • Halifax

他の銀行でも動作する可能性があるため、ぜひ試してみてフィードバックをお寄せください!
他の銀行では新しい正規表現パターンの追加が必要になる可能性が高く、取引タイプもほぼ確実に異なります。また、未対応のフォントエンコーディングがあるかもしれません。
すべての貢献を歓迎します!

インストール

pip install uk-bank-statement-anonymiser

Enter fullscreen mode Exit fullscreen mode

インストールと使用方法の詳細はREADMEでご覧いただけます

オープンソース

MITライセンス。すべての処理はローカルで行われます — ネットワークリクエスト、アカウント、データ収集はありません。

GitHub: github.com/boscorat/uk-bank-statement-anonymiser

同様のPDF匿名化の課題に遭遇したことはありますか? 他の銀行のPDF形式についてもお聞きしたいです — より多くのパターンを追加するほど、このツールの有用性が高まります。

ご質問やコメントも大歓迎です。この問題へのより良いアプローチや、プロジェクトの有用な範囲を広げるための構造変更についてのご意見をお待ちしています。