3. その他、デシリアライズ処理を悪用した攻撃の影響を軽減するための参考情報
その他、デシリアライズ処理を悪用した攻撃の影響を軽減するための対策を、参考までにいくつかご紹介する。
SecurityManagerによりアプリケーションが可能な動作を制限する
デシリアライズ時にJavaのセキュリティ機構であるSecurityManagerを使用して、アプリケーションに許可する動作を制限する。これにより、意図しないオブジェクトがデシリアライズされて悪意あるコード(OSコマンドなど)が実行された場合においても、システムへの影響を軽減できる場合がある。詳細はセキュアコーディングスタンダードSER04-Jを参照されたい。
なお、SecurityManagerによるセキュリティチェックはAPIを使ってプログラム内で行う以外にもJVMオプション" -Djava.security.manager"によって有効化することもできる。
以下は、デシリアライズ処理を悪用するように細工したクラスを、SecurityManagerを有効にしてデシリアライズした結果の例だ。セキュリティ例外が発生し、細工したコードの実行は行われない。
AnnotationInvocationHandlerクラスをSecurityManagerを有効にしてデシリアライズした場合:
通常外からの呼び出しができないクラスをデシリアライズしようとして、セキュリティ例外が発生。
java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessClassInPackage.sun.reflect.annotation")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:457)
at java.security.AccessController.checkPermission(AccessController.java:884)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
OSコマンドを実行するクラスをSecurityManagerを有効にしてデシリアライズした場合:
許可されていないファイルにアクセスしようとして、セキュリティ例外が発生。
Exception in thread "main" java.security.AccessControlException: access denied ("java.io.FilePermission" "<<ALL FILES>>" "execute")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:457)
at java.security.AccessController.checkPermission(AccessController.java:884)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.SecurityManager.checkExec(SecurityManager.java:799)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1018)
at java.lang.Runtime.exec(Runtime.java:620)
なお、デシリアライズ時に悪意あるコード(OSコマンドなどの外部プロセス)が実行された場合、Javaアプリケーションを実行しているユーザの権限で実行される。OSレベルでの対策として、アプリケーションの実行ユーザに対してアプリケーションの実行に必要な最小限の権限のみ与えることで、意図しないオブジェクトがデシリアライズされ、悪意あるコードが実行された場合においても、システムへの影響を軽減できる場合がある。
シリアライズデータを保護する
シリアライズデータを外部から受け取っている場合、盗聴や改ざんを受ける可能性がある。シリアライズデータにはクラスやオブジェクトの情報などが含まれるため、シリアライズデータをやりとりする通信を傍受するなどにより、攻撃に有用な情報を入手される可能性がある。外部(特にインターネット)から受け取ったデータをデシリアライズする場合は、オブジェクトの正当性、機密性を保証するために、シリアライズ対象オブジェクトに署名後、暗号化を行うことも有効な対策となる。詳細はセキュアコーディングスタンダードSER02-Jを参照のこと。また、シリアライズデータをやりとりする通信を認証や暗号化で保護することも対策の一つとして考えられる。
おわりに
昨年11月に話題となったApache Commons Collectionsライブラリの脆弱性と攻撃手法を踏まえ、外部から受け取ったデータをデシリアライズする際に発生し得るセキュリティ上の問題とその対策についての解説を行った。
シリアライズデータを受け取るサービスがインターネットに公開されており、認証なしでアクセスできる場合は特に注意が必要だ。可能であれば、信頼できない接続元からアクセスできないように制限することをお勧めする。また、認証を行っていても、ID/パスワードが弱い場合は、突破されてしまう可能性があるので、ID/パスワードの見直しをご検討いただきたい。
信頼できないデータのデシリアライズに関する脆弱性は、共通脆弱性タイプ(CWE)ではCWE-502(Deserialization of Untrusted Data)として定義されており、過去の例では、本記事で解説したCommons Collectionsライブラリの脆弱性の他、CVE-2012-0507 AtomicReferenceArrayクラスにおけるデシリアライズに関する脆弱性などが該当する。また、Java以外にもRuby、PHP、Pythonなどの言語仕様に起因して発生し得る脆弱性であり、この機会に、アプリケーションがセキュアな実装になっているかをご確認いただければと思う。
参考情報
-
Look-ahead Java deserialization
サブタイトル:How to secure deserialization from untrusted input without using encryption or sealing。 -
commons-collectionsのInvokerTransformer脆弱性について
上記記事では、Commons Collectionsライブラリを悪用した攻撃の仕組みを簡略化したサンプルコードを使って、LazyMapからInvokerTransformerを呼び出し、Gadget Chainを使って任意のコードを実行する仕組みを分かりやすく説明している。 - シリアル化と情報漏洩
