web-dev-qa-db-ja.com

アプリ内課金を行うときにGoogle Play公開キーを保護する方法

実際、これは公開鍵の保護について少しばかげています(そのときの公開鍵の定義は何ですか?)が Googleによるドキュメント によると:

悪意のあるユーザーやハッカーから公開鍵を保護するために、リテラル文字列としてコードに埋め込まないでください。代わりに、実行時に文字列を断片から構築するか、ビット操作(たとえば、XORと他の文字列を使用)を使用して実際のキーを非表示にします。キー自体は秘密情報ではありませんが、ハッカーや悪意のあるユーザーが公開鍵を別の鍵に簡単に置き換えられるようにしたい。

それを行うための推奨される方法はありますか?

私はそれを行う方法がたくさんあることを知っています、私は人々が過去にパスワードハッシュを処理する方法と同じ方法に従いたくありません(例えばmd5 、sha1など)、上記の使用例のベストプラクティスを知りたいです。

42
Ryan

これはここでよく出てきます:)あなたが引用している段落の背後にある考えは、アプリ内課金を安全にするために、トランザクションの署名を検証する必要があるということです。これらは、開発者アカウントに関連付けられた秘密鍵で署名されています。キーはGoogleのサーバーに常駐しているため、他の誰もキーでデータに署名できないと考えるのはかなり安全です。それを確認するには、開発者コンソールからコピーできる公開鍵が必要です。誰かがアプリでそれを置き換えた場合、不正なソースからのアプリ内課金トランザクションを受け入れるためにだまされる可能性があります。公開鍵を植え付けた場合、おそらく対応する秘密鍵も制御するためです。ただし、実際には、適切な場所でコードを変更するだけで、isLicensed()hasItem()などのメソッドで常にtrueを返し、誰もこれを行わない方がはるかに簡単です。

もちろん、キーを保護する最善の方法は、アプリにキーを一切含めないことです。すべてのトランザクション検証ロジックをサーバーに移動し、HTTPSを使用してそれに接続します。証明書チェーンを適切に検証して、自分のサーバーと通信していることを確認します。そうしないと、誰かがDNSをいじってアプリをだまして自分のサーバーに接続する可能性があります。 iOSの購入に対する同様の攻撃が数週間前に発表されました。

次善の策は、何らかの方法でキーを難読化し、アプリに含めることです。これにはサーバーが必要ないという利点がありますが、不利な点は、誰かが十分に決まっている場合、常にアプリのバイトコードを逆にすることができるため、それを理解できるということです。したがって、最善の策は、パブリックフォーラムに表示されない独自の独自の方法を考え出すことです。それを少し難しくするために、検証部分をネイティブコードで実装することができます。不可能)分析する。それでも、上記のように、適切な場所にバイトコードをパッチすることは、公開鍵を置き換えることよりもはるかに簡単なので、それがほとんどのクラッカーが行うことです。

38
Nikolay Elenkov

少なくとも単純なテキスト変換を行います。単純なdexを分解しても公開鍵は明らかにならないという考えです。

簡単な文字列のエンコード/デコードを行う関数の例を次に示します。

/**
 * Simple String transformation by XOR-ing all characters by value.
 */
static String stringTransform(String s, int i) {
   char[] chars = s.toCharArray();
   for(int j = 0; j<chars.length; j++)
      chars[j] = (char)(chars[j] ^ i);
   return String.valueOf(chars);
}

次に、秘密鍵はエンコードされた文字列(この関数でエンコード)としてソースに保存され、同じ関数で実行時にデコードされます。これは、Googleが提案する「XOR」方式の一種です。

'i'パラメータを自分で作成すると、0x27などのランダムなものが機能します。この方法でより多くの文字列を非表示にする場合は、変換ごとに異なる「i」を使用します。

32
Pointer Null

キーを手動で難読化する代わりに、難読化ツールに自動的に難読化させることもできます。 ProGuard はAndroid SDKの一部ですが、ほとんどの場合、文字列ではなくクラス/フィールド/メソッド名を難読化します。Android専用の兄弟、 DexGuard は、難読化の層をさらに追加し、文字列の暗号化、クラスの暗号化、およびリフレクションを適用できます。これは無料ではありませんが、時間を節約でき、おそらく手動で行うよりも効果的です。

(私はProGuardとDexGuardの開発者です)

11
Eric Lafortune

公開鍵をサーバー側に保存し、Google Playから応答を受け取ったら、キーがサーバーに応答を送信し、サーバーで操作を実行することを確認します。

4
skygeek

公開鍵はbase64でエンコードされています([a-zA-Z0-9+/])@PointerNullのソリューションの厄介な問題であるように、難読化された文字列をエスケープする必要を簡単に回避できます。

代わりに、まず問題の文字を6ビットのintに変換することで難読化を実行できます。次に、ビット操作(XOR処理など)を実行し、base64でエンコードされたcharに変換します。文字のエスケープが不要であることを保証します。

1
darrenp