webentwicklung-frage-antwort-db.com.de

Bewährte Methode zum Speichern und Schützen von privaten API-Schlüsseln in Anwendungen

Die meisten App-Entwickler werden einige Bibliotheken von Drittanbietern in ihre Apps integrieren. Wenn Sie auf einen Dienst wie Dropbox oder YouTube zugreifen oder Abstürze protokollieren möchten. Die Anzahl der Bibliotheken und Dienste von Drittanbietern ist enorm. Die meisten dieser Bibliotheken und Dienste werden durch eine Authentifizierung mit dem Dienst integriert. Meistens geschieht dies über einen API-Schlüssel. Aus Sicherheitsgründen generieren Dienste in der Regel einen öffentlichen und einen privaten, häufig auch als geheim bezeichneten Schlüssel. Um eine Verbindung zu den Diensten herzustellen, muss dieser private Schlüssel leider zur Authentifizierung verwendet werden und ist daher wahrscheinlich Teil der Anwendung. Unnötig zu erwähnen, dass dies ein immenses Sicherheitsproblem darstellt. Öffentliche und private API-Schlüssel können in wenigen Minuten aus APKs extrahiert und problemlos automatisiert werden.

Angenommen, ich habe etwas Ähnliches, wie kann ich den geheimen Schlüssel schützen:

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

}

Was ist Ihrer Meinung nach die beste und sicherste Art, den privaten Schlüssel zu speichern? Verschleierung, Verschlüsselung, was denkst du?

329
Basic Coder
  1. So wie es ist, enthält Ihre kompilierte Anwendung die Schlüsselzeichenfolgen, aber auch die Konstantennamen APP_KEY und APP_SECRET. Das Extrahieren von Schlüsseln aus einem solchen selbstdokumentierenden Code ist beispielsweise mit dem Standard-Tool Android dx.

  2. Sie können ProGuard anwenden. Die Tastenkombinationen bleiben unverändert, die konstanten Namen werden jedoch entfernt. Außerdem werden Klassen und Methoden mit kurzen, bedeutungslosen Namen umbenannt, wo immer dies möglich ist. Das Extrahieren der Schlüssel nimmt dann etwas mehr Zeit in Anspruch, um herauszufinden, welche Zeichenfolge welchem ​​Zweck dient.

    Beachten Sie, dass das Einrichten von ProGuard nicht so schwierig sein sollte, wie Sie befürchten. Zunächst müssen Sie nur ProGuard aktivieren, wie in project.properties dokumentiert. Wenn Probleme mit Bibliotheken von Drittanbietern auftreten, müssen Sie möglicherweise einige Warnungen in der Datei proguard-project.txt unterdrücken und/oder verhindern, dass sie verschleiert werden. Zum Beispiel:

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

    Dies ist ein Brute-Force-Ansatz; Sie können diese Konfiguration verfeinern, sobald die verarbeitete Anwendung funktioniert.

  3. Sie können die Zeichenfolgen in Ihrem Code manuell verschleiern, z. B. mit einer Base64-Codierung oder vorzugsweise mit etwas Komplizierterem. Vielleicht sogar nativer Code. Ein Hacker muss dann Ihre Kodierung statisch rückentwickeln oder die Dekodierung dynamisch an der richtigen Stelle abfangen.

  4. Sie können einen kommerziellen Verschleierer wie ProGuards spezialisiertes Geschwister DexGuard anwenden. Es kann zusätzlich die Zeichenfolgen und Klassen für Sie verschlüsseln/verschleiern. Das Herausziehen der Schlüssel kostet dann noch mehr Zeit und Sachkenntnis.

  5. Möglicherweise können Sie Teile Ihrer Anwendung auf Ihrem eigenen Server ausführen. Wenn Sie die Schlüssel dort aufbewahren können, sind sie sicher.

Am Ende müssen Sie einen wirtschaftlichen Kompromiss eingehen: Wie wichtig sind die Schlüssel, wie viel Zeit oder Software können Sie sich leisten, wie anspruchsvoll sind die Hacker, die an den Schlüsseln interessiert sind, und wie viel Zeit sie möchten Geben Sie aus, wie viel Wert eine Verzögerung ist, bevor die Schlüssel gehackt werden, in welchem ​​Umfang erfolgreiche Hacker die Schlüssel verteilen usw. Kleine Informationen wie Schlüssel sind schwieriger zu schützen als ganze Anwendungen. Eigentlich ist nichts auf der Client-Seite unzerbrechlich, aber Sie können die Messlatte sicherlich höher legen.

(Ich bin der Entwickler von ProGuard und DexGuard)

321
Eric Lafortune

Nur wenige Ideen geben meiner Meinung nach eine Garantie:

  1. Bewahren Sie Ihre Geheimnisse auf einem Server im Internet auf und greifen Sie sie bei Bedarf zu. Wenn der Benutzer Dropbox verwenden möchte, hindert Sie nichts daran, eine Anfrage an Ihre Site zu richten und Ihren geheimen Schlüssel zu erhalten.

  2. Geben Sie Ihre Geheimnisse in den JNI-Code ein und fügen Sie einen variablen Code hinzu, um Ihre Bibliotheken größer und schwieriger zu dekompilieren. Sie können die Schlüsselkette auch in einige Teile teilen und an verschiedenen Stellen aufbewahren.

  3. verwende den Obfuscator, gib ihn auch in das geheime Code-Hash ein und hebe ihn später bei Bedarf auf.

  4. Legen Sie Ihren geheimen Schlüssel als letzte Pixel eines Ihrer Bilder in Assets ab. Dann, wenn nötig, lesen Sie es in Ihrem Code. Das Verschleiern Ihres Codes sollte dazu beitragen, den Code, der ihn liest, auszublenden.

Wenn Sie einen kurzen Blick darauf werfen möchten, wie einfach es ist, Ihren apk-Code zu lesen, dann greifen Sie zu APKAnalyser:

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

72
marcinj

Ein anderer Ansatz besteht darin, das Geheimnis überhaupt nicht auf dem Gerät zu haben! Siehe Mobile API Security Techniques (insbesondere Teil 3).

Teilen Sie das Geheimnis zwischen Ihrem API-Endpunkt und einem App-Authentifizierungsdienst.

Wenn Ihr Client einen API-Aufruf ausführen möchte, fordert er den App-Authentifizierungsdienst auf, ihn zu authentifizieren (mithilfe starker Remote-Attestierungstechniken), und er erhält eine zeitlich begrenzte Bestätigung (normalerweise [~ # ~] jwt [~ # ~] ) Token, das vom Geheimnis signiert wurde.

Das Token wird bei jedem API-Aufruf gesendet, bei dem der Endpunkt seine Signatur überprüfen kann, bevor er auf die Anforderung reagiert.

Das eigentliche Geheimnis ist nie auf dem Gerät vorhanden; Tatsächlich hat die App keine Ahnung, ob sie gültig ist oder nicht, fordert keine Authentifizierung an und leitet das resultierende Token weiter. Wenn Sie das Geheimnis ändern möchten, können Sie dies tun, ohne dass Benutzer ihre installierten Apps aktualisieren müssen.

Wenn Sie also Ihr Geheimnis schützen möchten, ist es ein guter Weg, es überhaupt nicht in Ihrer App zu haben.

21
Skip Hovsmith

Befolgen Sie drei einfache Schritte, um API/Secret Key zu sichern

Wir können Gradle verwenden, um den API-Schlüssel oder den geheimen Schlüssel zu sichern.

1. gradle.properties (Projekteigenschaften): Variable mit Schlüssel erstellen.

GoolgeAPIKey = "Your API/Secret Key"

2. build.gradle (Modul: app): Setzen Sie die Variable in build.gradle, um in Aktivität oder Fragment darauf zuzugreifen. Fügen Sie den folgenden Code zu buildTypes {} hinzu.

buildTypes.each {
    it.buildConfigField 'String', 'GoogleSecAPIKEY', GoolgeAPIKey
}

3. Greifen Sie in Aktivität/Fragment mit der BuildConfig der App darauf zu:

BuildConfig.GoogleSecAPIKEY

Update:

Die obige Lösung ist hilfreich für das Open Source-Projekt, um ein Commit über Git durchzuführen. (Danke an David Rawson und riyaz-ALi für Ihren Kommentar).

Laut den Kommentaren von Matthew und Pablo Cegarra ist der obige Weg nicht sicher und der Decompiler ermöglicht es jemandem, die BuildConfig mit unseren geheimen Schlüsseln anzusehen.

Lösung:

Wir können NDK verwenden, um API-Schlüssel zu sichern. Wir können Schlüssel in der nativen C/C++ - Klasse speichern und in unseren Java - Klassen darauf zugreifen.

Bitte folgen Sie this blog, um API-Schlüssel mit NDK zu sichern.

Ein Follow-up zum sicheren Speichern von Tokens in Android

19
SANAT

Eine mögliche Lösung besteht darin, die Daten in Ihrer App zu verschlüsseln und zur Laufzeit zu dekodieren (wenn Sie diese Daten verwenden möchten). Ich empfehle auch, progaurd zu verwenden, um das Lesen und Verstehen des dekompilierten Quellcodes Ihrer App zu erschweren. Zum Beispiel habe ich einen verschlüsselten Schlüssel in die App eingefügt und dann eine Dekodierungsmethode in meiner App verwendet, um meine geheimen Schlüssel zur Laufzeit zu dekodieren:

// "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=="));
}

Der dekompilierte Quellcode einer proguarded App lautet wie folgt:

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

Zumindest ist es kompliziert genug für mich. Das mache ich, wenn ich keine andere Wahl habe, als einen Wert in meiner Anwendung zu speichern. Natürlich wissen wir alle, dass es nicht der beste Weg ist, aber es funktioniert für mich.

/**
 * @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";
}

Dekompilierte Version:

 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";
      }
    }
  }

und Sie können so viele Verschlüsselungsklassen mit einer kleinen Suche in Google finden.

13
Milad Faridnia

Der App-Secret-Schlüssel sollte vertraulich behandelt werden. Wenn Sie die App freigeben, können Sie jedoch von einigen Personen umgekehrt werden.

für die jungs wird es sich nicht verstecken, sperren sie entweder den ProGuard code. Es ist ein Refactor und einige bezahlte Obfuscatoren fügen ein paar bitweise Operatoren ein, um das jk433g34hg3 String. Sie können das Hacken um 5-15 Minuten verlängern, wenn Sie 3 Tage arbeiten :)

Der beste Weg ist, es so zu belassen, wie es ist, imho.

Selbst wenn Sie auf dem Server (Ihrem PC) speichern, kann der Schlüssel gehackt und ausgedruckt werden. Vielleicht dauert das am längsten? Trotzdem ist es im besten Fall eine Frage von wenigen Minuten oder ein paar Stunden.

Ein normaler Benutzer dekompiliert Ihren Code nicht.

10
user529543

Als Ergänzung zur @Manohar Reddy-Lösung kann die Firebase-Datenbank oder die Firebase-RemoteConfig (mit dem Standardwert Null) verwendet werden:

  1. Chiffriere deine Schlüssel
  2. Speichern Sie es in der Firebase-Datenbank
  3. Holen Sie es sich während des App-Starts oder wann immer erforderlich
  4. entschlüsseln und verwenden

Was ist bei dieser Lösung anders?

  • keine Anmeldeinformationen für Firebase
  • der Firebase-Zugriff ist geschützt, sodass nur Apps mit signiertem Zertifikat zum Ausführen von API-Aufrufen berechtigt sind
  • chiffrierung/Entschlüsselung, um das Abfangen durch den Mittelmann zu verhindern. Ruft aber schon https zur firebase auf
10
Ayman Al-Absi

Dieses Beispiel hat verschiedene Aspekte. Ich werde einige Punkte erwähnen, von denen ich glaube, dass sie nicht explizit an anderer Stelle behandelt wurden.

Das Geheimnis während des Transports schützen

Als Erstes müssen Sie beim Zugriff auf die Dropbox-API über den App-Authentifizierung -Mechanismus Ihren Schlüssel und Ihr Geheimnis übermitteln. Die Verbindung ist HTTPS, was bedeutet, dass Sie den Datenverkehr nicht abfangen können, ohne das TLS-Zertifikat zu kennen. Dies soll verhindern, dass eine Person die Pakete auf ihrer Reise vom Mobilgerät zum Server abfängt und liest. Für normale Benutzer ist es eine wirklich gute Möglichkeit, die Privatsphäre ihres Datenverkehrs zu gewährleisten.

Was es nicht gut kann, ist zu verhindern, dass eine böswillige Person die App herunterlädt und den Datenverkehr überprüft. Es ist wirklich einfach, einen Man-in-the-Middle-Proxy für den gesamten Datenverkehr auf und von einem mobilen Gerät zu verwenden. In diesem Fall ist aufgrund der Art der Dropbox-API kein Disassemblieren oder Reverse Engineering des Codes erforderlich, um den App-Schlüssel und das Geheimnis zu extrahieren.

Sie können Pinning ausführen, um zu überprüfen, ob das vom Server empfangene TLS-Zertifikat das erwartete ist. Dies fügt dem Client eine Überprüfung hinzu und erschwert das Abfangen des Datenverkehrs. Dies würde es schwieriger machen, den Verkehr im Flug zu überprüfen, aber die Pinning-Prüfung findet im Client statt, sodass es wahrscheinlich immer noch möglich ist, den Pinning-Test zu deaktivieren. Es macht es allerdings schwieriger.

Das Geheimnis in Ruhe schützen

In einem ersten Schritt hilft die Verwendung von proguard , die Aufdeckung von Geheimnissen zu verringern. Sie können den NDK auch verwenden, um den Schlüssel und das Geheimnis zu speichern und Anforderungen direkt zu senden, wodurch die Anzahl der Personen mit den entsprechenden Fähigkeiten zum Extrahieren der Informationen erheblich verringert wird. Eine weitere Verschleierung kann erreicht werden, indem die Werte nicht für längere Zeit direkt im Speicher gespeichert werden. Sie können sie kurz vor der Verwendung verschlüsseln und entschlüsseln, wie in einer anderen Antwort vorgeschlagen.

Weitere Optionen

Wenn Sie jetzt paranoid sind, das Geheimnis irgendwo in Ihre App zu stecken, und Sie Zeit und Geld haben, um in umfassendere Lösungen zu investieren, sollten Sie die Anmeldeinformationen auf Ihren Servern speichern (vorausgesetzt, Sie haben welche). Dies würde die Latenz von Aufrufen an die API erhöhen, da diese über Ihren Server kommunizieren muss, und könnte die Kosten für die Ausführung Ihres Dienstes aufgrund eines erhöhten Datendurchsatzes erhöhen.

Anschließend müssen Sie entscheiden, wie Sie am besten mit Ihren Servern kommunizieren, um sicherzustellen, dass diese geschützt sind. Dies ist wichtig, um zu verhindern, dass bei Ihrer internen API dieselben Probleme erneut auftreten. Die beste Faustregel, die ich geben kann, ist, wegen der Bedrohung durch den Mann in der Mitte kein Geheimnis direkt zu übermitteln. Stattdessen können Sie den Datenverkehr mithilfe Ihres Geheimnisses signieren und die Integrität aller Anforderungen überprüfen, die an Ihren Server gesendet werden. Eine Standardmethode besteht darin, eine HMAC der Nachricht zu berechnen, die in einem Geheimnis verschlüsselt ist. Ich arbeite in einem Unternehmen, das ein Sicherheitsprodukt hat, das auch in diesem Bereich tätig ist, weshalb mich solche Dinge interessieren. In der Tat ist hier ein Blog Artikel von einem meiner Kollegen, der das meiste davon behandelt.

Wie viel soll ich tun?

Bei solchen Sicherheitsratschlägen müssen Sie eine Kosten-/Nutzen-Entscheidung treffen, wie schwer es für jemanden sein soll, einzudringen. Wenn Sie eine Bank sind, die Millionen von Kunden schützt, unterscheidet sich Ihr Budget grundlegend von denen, die eine App in ihrem Budget unterstützen Freizeit. Es ist praktisch unmöglich, jemanden daran zu hindern, Ihre Sicherheit zu gefährden, aber in der Praxis benötigen nur wenige Menschen alle Schnickschnack, und mit einigen grundlegenden Vorsichtsmaßnahmen können Sie einen langen Weg zurücklegen.

9
ThePragmatist

Die sicherste Lösung besteht darin, Ihre Schlüssel auf einem Server zu belassen und alle Anforderungen, die diesen Schlüssel benötigen, über Ihren Server weiterzuleiten. Auf diese Weise verlässt der Schlüssel niemals Ihren Server. Solange Ihr Server sicher ist, verlässt er auch Ihren Schlüssel nicht. Natürlich sind mit dieser Lösung auch Kosten für die Leistung verbunden.

8
Bernard Igiri

Alter alter Beitrag, aber immer noch gut genug. Ich denke, es wäre großartig, es in einer .so-Bibliothek zu verstecken, natürlich unter Verwendung von NDK und C++. .so-Dateien können in einem Hex-Editor angezeigt werden

4
Ahmed Awad

Was auch immer Sie tun, um Ihre geheimen Schlüssel zu sichern, wird keine echte Lösung sein. Wenn der Entwickler die Anwendung dekompilieren kann, gibt es keine Möglichkeit, den Schlüssel zu sichern. Das Verbergen des Schlüssels ist nur eine Sicherheitsmaßnahme, die nur im Dunkeln liegt, und ebenso die Verschleierung des Codes. Das Problem beim Sichern eines geheimen Schlüssels besteht darin, dass Sie zum Sichern einen anderen Schlüssel verwenden müssen und dieser Schlüssel auch gesichert werden muss. Stellen Sie sich einen Schlüssel vor, der in einer Box versteckt ist, die mit einem Schlüssel verschlossen ist. Sie stellen eine Kiste in einen Raum und schließen den Raum ab. Sie haben noch einen anderen Schlüssel zum Sichern. Und dieser Schlüssel wird in Ihrer Anwendung immer noch fest codiert.

Es gibt also keine Möglichkeit, den Schlüssel zu verbergen, es sei denn, der Benutzer gibt eine PIN oder eine Phrase ein. Um dies zu tun, müssten Sie ein Schema für die Verwaltung von PINs haben, die außerhalb des Bandes stattfinden, dh durch ein anderer Kanal. Sicherlich nicht praktisch für das Sichern von Schlüsseln für Dienste wie Google APIs.

4
user1611728

Behalte das Geheimnis in firebase database und beim Starten der App erhalten, ist es weitaus besser als einen Webdienst aufzurufen.

4
Manohar Reddy

Die einzig wahre Möglichkeit, diese privat zu halten, besteht darin, sie auf Ihrem Server zu belassen und die App so zu senden, wie sie ist, und der Server interagiert mit Dropbox. Auf diese Weise verteilen Sie Ihren privaten Schlüssel NIEMALS in irgendeinem Format.

3
Nick

Aus bitterer Erfahrung und nach Rücksprache mit einem IDA-Pro-Experten besteht die beste Lösung darin, einen wichtigen Teil des Codes in eine DLL/ein SharedObject zu verschieben, ihn dann von einem Server abzurufen und zur Laufzeit zu laden.

Sensible Daten müssen verschlüsselt werden, da dies sehr einfach ist:

$ strings libsecretlib.so | grep My
  [email protected]$$W0rD
2
RonTLV