デフォルトでは、逆 pickle 化は pickle 化されたデータ中に見つかった クラスを import することになります。自前の unpickler をカスタマイズ することで、何が unpickle 化されて、どのメソッドが呼び出されるか を厳密に制御することはできます。しかし不運なことに、厳密に なにを行うべきかはpickle と cPickle のどちらを使うかで異なります 3.10。
pickle モジュールでは、Unpickler からサブクラスを 導出し、load_global() メソッドを上書きする必要があります。 load_global() は pickle データ列から最初の 2 行を読まなければ ならず、ここで最初の行はそのクラスを含むモジュールの名前、2 行目は そのインスタンスのクラス名になるはずです。 次にこのメソッドは、例えばモジュールをインポートして属性を掘り起こす などしてクラスを探し、発見されたものを unpickler のスタックに置きます。 その後、このクラスは空のクラスの __class__ 属性に代入する 方法で、クラスの __init__() を使わずにインスタンスを魔法のように 生成します。 あなたの作業は (もしその作業を受け入れるなら)、unpickler のスタックの 上に push された load_global() を、unpickle しても安全だと 考えられる何らかのクラスの既知の安全なバージョンにすることです。 あるいは全てのインスタンスに対して unpickling を許可したくないなら エラーを送出してください。このからくりがハックのように 思えるなら、あなたは間違っていません。このからくりを動かすには、 ソースコードを参照してください。
cPickle では事情は多少すっきりしていますが、十分という
わけではありません。何を unpickle 化するかを制御するには、
unpickler の find_global 属性を関数か None
に
設定します。属性が None
の場合、インスタンスを unpickle
しようとする試みは全て UnpicklingError を送出します。
属性が関数の場合、この関数はモジュール名またはクラス名を
受理し、対応するクラスオブジェクトを返さなくてはなりません。
このクラスが行わなくてはならないのは、クラスの探索、必要な
import のやり直しです。そしてそのクラスのインスタンスが
unpickle 化されるのを防ぐためにエラーを送出することもできます。
以上の話から言えることは、アプリケーションが unpickle 化する 文字列の発信元については非常に高い注意をはらわなくてはならないと いうことです。