433

ほとんどのアプリ開発者は、いくつかのサードパーティ ライブラリをアプリに統合します。Dropbox や YouTube などのサービスにアクセスする場合、またはクラッシュを記録する場合。サードパーティのライブラリとサービスの数は驚異的です。これらのライブラリとサービスのほとんどは、何らかの方法でサービスを認証することによって統合されます。ほとんどの場合、これは API キーを介して行われます。セキュリティ上の目的で、サービスは通常、秘密鍵とも呼ばれる公開鍵と秘密鍵を生成します。残念ながら、サービスに接続するには、この秘密鍵を認証に使用する必要があるため、おそらくアプリケーションの一部になっています。言うまでもなく、これは巨大なセキュリティ問題に直面しています。公開および秘密 API キーは APK から数分で抽出でき、簡単に自動化できます。

これに似たものがあると仮定すると、秘密鍵を保護するにはどうすればよいですか。

public class DropboxService  {

    private final static String APP_KEY = "jk433g34hg3";
    private final static String APP_SECRET = "987dwdqwdqw90";
    private final static AccessType ACCESS_TYPE = AccessType.DROPBOX;

    // SOME MORE CODE HERE

}

秘密鍵を保管するための最善かつ最も安全な方法は何だと思いますか? 難読化、暗号化、どう思いますか?

4

13 に答える 13

389
  1. そのままでは、コンパイルされたアプリケーションにはキー文字列が含まれていますが、定数名の APP_KEY と APP_SECRET も含まれています。このような自己文書化コードからキーを抽出するのは簡単です。たとえば、標準の Android ツール dx を使用します。

  2. ProGuard を適用できます。キー文字列はそのまま残りますが、定数名は削除されます。また、可能な限り、クラスとメソッドの名前を短くて意味のない名前に変更します。キーの抽出には、どの文字列がどの目的に役立つかを理解するために、さらに時間がかかります。

    ProGuard の設定は、恐れるほど難しくはないことに注意してください。まず、project.properties に記載されているように、ProGuard を有効にするだけで済みます。サードパーティのライブラリに問題がある場合は、proguard-project.txt でいくつかの警告を抑制したり、難読化されないようにする必要がある場合があります。例えば:

    -dontwarn com.dropbox.**
    -keep class com.dropbox.** { *; }
    

    これは強引なアプローチです。処理されたアプリケーションが機能したら、そのような構成を調整できます。

  3. コード内で文字列を手動で難読化できます。たとえば、Base64 エンコーディングを使用するか、できればより複雑なものを使用します。たぶんネイティブコードです。ハッカーは、エンコードを静的にリバース エンジニアリングするか、適切な場所で動的にデコードを傍受する必要があります。

  4. ProGuard の特殊な兄弟である DexGuardなどの市販の難読化ツールを適用できます。さらに、文字列とクラスを暗号化/難読化できます。鍵の抽出には、さらに多くの時間と専門知識が必要です。

  5. アプリケーションの一部を独自のサーバーで実行できる場合があります。そこに鍵を保管できれば、安全です。

結局のところ、それはあなたがしなければならない経済的なトレードオフです: 鍵がどれほど重要か、どれだけの時間またはソフトウェアに余裕があるか、鍵に興味を持っているハッカーがどれほど洗練されているか、どれだけの時間を欲しがるかです。キーがハッキングされるまでの遅延の価値、成功したハッカーがキーを配布する規模など。キーのような小さな情報は、アプリケーション全体よりも保護が困難です。本質的に、クライアント側で壊れないものは何もありませんが、確実にバーを上げることができます。

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

于 2013-01-28T22:01:22.783 に答える
89

私の意見では、最初のアイデアだけがいくつかの保証を提供します。

  1. インターネット上のサーバーに秘密を保管し、必要なときにそれらを取得して使用します。ユーザーがドロップボックスを使用しようとしている場合、サイトにリクエストを送信して秘密鍵を取得することを妨げるものは何もありません。

  2. シークレットを jni コードに入れ、変数コードを追加して、ライブラリを大きくし、逆コンパイルをより困難にします。キー文字列をいくつかの部分に分割して、さまざまな場所に保管することもできます。

  3. 難読化ツールを使用し、ハッシュ化された秘密のコードを入れて、後で使用する必要があるときにハッシュを解除します。

  4. アセット内の画像の 1 つの最後のピクセルとして秘密鍵を配置します。次に、必要に応じてコードで読み取ります。コードを難読化すると、それを読み取るコードを隠すのに役立ちます。

apk コードの読み取りがいかに簡単かを簡単に確認したい場合は、APKAnalyser を取得します。

http://developer.sonymobile.com/knowledge-base/tool-guides/analyse-your-apks-with-apkanalyser/

于 2013-01-28T21:07:01.827 に答える
16

App-Secret キーは非公開にしておく必要がありますが、アプリをリリースするときに何人かによって元に戻される可能性があります。

それらの人のために、それは隠されませんProGuard。コードのいずれかをロックしてください。これはリファクタリングであり、一部の有償の難読化ツールは、jk433g34hg3 文字列を取得するためにいくつかのビット演算子を挿入しています。3 日間作業すれば、ハッキングを 5 ~ 15 分長くすることができます :)

最善の方法は、そのままにしておくことです。

サーバー側(PC)に保存しても、キーがハッキングされて印刷される可能性があります。もしかしてこれが一番時間かかる?とにかく、せいぜい数分または数時間の問題です。

通常のユーザーはコードを逆コンパイルしません。

于 2013-01-28T20:54:41.890 に答える
15

考えられる解決策の 1 つは、アプリでデータをエンコードし、実行時に (そのデータを使用する場合) デコードを使用することです。アプリの逆コンパイルされたソース コードを読みにくく、理解しにくくするために、progaurd を使用することもお勧めします。たとえば、アプリにエンコードされたキーを配置し、アプリでデコード メソッドを使用して、実行時に秘密キーをデコードしました。

// "the real string is: "mypassword" "; 
//encoded 2 times with an algorithm or you can encode with other algorithms too
public String getClientSecret() {
    return Utils.decode(Utils
            .decode("Ylhsd1lYTnpkMjl5WkE9PQ=="));
}

プロガードされたアプリの逆コンパイルされたソース コードは次のとおりです。

 public String c()
 {
    return com.myrpoject.mypackage.g.h.a(com.myrpoject.mypackage.g.h.a("Ylhsd1lYTnpkMjl5WkE9PQ=="));
  }

少なくとも私にとっては十分に複雑です。これは、アプリケーションに値を格納する以外に選択肢がない場合に行う方法です。もちろん、それが最善の方法ではないことは誰もが知っていますが、私にとってはうまくいきます。

/**
 * @param input
 * @return decoded string
 */
public static String decode(String input) {
    // Receiving side
    String text = "";
    try {
        byte[] data = Decoder.decode(input);
        text = new String(data, "UTF-8");
        return text;
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return "Error";
}

逆コンパイルされたバージョン:

 public static String a(String paramString)
  {
    try
    {
      str = new String(a.a(paramString), "UTF-8");
      return str;
    }
    catch (UnsupportedEncodingException localUnsupportedEncodingException)
    {
      while (true)
      {
        localUnsupportedEncodingException.printStackTrace();
        String str = "Error";
      }
    }
  }

Google で少し検索するだけで、非常に多くの暗号化クラスを見つけることができます。

于 2016-06-18T10:11:54.680 に答える
7

最も安全な解決策は、キーをサーバーに保持し、そのキーを必要とするすべてのリクエストをサーバー経由でルーティングすることです。そうすれば、キーがサーバーから離れることはありません。そのため、サーバーが安全である限り、キーも安全です。もちろん、このソリューションにはパフォーマンス コストがかかります。

于 2016-09-24T15:41:13.317 に答える
7

秘密鍵を保護するために何をしても、本当の解決策にはなりません。開発者がアプリケーションを逆コンパイルできる場合、キーを保護する方法はありません。キーを隠すことは、あいまいさによるセキュリティにすぎず、コードの難読化も同様です。秘密鍵の保護に関する問題は、秘密鍵を保護するために別の鍵を使用する必要があり、その鍵も保護する必要があることです。鍵でロックされた箱に隠された鍵を考えてみてください。部屋の中に箱を置き、部屋に鍵をかけます。安全のための別の鍵が残っています。そして、そのキーは引き続きアプリケーション内でハードコーディングされます。

したがって、ユーザーが PIN またはフレーズを入力しない限り、キーを非表示にする方法はありません。しかし、それを行うには、帯域外で発生する PIN を管理するためのスキームが必要になります。つまり、別のチャネルを介することになります。確かに、Google API などのサービスのキーを保護するには実用的ではありません。

于 2016-12-15T16:27:44.127 に答える