wake-up-neo.com

RESTful Web Service - Wie authentifiziere ich Anfragen von anderen Diensten?

Ich entwerfe einen RESTful-Webdienst, auf den Benutzer, aber auch andere Webdienste und -anwendungen zugreifen müssen. Alle eingehenden Anforderungen müssen authentifiziert werden. Die gesamte Kommunikation erfolgt über HTTPS. Die Benutzerauthentifizierung wird auf der Grundlage eines Authentifizierungstokens ausgeführt, das durch POSTEN des Benutzernamens und des Kennworts (über eine SSL-Verbindung) an eine /session -Ressource von bereitgestellt wird der Service.

Bei Web-Service-Clients befindet sich kein Endbenutzer hinter dem Client-Service. Die Anforderungen werden durch geplante Tasks initiiert , Ereignisse oder andere Computervorgänge. Die Liste der Verbindungsdienste ist im Voraus bekannt (offensichtlich, denke ich). Wie soll ich diese Anfragen von anderen (Web-) Diensten authentifizieren? Ich möchte, dass der Authentifizierungsprozess für diese Dienste so einfach wie möglich implementiert wird, jedoch nicht auf Kosten der Sicherheit. Was wären die Standards und Best Practices für ein solches Szenario?

Optionen, an die ich denken kann (oder die mir vorgeschlagen wurden):

  1. Lassen Sie die Client-Dienste einen "falschen" Benutzernamen und ein falsches Kennwort verwenden und authentifizieren Sie sie auf die gleiche Weise wie Benutzer. Diese Option gefällt mir nicht - sie fühlt sich einfach nicht richtig an.

  2. Vergeben Sie eine permanente Anwendungs-ID für den Client-Service, möglicherweise auch einen Anwendungsschlüssel. Soweit ich verstanden habe, ist dies genau das Gleiche wie Benutzername + Passwort. Mit dieser ID und diesem Schlüssel kann ich entweder jede Anforderung authentifizieren oder ein Authentifizierungstoken erstellen, um weitere Anforderungen zu authentifizieren. In beiden Fällen gefällt mir diese Option nicht, da sich jeder, der die Anwendungs-ID und den Schlüssel in die Hand nimmt, als Client ausgeben kann.

  3. Ich könnte der vorherigen Option eine IP-Adressprüfung hinzufügen. Dies würde es schwieriger machen, falsche Anforderungen auszuführen.

  4. Client-Zertifikate. Richten Sie meine eigene Zertifizierungsstelle ein, erstellen Sie ein Stammzertifikat und erstellen Sie Clientzertifikate für die Clientdienste. Ein paar Dinge fallen mir jedoch ein: a) Wie kann ich den Benutzern noch die Authentifizierung ohne Zertifikate erlauben und b) wie kompliziert ist dieses Szenario aus Sicht des Client-Service zu implementieren?

  5. Noch etwas - muss es da draußen andere Lösungen geben?

Mein Dienst würde auf Java ausgeführt, aber ich habe bewusst Informationen darüber ausgelassen, auf welchem ​​spezifischen Framework er basieren würde, da ich mich mehr für die Grundprinzipien und weniger für die Implementierungsdetails interessiere - ich gehe davon aus, dass dies die beste Lösung ist unabhängig vom zugrunde liegenden Framework implementiert werden können. Ich bin jedoch ein wenig unerfahren mit diesem Thema, daher werden auch konkrete Tipps und Beispiele zur tatsächlichen Implementierung (wie nützliche Bibliotheken von Drittanbietern, Artikel usw.) sehr geschätzt.

113
Tommi

Jede Lösung für dieses Problem läuft auf ein gemeinsames Geheimnis hinaus. Ich mag auch die fest codierte Option für Benutzername und Passwort nicht, aber sie hat den Vorteil, dass sie recht einfach ist. Das Client-Zertifikat ist auch gut, aber ist es wirklich viel anders? Es gibt ein Zertifikat auf dem Server und eines auf dem Client. Der Hauptvorteil ist, dass es schwieriger ist, Gewalt anzuwenden. Hoffentlich haben Sie andere Schutzmechanismen installiert, um sich dagegen zu schützen.

Ich denke nicht, dass Ihr Punkt A für die Client-Zertifikat-Lösung schwer zu lösen ist. Sie benutzen nur einen Zweig. if (client side certificat) { check it } else { http basic auth } Ich bin kein Java Experte und ich habe noch nie damit gearbeitet, um clientseitige Zertifikate zu erstellen. Ein kurzes Google führt uns jedoch zu dieses Tutorial das sieht direkt in deiner Gasse aus.

Lassen Sie mich trotz all dieser "Was ist das Beste" -Diskussion darauf hinweisen, dass es eine andere Philosophie gibt, die besagt: "Weniger Code, weniger Klugheit ist besser." (Ich persönlich halte diese Philosophie). Die Client-Zertifikat-Lösung klingt nach viel Code.

Ich weiß, dass Sie Fragen zu OAuth gestellt haben, aber der OAuth2-Vorschlag enthält eine Lösung für Ihr Problem namens " Inhaber-Token ", die in Verbindung mit SSL verwendet werden muss. Ich denke, der Einfachheit halber würde ich entweder den fest codierten Benutzer/Pass (einen pro App, damit sie einzeln widerrufen werden können) oder die sehr ähnlichen Inhaber-Token wählen.

33
newz2000

Nachdem Sie Ihre Frage gelesen haben, würde ich sagen, erstellen Sie ein spezielles Token für die erforderliche Anforderung. Dieser Token wird in einer bestimmten Zeit (sagen wir an einem Tag) leben.

Hier ist ein Beispiel zum Generieren eines Authentifizierungstokens:

(day * 10) + (month * 100) + (year (last 2 digits) * 1000)

zum Beispiel: 3. Juni 2011

(3 * 10) + (6 * 100) + (11 * 1000) = 
30 + 600 + 11000 = 11630

dann verketten mit Benutzer Passwort, Beispiel "my4wesomeP4ssword!"

11630my4wesomeP4ssword!

Dann mache MD5 dieser Zeichenkette:

05a9d022d621b64096160683f3afe804

Wenn Sie eine Anfrage aufrufen, verwenden Sie immer dieses Token,

https://mywebservice.com/?token=05a9d022d621b64096160683f3afe804&op=getdata

Dieser Token ist jeden Tag einzigartig. Ich denke, diese Art des Schutzes ist mehr als ausreichend, um unseren Service immer zu schützen.

Hoffnung hilft

:)

35
kororo

Es gibt verschiedene Ansätze.

  1. Die RESTful-Puristen möchten, dass Sie die BASIC-Authentifizierung verwenden und bei jeder Anforderung Anmeldeinformationen senden. Ihre Begründung ist, dass niemand einen Staat speichert.

  2. Der Client-Service könnte ein Cookie speichern, das eine Sitzungs-ID verwaltet. Ich persönlich finde das nicht so anstößig wie einige der Puristen, von denen ich höre - es kann teuer sein, sich immer wieder zu authentifizieren. Es hört sich aber so an, als ob Sie diese Idee nicht mögen.

  3. Ihrer Beschreibung nach hört es sich wirklich so an, als ob Sie sich für OAuth2 interessieren könnten. Meine bisherige Erfahrung ist, dass es irgendwie verwirrend und blutig ist. Es gibt Implementierungen, aber es gibt nur wenige. In Java wurde es meines Wissens in die Sicherheit Module von Spring3 integriert. (Ihr Tutorial ist schön geschrieben.) Ich habe darauf gewartet, ob es eine Erweiterung in Restlet geben wird, aber bisher, obwohl es vorgeschlagen wurde und werden kann Im Inkubator ist es noch nicht vollständig integriert.

11
jwismar

5. Noch etwas - es muss andere Lösungen geben?

Da hast du recht! Und es heißt JWT (JSON Web Tokens).

JSON Web Token (JWT) ist ein offener Standard (RFC 7519), der eine kompakte und eigenständige Methode für die sichere Übertragung von Informationen zwischen Parteien als JSON-Objekt definiert. Diese Informationen können überprüft und als vertrauenswürdig eingestuft werden, da sie digital signiert sind. JWTs können mit einem geheimen Schlüssel (mit dem HMAC-Algorithmus) oder einem öffentlichen/privaten Schlüsselpaar mit RSA signiert werden.

Ich empfehle dringend, in JWTs zu suchen. Sie sind im Vergleich zu alternativen Lösungen eine viel einfachere Lösung für das Problem.

https://jwt.io/introduction/

3
justin.hughey

Was den Client-Zertifikat-Ansatz angeht, wäre es nicht besonders schwierig, ihn zu implementieren, während die Benutzer ohne Client-Zertifikate weiterhin zugelassen werden.

Wenn Sie in der Tat Ihre eigene selbstsignierte Zertifizierungsstelle erstellt und Client-Zertifikate für jeden Client-Service ausgestellt hätten, hätten Sie eine einfache Möglichkeit, diese Services zu authentifizieren.

Abhängig vom verwendeten Webserver sollte es eine Methode zur Angabe der Clientauthentifizierung geben, die ein Clientzertifikat akzeptiert, jedoch kein Clientzertifikat erfordert. Beispielsweise können Sie in Tomcat bei der Angabe Ihres https-Connectors "clientAuth = want" anstelle von "true" oder "false" festlegen. Sie müssen dann Ihr selbstsigniertes CA-Zertifikat zu Ihrem Truststore hinzufügen (standardmäßig die Cacerts-Datei in der von Ihnen verwendeten JRE, es sei denn, Sie haben in Ihrer Webserverkonfiguration eine andere Datei angegeben), sodass die einzigen vertrauenswürdigen Zertifikate diejenigen sind, die von ausgestellt wurden Ihre selbstsignierte Zertifizierungsstelle.

Auf der Serverseite würden Sie den Zugriff auf die Dienste, die Sie schützen möchten, nur zulassen, wenn Sie in der Lage sind, ein Clientzertifikat aus der Anforderung abzurufen (nicht null), und alle DN-Prüfungen bestehen, wenn Sie zusätzliche Sicherheit bevorzugen. Benutzer ohne Client-Zertifikate können weiterhin auf Ihre Dienste zugreifen, haben jedoch einfach keine Zertifikate in der Anforderung.

Meiner Meinung nach ist dies der "sicherste" Weg, aber es hat sicherlich Lernaufwand und Overhead, so dass es nicht unbedingt die beste Lösung für Ihre Bedürfnisse sein muss.

3
bobz32

Ich glaube der Ansatz:

  1. Erste Anfrage, Client sendet ID/Passcode
  2. Tauschen Sie ID/Pass gegen eindeutiges Token aus
  3. Validieren Sie das Token bei jeder nachfolgenden Anforderung, bis es abläuft

ist ziemlich Standard, unabhängig davon, wie Sie und andere spezifische technische Details implementieren.

Wenn Sie den Umschlag wirklich verschieben möchten, können Sie den https-Schlüssel des Clients möglicherweise in einem vorübergehend ungültigen Zustand betrachten, bis die Anmeldeinformationen validiert sind, Informationen einschränken, falls dies nie der Fall ist, und den Zugriff bei deren Validierung basierend auf dem Ablauf erneut gewähren.

Hoffe das hilft

3
Dynrepsys

Sie können eine Sitzung auf dem Server erstellen und sessionId für jeden REST Aufruf zwischen Client und Server freigeben.

  1. Authentifizieren Sie zuerst REST request: /authenticate. Gibt die Antwort (gemäß Ihrem Client-Format) mit sessionId: ABCDXXXXXXXXXXXXXX Zurück.

  2. Speichern Sie dieses sessionId in Map mit der aktuellen Sitzung. Map.put(sessionid, session) oder benutze SessionListener, um Schlüssel für dich zu erstellen und zu zerstören;

    public void sessionCreated(HttpSessionEvent arg0) {
      // add session to a static Map 
    }
    
    public void sessionDestroyed(HttpSessionEvent arg0) {
      // Remove session from static map
    }
    
  3. Holen Sie sich sessionid bei jedem REST Aufruf, wie URL?jsessionid=ABCDXXXXXXXXXXXXXX (Oder auf andere Weise);

  4. Rufe HttpSession mit sessionId von der Karte ab;
  5. Validieren Sie die Anforderung für diese Sitzung, wenn die Sitzung aktiv ist.
  6. Antwort oder Fehlermeldung zurücksenden.
1
arviarya

Ich würde es verwenden, wenn eine Anwendung einen Benutzer mit einem Anwendungs-ID-Parameter auf Ihre Website umleitet, sobald der Benutzer die Anforderung genehmigt, wird ein eindeutiges Token generiert, das von der anderen App zur Authentifizierung verwendet wird. Auf diese Weise verarbeiten die anderen Anwendungen keine Benutzeranmeldeinformationen, und andere Anwendungen können von Benutzern hinzugefügt, entfernt und verwaltet werden. Foursquare und einige andere Sites authentifizieren sich auf diese Weise und lassen sich sehr einfach als andere Anwendung implementieren.

0
Devin M