opthub-org / opthub-client

CLI tools used in OptHub competitions.
https://pypi.org/project/opthub_client/
1 stars 0 forks source link

`pickle` and modules that wrap it can be unsafe when used to deserialize untrusted data, possible security issue #95

Open Mishima-Ryuji opened 2 months ago

Mishima-Ryuji commented 2 months ago

このエラーを無視することは、セキュリティの観点から非常にリスクが高いです。以下の理由から、このエラーは深刻に受け止めるべきです:

  1. セキュリティ脆弱性: pickle(およびshelveなどのpickleをラップするモジュール)は、信頼できないデータをデシリアライズする際に安全ではありません。攻撃者が悪意のあるシリアライズされたデータを提供すると、任意のコード実行につながる可能性があります。

  2. 潜在的な攻撃ベクトル: 攻撃者がシリアライズされたデータを操作できる場合、システムに対して深刻な攻撃を仕掛けることができます。これには、データの改ざん、機密情報の漏洩、さらにはリモートコード実行などが含まれます。

  3. データの整合性: pickleはデータの整合性を保証しません。悪意のある改変や破損したデータは、アプリケーションの予期しない動作やクラッシュを引き起こす可能性があります。

  4. 業界のベストプラクティス: セキュリティ専門家は、信頼できないソースからのデータをデシリアライズする際にpickleを使用しないことを強く推奨しています。

このエラーを無視する代わりに、以下の対策を検討してください:

  1. 代替手段の使用:

    • JSONなどの安全なシリアライゼーション形式を使用する。
    • データベース(SQLiteなど)を使用してデータを保存・取得する。
  2. データの検証: デシリアライズする前に、データの出所と整合性を厳密に検証する仕組みを実装する。

  3. 限定的な使用: pickleの使用を完全に避けられない場合、その使用を信頼できるデータソースに厳密に限定し、適切なサニタイズを行う。

  4. セキュアな代替手段: 暗号化されたストレージや専用のキー管理システムを使用して、機密データ(暗号化キーなど)を安全に保存する。

例えば、先ほどの例を安全な方法で実装するなら、以下のようになります:

import os
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
import base64

KEY_FILE_PATH = "encryption_key.bin"
SALT_FILE_PATH = "salt.bin"

def get_or_create_key():
    if not os.path.exists(SALT_FILE_PATH):
        salt = os.urandom(16)
        with open(SALT_FILE_PATH, "wb") as salt_file:
            salt_file.write(salt)
    else:
        with open(SALT_FILE_PATH, "rb") as salt_file:
            salt = salt_file.read()

    if not os.path.exists(KEY_FILE_PATH):
        kdf = PBKDF2HMAC(
            algorithm=hashes.SHA256(),
            length=32,
            salt=salt,
            iterations=100000,
        )
        key = base64.urlsafe_b64encode(kdf.derive(os.urandom(32)))
        with open(KEY_FILE_PATH, "wb") as key_file:
            key_file.write(key)
    else:
        with open(KEY_FILE_PATH, "rb") as key_file:
            key = key_file.read()

    return key

この方法では、pickleshelveを使用せず、暗号学的に安全な方法でキーを生成・保存しています。また、ファイルシステムの権限設定を適切に行い、これらのファイルへのアクセスを制限することも重要です。

結論として、このエラーを無視することは非常に危険です。セキュリティを重視し、安全な代替手段を採用することを強くお勧めします。

Mishima-Ryuji commented 2 months ago

現状は他のユーザのデータをpickleでロードすることはないので放置する。