2012年2月20日月曜日

難読化していないAndroidアプリケーションは脆弱性か

このエントリでは、Androidアプリケーションにおいて、難読化が施されていない場合、脆弱性にあたるかについて議論します。

はじめに

Androidアプリケーションは主にJava言語で記述され、DEX形式のファイルにコンパイルされたコードを、DalvikというJava互換VM上で実行します。DEXおよびAPKファイルの仕様は公開されており、DEXにはクラスやメソッド等のシンボル名も含まれているため、リバースエンジニアリングが容易であると言われています。このため、Android SDKには標準でProGuardという難読化ツールが添付されています。
それでは、難読化の目的はそもそも何で、難読化でその目的は達成されるのでしょうか。

難読化の目的

Webアプリケーションの場合は、重要なロジックは主にサーバー側に存在するため、ソースコードを外部から取得することはできません。これに対して、スマートフォンアプリケーションの場合は、実行プログラムが手元の端末上にあるため、リバースエンジニアリングにより、(手間の大小はともかく)ソースコードを再現させることが可能です。
リバースエンジニアリングに対抗するために、プログラムを解析しにくくする行為を難読化と呼びます。
難読化の典型的な目的を以下に示します。

  • アプリケーションロジックの流出防止
  • 内部の隠れた脆弱性の発見防止
  • 課金コードの改変による不正利用の防止
  • アプリケーションの不正流用の防止
  • 暗号鍵など秘密情報の漏洩防止

ProGuardとは

ProGuardとは、Android SDKに標準で添付される難読化ツールです。ProGuardには複数の機能がありますか、難読化に寄与するものとしては、クラスやメソッドの名前の付け替え(連番のような形になる)があります。
クラス名やメソッド名から意味がわからなくなるため、リバースエンジニアリングがしにくくなることを期待しての機能でしょう。

ProGuardで十分なのか

セキュリティの専門家の立場から見ると、ProGuardの提供する機能は中途半端です。一般的に、リバースエンジニアリングというと、機械語のバイナリからの解析を指します。職業的にリバースエンジニアリングをしている人たち、例えばウイルス対策ソフトのマルウェア解析担当者は、なんのヒントもないマルウェアのバイナリを解析して、マルウェアの挙動を把握し、パターンファイルを作成しているわけです。最近のマルウェアは、単純な機械語ではなく、加えて難読化が施されていて解析が難しくなっていると言われています。
これに対して、ProGuardの「難読化」の結果は、機械語に比べるとはるかにリバースエンジニアリングが易しいと言えます。シンボルが除去されるとは言え、アプリケーションが利用するライブラリのシンボル名などは除去できないためです。
すなわち、ProGuardの効果は、「very easyをeasyにする」程度のものと言えます。このあたりの感覚については、杉山俊春氏の寄稿記事も参考になります。


商用難読化ツールはどうか

ProGuardはどうももの足りないということであれば、商用難読化ツールというものもあります。以下に、Android向けの商用難読化ツールを紹介します。
※いずれの製品も私自身は評価しておらず、推奨というわけではありません。

一例として、DashOの機能を見てみると、以下のような難読化機能が提供されています。
  • 改ざん検出と通知 
  • 名前の変更
  • 制御フローの難読化
  • 文字列の暗号化
  • バイトコードの最適化
  • ウォーターマーク(出所を追跡可能に)

このうち、名前の変更とバイトーコードの最適化はProGuardにもある機能ですが、これら以外はProGuardにはない機能です。
難読化というからには、この程度はやって欲しい気がしますが、商用難読化ツールは高価(DashOは最小構成で79万円)なため、手軽に導入するわけにはいきません。

ではどうするのがよいか

ProGuardでは頼りない、商用難読化ツールは高価だとすると、どうすればよいのでしょうか。
その答えは、先に紹介した杉山氏の記事タイトル『見せたくないなら「持たせない」が鉄則』だと思います。具体的には、見せたくないリソースやロジックは極力サーバー側に持たせ、スマートフォン側には、入力や表示など最低限の機能に絞ることです。
それでも、なんらかの事情により難読化したい場合はあるでしょうが、以下のように考えればよいでしょう。

  • リバースエンジニアリングによる想定被害金額を見積もる
  • 想定被害金額が商用難読化ツール購入費用よりも大幅に大きければ、商用難読化ツールにより難読化処理する
  • 想定被害金額が大きくなく、費用対効果が見合わない場合は、ProGuard+手動難読化を施す

手動難読化とは私の造語ですが、プログラムロジックを故意に複雑にすることで、リバースエンジニアリングの邪魔をすることです。冗長なコードを挿入したり、文字列をエンコードあるいは暗号化した状態で保持して、アプリケーション内でデコードあるいは復号するなどです(面倒です)。
手動難読化も、あまり期待しない方がよいとは思いますが、ソースコード診断をしていると「まるで難読化されたような」読むのが嫌になるソースコードに出くわすこともしばしばですので、プログラムの下手な人に依頼すると思わぬ効果があるかもしれません(冗談です)。

また、そもそも難読化はリバースエンジニアリングを難しくするものであり、不可能にするものではないので、リバースエンジニアリングによる影響は受容可能にしなければなりません。例えば、リバースエンジニアリングによって、大量の個人情報が漏洩するような設計はダメだと言うことです。


まとめ

以上をまとめると以下のようになります。
  • 難読化するか否かはアプリケーション要件である
  • 難読化が破られリバースエンジニアリングされた場合でも、影響が受容可能であるように設計する
  • 本当に難読化の必要な場合はProGuardでは機能不足であり商用難読化ツールを検討する必要がある
  • 商用難読化ツールは高価なので、導入にあたっては費用対効果の検討が不可欠

ということで、表題の「難読化していないAndroidアプリケーションは脆弱性か」という問の答えは、「一般には脆弱性とは言えず、アプリケーション要件である」が答えだと考えます。


[PR]
3月2日、株式会社DNPデジタルコム主催の「スマートフォン向けセキュリティセミナー」(五反田、無料)で基調講演します。この中で、スマートフォンアプリケーションのセキュリティに関する責任範囲や対策などについて、基礎的なところから説明できればと思います。

スマートフォンアプリケーションのセキュリティ強化策についての相談は、HASHコンサルティング株式会社まで。
安全なWebアプリケーションの作り方DRMフリーのPDFによる電子版もあります。

2012年2月6日月曜日

スマートフォンアプリケーションでSSLを使わないのは脆弱性か

このエントリでは、スマートフォンアプリケーションの通信暗号化の必要性について議論します。

はじめに

先日、スマートフォンアプリケーションのセキュリティに関するセミナーを聴講しました(2月8日追記。講演者からの依頼によりセミナーのサイトへのリンクをもうけました)。この際に、スマートフォンアプリケーションの脅威に対する共通認識がまだないという課題を改めて感じました。その課題を痛感できたという点で、セミナーは私にとっては有益でした。
このため、当ブログではスマートフォンアプリケーションの話題をあまり取り上げていませんでしたが、今後は、とりあげようと思います。まずは、スマートフォンアプリケーションでは暗号化を必須とするべきかという話題です。この話題は、前記セミナーでもとりあげられていました。

暗号化の目的は何か

まず、暗号化の必要性を論じるためには、暗号化の目的を明確にする必要があります。前記セミナーでは、この目的が明確に示されていませんでした。
一般的に、通信を暗号化する目的には、以下の2つの可能性があります。
  • 第三者からのデータ盗聴を防ぐため
  • 第三者だけでなく、アプリ利用者にもデータ通信の内容を見せないため
第三者の盗聴を防ぐ目的にはSSLを使用すればすむことですが、SSLはデータの利用者に通信内容を見せない機能はありません。一般のWebアプリケーションの場合は、通信内容はすべて利用者には開示されるという前提でアプリケーションを開発するので、これでよいわけです。
先のセミナーでは、質疑応答にて、SSLだと利用者には通信内容が見えてしまうので、GET/POSTの内容を見せないような暗号化が望ましいと説明していました。つまり、SSLではなく独自の暗号化ということでしょうが、そうすべき理由は明確に説明されませんでした。

利用者にも通信内容を見せない理由

利用者にも通信内容を見せたくない動機は、悪意の利用者を想定してのことです。この想定自体は妥当です。
では、悪意の利用者のどの行為を防ぎたいのでしょうか。以下の二種類が考えられます。
  • サーバーの脆弱性をついた攻撃
  • ゲームなどで、正規のアプリでは困難なプレイを実現する不正なクライアントの作成
先の講演では、なんとなく前者を目的とした暗号化のように私には聞こえましたが、もしそうであれば、危険な発想です。

「隠すこと」による脆弱性対策は危険

通信内容を隠してしまえば攻撃もできなくなるだろうという発想は危険です。完全に隠し通せるならともかく、完全な隠蔽は困難であるからです。
その理由は、スマートフォンアプリケーションの場合、暗号鍵を隠すことが困難であるからです。アプリケーションのリバースエンジニアリングが可能なので、鍵の保存方式を解析されれば、暗号を破ることができます。このため、アプリの難読化ということをするわけですが、あくまで「難読」であって、「不可読」ではないので、鍵を盗まれる可能性はあります。
このため、サーバー側の脆弱性対策については、Webアプリケーションと同様に「全ての通信内容は把握される」ことを前提として、脆弱性を元から断つことが必須です。

独自の暗号化が必要な場合

一方、ゲームなどのアプリケーションの場合、不正プレイを防止する等の目的で、通信内容を秘匿したいニーズがあります。
この場合も、前述のように、通信方式がばれるリスクはあるわけですが、以下のように考えるとよいでしょう。
  • 通信方式が解読された場合でも、利用者の個人情報などは漏洩しないよう実装する
  • 通信方式が解読された場合に備えて、サーバー側ロジックにも不正プレイ対策を組み込む
  • その上で、独自の暗号化とアプリの難読化を施す
このように、通信方式が解読されても利用者の不利益にならないようにする一方、サイト運営者の不利益が受容可能なレベルになるようにサーバー側で対策します。

独自暗号化のデメリット

一方、独自暗号化にはデメリットはないでしょうか。私は、独自暗号化にはデメリットもあると考えます。
最近のスマートフォンアプリをめぐる話題として、プライバシー情報の不正送信というテーマがあります。このため、アプリ提供者には以下が求められるわけです。
  • アプリの実現に必要最低限のパーミッションを用いる
  • 取得およびサーバー送信するプライバシー情報を開示する
しかし、プライバシー情報を取得できるパーミッションを得ているアプリの場合、送信していないと表明しても、「本当はサーバーにプライバシー情報を送信しているのではないか」という疑念は残ります。
このため、通信内容を監査可能な状態に保つ(SSLのみで暗号化する)ということは、アプリ提供者が身を守る上でも有効だと考えます。上記二項は守った上で、「調べたければいつでもどうぞ」という状態にしておけば、提供側も堂々と構えておけばよいわけです。
一方、利用者当人にも読めない暗号化がしてあると、「本当はプライバシー情報も送信しているのではないか」という疑惑は(パーミッションを外す以外の方法では)ぬぐえません。

スマートフォンアプリにSSL暗号化が要求される本当の理由

先のセミナーでは、スマートフォンアプリが通信を暗号化すべき理由として、従来型携帯電話(フィーチャーフォン、俗に言うガラケー)と比べてWi-Fiでの利用があり得るので、盗聴のリスクが増すからだと説明されていました。この説明自体間違ってはいませんが、もう少し深い理由があると私は考えます。
Webアプリケーションの世界では、SSL暗号化は「望ましい」条件であって必須とまではされていません。その理由は、SSLの使用に費用が掛かるためということもありますが、SSLを使っているかどうかは、ブラウザの錠前マークを見れば一目瞭然であるので、利用者が回線品質に不安があれば、SSL不使用の場合に自分の判断で利用を止めることができるからです。
一方、スマートフォンアプリケーションの場合は、アプリケーションがHTTP平文通信しているのか、HTTPSの暗号化通信を利用しているのかは、一般利用者には分かりません。
このため、今後スマートフォンアプリケーションでは、以下のように考えるとよいと思います。
  • アプリケーションの場合SSL通信しているかどうか利用者には分からないため、通信路をSSL暗号化していない場合にはその旨を告知することが望ましい
  • 告知せず平文通信している場合は、アプリケーションの脆弱性とみなすことを提案します(公開情報のみを通信している場合を除く)
  • 前提として、公衆無線LANには信頼性の低いものがあり、スマートフォンから利用されてしまうリスクが現実的に存在するため

追記(2012/2/8)

twitterで @bulkneets さんからコメントを頂きました。
徳丸さんの、平文で通信するiOSアプリの通信内容が改竄された結果として受信したレスポンスそのまま表示なりして、そのインジェクションされたコードから触れるAPIなりファイルなりが機密データだったら、そのアプリが扱ってる情報と関係なく危険なので公開情報のみ通信してるかどうかは関係ない(リンク)
確かにその通りです。
改ざんされた場合、コードが実行できない場合でも、間違った情報が見えるという時点でセキュリティ上の問題が生じる可能性はありますね。
ということで、「公開情報のみを通信している場合を除く」という但し書きは、大ざっぱな免責条項として書いたものですが、正確ではありません。安全サイドに倒すならば、「平文通信の場合は常に告知せよ、そうでなければ脆弱性」というガイドラインがよいことになります。

まとめ

スマートフォンアプリケーションのセキュリティ全般の話題の後、スマートフォンアプリケーションでは暗号化に対する要求がWebアプリケーションよりも厳しくなる理由を説明しました。
手元のTwitterアプリケーションなどを調べると、平文送信しているものもけっこう見かけます。それらが即脆弱だというほどの共通認識はできていませんが、今後の議論により、アプリの平文通信が脆弱性か否かや、脆弱性と言えるための条件等について、共通認識が得られればと希望します。


スマートフォンアプリケーションのセキュリティ強化策についての相談は、HASHコンサルティング株式会社まで。
安全なWebアプリケーションの作り方DRMフリーのPDFによる電子版もあります。


フォロワー