私はiOS6でApple)によって導入された NSSecureCoding
プロトコルについて学んでいます。
これまでの私の理解では、置換攻撃を防ぐために、クラスがそれ自体のインスタンスをエンコード/デコードするときはいつでも使用する必要があります。
他の場合に使うのが適切かどうか疑問に思います。
具体的には、クラスがそれ自体のインスタンス全体ではなく、インスタンス変数をエンコード/デコードすることによってNSCoding
に準拠している場合でも、NSSecureCoding
を実装することをお勧めしますか?
次のようにNSCoding
を実装しているクラスがあるとします。
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.aString forKey:@"aMeaningfulString"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if((self = [super init])) {
self.aString = [decoder decodeObjectForKey:@"aMeaningfulString"];
}
return self;
}
また、XPCが関与していないと仮定します。このクラスのインスタンスは、ディスクに保存されているplistにアーカイブされます。
セキュリティ面では、-decodeObjectOfClass:forKey:
ではなく-decodeObjectForKey:
を使用することにメリットはありますか?
特に、クラスがそれ自体のインスタンス全体ではなく、インスタンス変数をエンコード/デコードすることによってNSCodingに準拠している場合でも、NSSecureCodingを実装することをお勧めしますか?
アプリケーションのニーズによって異なります。古いアプリの場合、書き込まれる情報とアプリケーション自体は本質的に機密性が高い(すべきではない)ため、プレーンなNSCodingを使用してディスクに永続化することは問題ありません。しかし、あなたがアプリケーションをリリースしている銀行だったとしましょう。一部のアカウント情報またはAPIキーをディスクに保持して、サービスとの通信、ユーザーのIDの確認などを行うことができます。オブジェクト全体が必要ない場合もありますが、それは問題ではありません。 NSCoderは気にしませんwhatが読み取られているだけで、それを読み取って正しくジョブを実行できます。これは問題だ。
セキュリティ面では、-decodeObjectForKey:ではなく-decodeObjectOfClass:forKey:を使用することに利点はありますか?
はい、とてもそうです。オブジェクト(適切なオブジェクトは言うまでもなく)をシリアル化/逆シリアル化するためにNSCoderに依存しているという事実は、巨大な攻撃ベクトルです。ハッカーがNSCoderで使用される形式(人間が読める形式で非常に悪意のあるものであるplistのような構造)で情報を変更すると、返されるものが入力したものであることを保証する方法はありません。 。NSCoderは、誰かがアーカイブに含まれるクラスを切り替えることを決定したことを気にしないため、悪意のあるクラスのオブジェクトを再構築し、ランタイムも再構築しません。実際、十分に賢いハッカーは、アプリケーションにパッチを挿入して、逆シリアル化されたオブジェクトが何らかの未定義の状態(スタックオーバーフロー)を引き起こし、アプリケーション全体を悪用する可能性があることを確認します。
decodeObjectOfClass:forKey:
を使用すると、NSCoderに逆シリアル化についてよりスマートにすることができ、非常に大きな穴にパッチを当てることができます。それはあなたが決してNSSecureCoding
なしでNSCoderを使うべきだと言っているのではなく、むしろあなたがそれをどのような状況で使うかについて賢くなければならないということです。
これがドキュメントと NSHipsters 投稿を読んだときの私の気持ちです。
カルスをバイナリに変換するために NSCoding
を使用します。これは、データをディスクにアーカイブするため、またはプロセス間通信のためです。ディスクへのアーカイブは比較的安全ですが、データを提供しているソースプロセスを信頼できない可能性があるため、プロセス間通信にはリスクが伴います。
したがって、最初に、オブジェクトを永続的にディスクに書き込むためにNSCoding
を使用している場合は、NSSecureCoding
について心配する必要はありません(ただし、実装は非常に簡単です。以下を参照してください)。
具体的には、クラスがそれ自体のインスタンス全体ではなく、インスタンス変数をエンコード/デコードすることによってNSCodingに準拠している場合でも、NSSecureCodingを実装することをお勧めしますか?
クラスのインスタンス全体をどのようにデコードできるかわかりません。クラスは、アーカイバからのデータをデコードし、それを使って何かを行うことによってデコードされます。
- (id) initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder])
{
// Old way
//obj myUnsecureObj = [aDecoder decodeObjectForKey:@"myKey"];
// New way
obj mySecureObj = [aDecoder decodeObjectOfClass:[MyClass class]
forKey:@"myKey2"];
// Use mySecureObj (e.g. save to an property / ivar)
}
return self;
}
+ (BOOL)supportsSecureCoding {
return YES;
}
decodeObjectForKey:
を呼び出してインスタンス変数をデコードすると、クラスタイプを確認する前にオブジェクトが構築されます(NSSecureCoding
が導入された理由)。
したがって、ここでも同じルールが適用されていると思います。したがって、インスタンス変数をデコードする場合も、decodeObjectOfClass:forKey
の代わりにdecodeObjectForKey:
を使用することをお勧めします。