2016-07-12 9 views
1

Ich baue eine App und möchte ein Feedback über meine Vorgehensweise bei der Erstellung der Datensynchronisierung Prozess und API, die es unterstützt. Für Kontext, das sind die Leitprinzipien für meine App/API:App-API-Design-Beratung speziell rund um Sicherheit

  • Free: Ich möchte nicht die Leute überhaupt die App/API verwenden.
  • Open Source: Der Quellcode sowohl für die App als auch für die API steht der Öffentlichkeit zur Verwendung frei zur Verfügung.
  • Dezentral: Der API-Dienst, der die App unterstützt, kann von jedem Benutzer auf jedem Server ausgeführt und Benutzern der App zur Verfügung gestellt werden.
  • Anonym: Der Benutzer muss sich nicht für den Dienst anmelden oder persönliche Identifikationsdaten angeben, die zusammen mit seinen Daten gespeichert werden.
  • Sicher: Die Daten des Benutzers sollten verschlüsselt werden, bevor sie an den Server gesendet werden, jeder mit Zugriff auf den Server sollte nicht in der Lage sein, die Daten des Benutzers zu lesen.
  • Ich werde eine Instanz der API auf einem öffentlichen Server implementieren, der standardmäßig in der App ausgewählt wird. Auf diese Weise können anfängliche Benutzer der App ihre Daten sofort synchronisieren, ohne eine Instanz des API-Dienstes suchen oder einrichten zu müssen. Wenn die App im Laufe der Zeit populär ist, werden die Benutzer hoffentlich andere Instanzen des API-Dienstes entweder für sich selbst einrichten oder anderen Benutzern der App zur Verfügung stellen, falls sie eine andere Instanz verwenden möchten (oder wenn die primäre Instanz leer ist) Raum, geht nach unten, usw.). Sie können sogar auf die API in ihren eigenen Apps zugreifen. Im Wesentlichen möchte ich, dass sie in der Lage sind, die Wahl zu haben, unabhängig zu sein und sich nicht notwendigerweise darauf verlassen zu müssen, dass andere ihnen aus Gründen der Privatsphäre, Belastbarkeit, Kostenersparnis usw. eine Instanz für den Dienst bereitstellen. Hinweis: die Daten in Frage ist nicht empfindlich (dh finanziell, usw.), aber es ist persönlich.

    Die Sync-Reise arbeitet der Benutzer wie folgt aus:

    1. Benutzer die App herunterlädt, und erstellt ihre Daten in den Prozess der App zu verwenden.
    2. Wenn der Benutzer für die anfängliche Synchronisierung bereit ist, geben sie im Kennwortfeld ein "Kennwort" ein, mit dem ein komplexer Schlüssel zum Verschlüsseln der Daten erstellt wird. Ihr Passwort wird lokal im Klartext gespeichert, aber niemals an den Server gesendet.
    3. Der Benutzer klickt auf die Schaltfläche "Synchronisieren", seine Daten werden verschlüsselt (mithilfe ihres Kennworts) und an die angegebene (oder standardmäßige) API-Instanz gesendet und antworten mit einer eindeutigen ID, die von der App gespeichert wird.
    4. Für zukünftige Synchronisierungen werden ihre Daten lokal mit ihrem gespeicherten Kennwort verschlüsselt, bevor sie zusammen mit ihrer eindeutigen ID, die ihre synchronisierten Daten auf dem Server aktualisiert, an die API gesendet werden.
    5. Beim Abrufen von synchronisierten Daten wird ihre eindeutige ID an die API gesendet, die mit ihren verschlüsselten Daten antwortet. Ihr lokal gespeichertes Passwort wird dann verwendet, um die Daten für die Verwendung durch die App zu entschlüsseln.

    Ich habe die App in Javascript, und die API in Node.js (restify) mit MongoDB als Backend implementiert, so dass in der Praxis eine Sync-Anfragen an den Server wie folgt aussieht:

    1 .Initial Sync

    POST/api/Daten

    Beitrag Körper:

    { 
        "data":"DWCx6wR9ggPqPRrhU4O4oLN5P09onApoAULX4Xt+ckxswtFNH/QQ+Y/RgxdU+8+8/muo4jo/jKnHssSezvjq6aPvYK+EAzAoRmXenAgUwHOjbiAXFqF8gScbbuLRlF0MsTKn/puIyFnvJd..." 
    } 
    

    Antwort:

    { 
        "id":"507f191e810c19729de860ea", 
        "lastUpdated":"2016-07-06T12:43:16.866Z" 
    } 
    

    2. Erhalten Sie Sync-Daten

    GET/api/Daten/507f191e810c19729de860ea

    Antwort:

    { 
        "data":"DWCx6wR9ggPqPRrhU4O4oLN5P09onApoAULX4Xt+ckxswtFNH/QQ+Y/RgxdU+8+8/muo4jo/jKnHssSezvjq6aPvYK+EAzAoRmXenAgUwHOjbiAXFqF8gScbbuLRlF0MsTKn/puIyFnvJd...", 
        "lastUpdated":"2016-07-06T12:43:16.866Z" 
    } 
    

    3. Update-synchronisierten Daten

    POST/api/data/507f191e810c19729de860ea

    Beitrag Körper:

    { 
        "data":"DWCx6wR9ggPqPRrhU4O4oLN5P09onApoAULX4Xt+ckxswtFNH/QQ+Y/RgxdU+8+8/muo4jo/jKnHssSezvjq6aPvYK+EAzAoRmXenAgUwHOjbiAXFqF8gScbbuLRlF0MsTKn/puIyFnvJd..." 
    } 
    

    Antwort:

    { 
        "lastUpdated":"2016-07-06T13:21:23.837Z" 
    } 
    

    Ihre Daten in MongoDB wird wie folgt aussehen:

    { 
        "id":"507f191e810c19729de860ea", 
        "data":"DWCx6wR9ggPqPRrhU4O4oLN5P09onApoAULX4Xt+ckxswtFNH/QQ+Y/RgxdU+8+8/muo4jo/jKnHssSezvjq6aPvYK+EAzAoRmXenAgUwHOjbiAXFqF8gScbbuLRlF0MsTKn/puIyFnvJd...", 
        "lastUpdated":"2016-07-06T13:21:23.837Z" 
    } 
    

    Verschlüsselung wird derzeit umgesetzt CryptoJS der AES-Implementierung verwendet wird. Da die App das Passwort des Benutzers als Passphrase für die AES-Funktion "encrypt" bereitstellt, generiert sie einen 256-Bit-Schlüssel, der die Daten des Benutzers verschlüsselt, bevor er an die API gesendet wird.

    Der Synchronisierungsprozess ist ziemlich einfach, aber offensichtlich muss er sicher und zuverlässig sein. Meine Bedenken sind:

    • Da die MongoDB ObjectID ist ziemlich leicht zu erraten, es ist möglich, dass ein böswilliger Benutzer jemand anderes Daten fordern könnte (gemäß Schritt 2. Synchronisationsdaten Get) durch ihre ID zu erraten. Wenn sie jedoch erfolgreich sind, werden sie nur verschlüsselte Daten abrufen und haben nicht den Schlüssel, mit dem sie zu entschlüsseln. Gleiches gilt für jeden, der Zugriff auf die Datenbank auf dem Server hat.
    • Angesichts der oben genannten, ist die CryptoJS AES-Implementierung sicher genug, so dass in der realen Möglichkeit, dass die verschlüsselten Daten eines Benutzers von einem böswilligen Benutzer abgerufen werden, sie realistisch nicht in der Lage sein werden, die Daten zu entschlüsseln?
    • Da die API ist offen für alle und Prüfung nicht oder überprüfen Sie die übermittelten Daten, jeder potenziell alle Daten, die sie wünschen einreichen könnten zum Beispiel im Dienst, gespeichert werden:

    Beitrag Körper:

    { 
        "data":"This is my anyold data..." 
    } 
    

    Gibt es etwas, was ich tun kann, um dagegen zu schützen, während ich die oben genannten Prinzipien befolge?

  • Allgemeiner Missbrauch des Dienstes, z. B. wenn Benutzer anfängliche Synchronisierungen (Schritt 1 oben) immer wieder spammen, um den Platz auf dem Server zu füllen; oder einige Benutzer verwenden unverhältnismäßig viel Serverraum.Ich habe einige Funktionen implementiert, um dies zu verhindern, wie das Protokollieren von IPs für erste Synchronisierungen für einen Tag (nicht länger als das), um eine einzelne IP auf eine bestimmte Anzahl von anfänglichen Synchronisierungen pro Tag zu beschränken. Außerdem beschränke ich die Post-Körpergröße für Syncs. Diese Optionen sind jedoch in der API konfigurierbar. Wenn also einem Benutzer diese Einschränkungen für eine öffentliche API-Instanz nicht gefallen, können sie ihre eigene Instanz hosten und die Einstellungen nach ihren Wünschen anpassen.
  • Also das ist es, ich würde mich über jeden freuen, der irgendwelche Gedanken oder Feedback zu diesem Ansatz hat, wenn man meinen Leitprinzipien folgt. Ich konnte keine Beispiele finden, bei denen andere Apps einen ähnlichen Ansatz verfolgt haben. Wenn jemand etwas davon kennt und mit ihnen verlinkt werden kann, wäre ich dankbar.

    Antwort

    0

    Ich kann nicht wirklich kommentieren, ob bestimmte AES-Algorithmen/Schlüssel sicher sind oder nicht, aber vorausgesetzt, sie sind (und die Schlüssel werden korrekt generiert), sollte es kein Problem sein, wenn andere Benutzer auf die verschlüsselten Daten zugreifen können.

    Sie können sich vielleicht vor Missbrauch schützen, ohne andere Konten zu benötigen, indem Sie Captchas oder ähnliche Wächter gegen automatische Nutzung verwenden. Wenn Sie für neue Accounts einen Catcha benötigen und für alle Accounts Limits für Datenvolumen und Anrufhäufigkeit festlegen, sollten Sie in Ordnung sein.

    Zum Schutz vor versehentlichen Klartextdaten können Sie für jeden Account einen sekundären Schlüssel erstellen und dann auf dem Server mit dem öffentlichen sekundären Schlüssel überprüfen, ob die Nachrichten entschlüsselt werden können. Etwas wie folgt aus:

    data = secondary_key(user_private_key(cleartext)) 
    

    Auf diese Weise werden die Daten immer verschlüsselt werden, und im schlimmsten Fall wird der Server in der Lage sein, es zu lesen, aber andere nicht.

    Ein paar Kommentare zu Ihrer API :) Wenn Sie bereits HTTP und POST verwenden, brauchen Sie nicht wirklich eine id. Die POST gibt normalerweise eine URI zurück, die auf die erstellten Daten verweist. Sie können dann GET dass URI oder PUT es ändern:

    POST /api/data 
    {"data": "..."} 
    

    Antwort:

    Location: /api/data/12345 
    {"data": "...", "lastmodified": "..." } 
    

    Um es zu ändern:

    PUT /api/data/12345 
    {"data": "..."} 
    

    Sie müssen es nicht auf diese Weise , aber es könnte einfacher sein, auf der Client-Seite zu implementieren, und vielleicht sogar bei der Zwischenspeicherung und Cache-Invalidierung helfen.

    +0

    Vielen Dank für die nützlichen Vorschläge Robert und für die Zeit nehmen zu beantworten. –