Pythonでは、オブジェクトをストレージ/転送のためにバイト列または文字列に変換する(シリアル化)ために、pickleおよびjsonモジュールが使用されます:
Pickleを制御できない第三者間でデータを保存/転送するために使用するのは危険です。 なぜなら、デシリアル化時に任意の悪意のあるコードが実行される可能性があるからです。jsonはこの欠点を持っていません。
動作例:
import pickle import json # Pickle(バイナリシリアル化) data = {'x': 10, 'func': lambda x: x + 1} with open('data.pkl', 'wb') as f: pickle.dump(data, f) # JSON(単純なオブジェクトのみ) data = {'x': 10, 'y': [1, 2, 3]} with open('data.json', 'w') as f: json.dump(data, f)
質問: 任意のPythonオブジェクトをセッション間でシリアル化および保存するためにpickleを使用できますか?このメカニズムはユーザーデータの保存に推奨されない理由は何ですか?
回答:
いいえ、pickleを至る所で使用するのは悪い習慣です。セキュリティ(「他人」のpickledオブジェクトをロードすると、実行が妥協される可能性がある)に加え、Pythonまたはクラスのバージョン不一致という問題があります。シリアル化されたオブジェクトは、クラスの構造が変更されるとロードできないか、正しく動作しない可能性があります。
例:
# pickleファイルの読み込み、クラスの構造が変更された場合 import pickle with open('old_version.pkl', 'rb') as f: obj = pickle.load(f) # AttributeErrorまたは構造の不一致
歴史
大規模なプロジェクトでユーザープロファイルの保存にpickleが使用されていました。Pythonのバージョンを更新し、クラスを変更した後、シリアル化されたオブジェクトの構造は互換性を失い、システムがクラッシュし、大部分のユーザーデータを失う結果となりました。
ウェブサービスでpickleがユーザーのセッションに使用されていました。悪意のある人物が悪意のあるpickledオブジェクトをロードし、サーバーへのコードインジェクションを実行することができました。
pickleを介して関数をシリアル化してネットワークを介して転送しようとする試みは、さまざまな環境で失敗しました:pickledラムダは異なる構成/バージョンのPythonを持つマシン間で移動できませんでした。