💨

OSSの画像PIIスキャナー、Octopii試してみた

2022/12/06に公開

気にはなってるけど触ってないビッグデータ系のツール・サービスを触る Advent Calendar 2022の#5です。

OSSの画像PIIスキャナーOctopiiについて調べて・触ってみました。

tl;dr

  • PIIスキャナー・DLPと呼ばれるカテゴリーの製品があるよ
  • OctopiiはOSSの画像スキャンしてくれるツールだよ
  • 現状、学習に使ったモデルがまだ小さいため精度は微妙かも。ただ、Kerasのモデルを拡張できるよ

PIIとは

PII(Personally Identifiable Information)で、「個人を特定できる情報」です。例えば、

  • マイナンバーやアメリカの社会保障番号などの、国が発行する識別番号
  • 電話番号やメールアドレス

などです。

PIIスキャナー・DLP(Data Loss Prevention)

PIIは法律による規制(GDPRとか個人情報保護法とか)があり、他のデータより取り扱いに注意が必要です。

PIIが元から入ることが決まっているデータ(e.g. マッチングアプリで成人確認のために受け取る)であれば事前に用意・覚悟できるのですが、PIIが本来入っていはずのデータにPIIがあると話が難しくなります。具体的には、

  • PIIに関係ないユーザ入力で、ユーザが間違ってPIIを入れる
  • 設定ミスなので本来、うっかりPIIが入る

などの場合が考えられます。

PIIスキャナーはデータをスキャンし、PIIが有無を確認するソフトウェアです。

(似た言葉で、DLP(Data Loss/Lake Prevention)というサービス・ツールもありますが違いは不明です…)

PIIスキャナー・DLP(Data Loss Prevention)の例

セキュリティーベンダーや、パブリッククラウドがSaaSとして提供している例が多く、具体的な製品としては

などがあります。

Octopiiとは

セキュリティー系の企業Redunt Labsが開発している、OSSの画像PIIスキャナーです。Pythonで動き、ローカルもしくはS3の画像をスキャンし、PIIの有無を確認します。

裏側では、

  • Kerasの訓練済みモデルで分類
    • 身分証のフォーマットを決めたISO/IEC 7810っぽいかをチェックしているらしいです
  • TesseractでOCRして、PIIらしき文字列が含まれるか

の二種類のチェックを行っているようです。

注意

ツールの特性として、機微な情報を含みうる画像に使うと思いますが、自己責任でお願いします。

準備

Ubuntu 20.04 (Windows10のWSL2上)で試しました。

リポジトリを取得します。

 git clone https://github.com/redhuntlabs/Octopii.git 

必要なパッケージをインストールします。

pip install -r requirements.txt
sudo apt install tesseract-ocr -y

提供されているダミーデータで試してみる

dummy-piiディレクりにいくつかダミーのPIIファイルの画像ファイルが用意されています。

  • アドハー(インドの個人識別番号)
  • クレジットカード
  • 運転免許証(ネブラスカ(アメリカ)とマハーラーシュトラ(インド))
  • パスポート(イギリス、インド)
  • 署名
e https://github.com/redhuntlabs/Octopii.git
notrogue@DESKTOP-6QTOO0L:~/project/Octopii$ tree dummy-pii/
dummy-pii/
├── Aadhaar
│   └── dummy-aadhaar.jpg
├── Debit_Credit_Card
│   └── dummy-debit-card.jpg
├── Drivers_License
│   ├── dummy-drivers-license-maharashtra.jpg
│   └── dummy-drivers-license-nebraska-us.jpg
├── PAN
│   └── dummy-PAN-India.jpg
├── Passport
│   ├── dummy-passport-britain.jpg
│   └── dummy-passport-india.jpg
└── Signature
    └── dummy-signature.png

6 directories, 8 files

用意されたダミーファイルで、Octopiiを動かしてみます。

 time python3 octopii.py dummy-pii/
WARNING:tensorflow:No training configuration found in the save file, so the model was *not* compiled. Compile it manually.
octopii.py:133: DeprecationWarning: ANTIALIAS is deprecated and will be removed in Pillow 10 (2023-07-01). Use Resampling.LANCZOS instead.
  image = ImageOps.fit(image, size, Image.ANTIALIAS)
1/1 [==============================] - 0s 405ms/step
octopii.py:133: DeprecationWarning: ANTIALIAS is deprecated and will be removed in Pillow 10 (2023-07-01). Use Resampling.LANCZOS instead.
  image = ImageOps.fit(image, size, Image.ANTIALIAS)
1/1 [==============================] - 0s 19ms/step
octopii.py:133: DeprecationWarning: ANTIALIAS is deprecated and will be removed in Pillow 10 (2023-07-01). Use Resampling.LANCZOS instead.
  image = ImageOps.fit(image, size, Image.ANTIALIAS)
1/1 [==============================] - 0s 23ms/step
octopii.py:133: DeprecationWarning: ANTIALIAS is deprecated and will be removed in Pillow 10 (2023-07-01). Use Resampling.LANCZOS instead.
  image = ImageOps.fit(image, size, Image.ANTIALIAS)
1/1 [==============================] - 0s 21ms/step
octopii.py:133: DeprecationWarning: ANTIALIAS is deprecated and will be removed in Pillow 10 (2023-07-01). Use Resampling.LANCZOS instead.
  image = ImageOps.fit(image, size, Image.ANTIALIAS)
1/1 [==============================] - 0s 39ms/step
octopii.py:133: DeprecationWarning: ANTIALIAS is deprecated and will be removed in Pillow 10 (2023-07-01). Use Resampling.LANCZOS instead.
  image = ImageOps.fit(image, size, Image.ANTIALIAS)
1/1 [==============================] - 0s 20ms/step
octopii.py:133: DeprecationWarning: ANTIALIAS is deprecated and will be removed in Pillow 10 (2023-07-01). Use Resampling.LANCZOS instead.
  image = ImageOps.fit(image, size, Image.ANTIALIAS)
1/1 [==============================] - 0s 22ms/step
octopii.py:133: DeprecationWarning: ANTIALIAS is deprecated and will be removed in Pillow 10 (2023-07-01). Use Resampling.LANCZOS instead.
  image = ImageOps.fit(image, size, Image.ANTIALIAS)
1/1 [==============================] - 0s 19ms/step
No text found in: dummy-pii/Signature/dummy-signature.png
[
    {
        "asset_type": "Passport",
        "country_of_origin": "International",
        "confidence": 50,
        "file_name": "dummy-passport-britain.jpg",
        "extension": "jpg",
        "path": "dummy-pii/Passport/dummy-passport-britain.jpg"
    },
    {
        "asset_type": "Passport",
        "country_of_origin": "International",
        "confidence": 100,
        "file_name": "dummy-passport-india.jpg",
        "extension": "jpg",
        "path": "dummy-pii/Passport/dummy-passport-india.jpg"
    },
    {
        "asset_type": "Driver License",
        "country_of_origin": "International",
        "confidence": 100,
        "file_name": "dummy-drivers-license-nebraska-us.jpg",
        "extension": "jpg",
        "path": "dummy-pii/Drivers_License/dummy-drivers-license-nebraska-us.jpg"
    },
    {
        "asset_type": "Driver License",
        "country_of_origin": "International",
        "confidence": 50,
        "file_name": "dummy-drivers-license-maharashtra.jpg",
        "extension": "jpg",
        "path": "dummy-pii/Drivers_License/dummy-drivers-license-maharashtra.jpg"
    },
    {
        "asset_type": "Bank",
        "country_of_origin": "IN",
        "confidence": 50,
        "file_name": "dummy-debit-card.jpg",
        "extension": "jpg",
        "path": "dummy-pii/Debit_Credit_Card/dummy-debit-card.jpg"
    },
    {
        "asset_type": "Aadhaar",
        "country_of_origin": "IN",
        "confidence": 100,
        "file_name": "dummy-aadhaar.jpg",
        "extension": "jpg",
        "path": "dummy-pii/Aadhaar/dummy-aadhaar.jpg"
    },
    {
        "asset_type": "PAN",
        "country_of_origin": "IN",
        "confidence": 100,
        "file_name": "dummy-PAN-India.jpg",
        "extension": "jpg",
        "path": "dummy-pii/PAN/dummy-PAN-India.jpg"
    },
    {
        "asset_type": "Signature",
        "country_of_origin": null,
        "confidence": 7,
        "file_name": "dummy-signature.png",
        "extension": "png",
        "path": "dummy-pii/Signature/dummy-signature.png"
    }
]

real    0m7.743s
user    0m11.307s
sys     0m1.802s

8枚の画像で1秒程度で実行でき、

  • asset_typeの部分に画像の種類
  • country_of_originの部分に画像に関係する国
  • confidenceにPIIを含むかどうかの確信度合い

が表示されています。

日本語を含む画像・PIIでない画像で試してみる

PIIっぽい画像として、

PIIっぽくない画像として、

を試してみます。

$ time python3 octopii.py jp-pii/
WARNING:tensorflow:No training configuration found in the save file, so the model was *not* compiled. Compile it manually.
octopii.py:133: DeprecationWarning: ANTIALIAS is deprecated and will be removed in Pillow 10 (2023-07-01). Use Resampling.LANCZOS instead.
  image = ImageOps.fit(image, size, Image.ANTIALIAS)
1/1 [==============================] - 0s 398ms/step
octopii.py:133: DeprecationWarning: ANTIALIAS is deprecated and will be removed in Pillow 10 (2023-07-01). Use Resampling.LANCZOS instead.
  image = ImageOps.fit(image, size, Image.ANTIALIAS)
1/1 [==============================] - 0s 19ms/step
octopii.py:133: DeprecationWarning: ANTIALIAS is deprecated and will be removed in Pillow 10 (2023-07-01). Use Resampling.LANCZOS instead.
  image = ImageOps.fit(image, size, Image.ANTIALIAS)
1/1 [==============================] - 0s 22ms/step
octopii.py:133: DeprecationWarning: ANTIALIAS is deprecated and will be removed in Pillow 10 (2023-07-01). Use Resampling.LANCZOS instead.
  image = ImageOps.fit(image, size, Image.ANTIALIAS)
1/1 [==============================] - 0s 19ms/step
octopii.py:133: DeprecationWarning: ANTIALIAS is deprecated and will be removed in Pillow 10 (2023-07-01). Use Resampling.LANCZOS instead.
  image = ImageOps.fit(image, size, Image.ANTIALIAS)
1/1 [==============================] - 0s 22ms/step
[
    {
        "asset_type": "Aadhaar",
        "country_of_origin": "IN",
        "confidence": 99,
        "file_name": "license_jp.jpg",
        "extension": "jpg",
        "path": "jp-pii/license_jp.jpg"
    },
    {
        "asset_type": "PAN",
        "country_of_origin": "IN",
        "confidence": 83,
        "file_name": "pokemon_card_eievui.jpg",
        "extension": "jpg",
        "path": "jp-pii/pokemon_card_eievui.jpg"
    },
    {
        "asset_type": "PAN",
        "country_of_origin": "IN",
        "confidence": 99,
        "file_name": "2808honnin.png",
        "extension": "png",
        "path": "jp-pii/2808honnin.png"
    },
    {
        "asset_type": "Aadhaar",
        "country_of_origin": "IN",
        "confidence": 9,
        "file_name": "menzyou.jpg",
        "extension": "jpg",
        "path": "jp-pii/menzyou.jpg"
    },
    {
        "asset_type": "Aadhaar",
        "country_of_origin": "IN",
        "confidence": 99,
        "file_name": "pokemon_card.jpg",
        "extension": "jpg",
        "path": "jp-pii/pokemon_card.jpg"
    }
]

real    0m5.656s
user    0m7.002s
sys     0m1.699s
  • 保険証と免許証は期待通り、高いconfidenceが出力されています
  • こちらも期待通り、免状は低いcofidenceが出力されています
  • 残念ながら、ポケモンカードは期待と違い、高いconfidenceが出力されています

(Octopiiより正確な能力を知るには、ラベル付きのデータをたくさん集めて、偽陽性とか評価すべきだとは思いますが力尽きました)

モデルの拡張

Octopiiが学習に使ったモデルがまだ小さいため、モデルの拡張を推奨しているらしいです。
(「Since our current dataset is quite small, we could benefit from a large Keras model of international PII for this project」)

models/ディレクトリの下にKerasのモデル(h5ファイル)を置くと拡張できるらしいです。

Discussion