2016-01-14 9 views
6

In den letzten Tagen habe ich mit dem Micro Service Muster gespielt und alles läuft gut, aber die Sicherheit scheint mich zu verblüffen.Micro Service Sicherheit

Also, wenn ich eine Frage stellen kann: Wie handhabe ich die Benutzerauthentifizierung an einem einzelnen Dienst? Im Moment übergebe ich eine Anfrage an die Gateway API, die wiederum mit dem Dienst verbindet.

Frage Herausgegeben Siehe unten

Angesichts der Tatsache, dass die einzelnen Dienste, die nicht voneinander wissen sollten. Die Gateway ist der Aggregator als solcher.

Aktuelle Architektur.

enter image description here

Ein kleiner Code, um die Anfrage zu simulieren:

Frontend - Client-App

public class EntityRepository<T> 
{ 
    private IGateway _gateway = null; 
    public EntityRepository(IGateway gateway) 
    { 
     this._gateway = gateway; 
    } 
    public IEnumerable<T> FindAll() 
    { 
     return this._gateway.Get(typeof(T)).Content.ReadAsAsync<IEnumerable<T>>().Result; 
    } 
    public T FindById(int id) 
    { 
     return this._gateway.Get(typeof(T)).Content.ReadAsAsync<T>().Result; 
    } 
    public void Add(T obj) 
    { 
     this._gateway.Post(typeof(T), obj); 
    } 
    public void Update(T obj) 
    { 
     this._gateway.Post(typeof(T), obj); 
    } 
    public void Save(T obj) 
    { 
     this._gateway.Post(typeof(T), obj); 
    } 
} 


    //Logic lives elsewhere 
    public HttpResponseMessage Get(Type type) 
    { 
     return Connect().GetAsync(Path(type)).Result; 
    } 
    public HttpResponseMessage Post(Type type, dynamic obj) 
    { 
     return Connect().PostAsync(Path(type), obj); 
    } 
    private string Path(Type type) 
    { 
     var className = type.Name; 
     return "api/service/" + Application.Key + "/" + className; 
    } 
    private HttpClient Connect() 
    { 
     var client = new HttpClient(); 
     client.BaseAddress = new Uri("X"); 

     // Add an Accept header for JSON format. 
     client.DefaultRequestHeaders.Accept.Add(
     new MediaTypeWithQualityHeaderValue("application/json")); 

     return client; 
    } 

ich Generika verwenden, um festzustellen, wo sie es feuern muss einmal Hit das Tor . Wenn also die TypeKategorie ist, wird es die Kategorie Service Feuer so rufen:

public IEnumerable<dynamic> FindAll(string appKey, string cls) 
{ 
    var response = ConnectTo.Service(appKey, cls); 
    return (appKey == Application.Key) ? (response.IsSuccessStatusCode) ? response.Content.ReadAsAsync<IEnumerable<dynamic>>().Result : null : null; 
} 

Das Gateway nicht die physischen Dateien/Class der Typen enthalten.

Nach ein wenig Code hatte ich gehofft, jemand könnte mir eine kleine Demonstration oder den besten Ansatz geben, Sicherheit/Benutzerauthentifizierung mit der aktuellen Architektur zu behandeln.

Case Scenario 1 Benutzer die Web-App trifft und meldet sich an diesem Punkt die Benutzer verschlüsselte E-Mail und Passwort an den Gateway API gesendet wird, die dann an die User Service geleitet wird und entscheidet, ob der Benutzer authentifiziert ist - alles gut und gut, aber jetzt möchte ich alle Nachrichten aus dem Message Service abrufen, die der Benutzer erhalten hat. Ich kann wirklich nicht im Gateway sagen, wenn der Benutzer authentifiziert ist, um die Nachrichten holen, weil das das Problem nicht lösen von dem Aufruf der Message Service außerhalb der Gateway API

Ich kann auch nicht hinzufügen Authentifizierung für jeden einzelnen Dienst, weil das all entsprechenden erfordern würde Dienste im Gespräch mit der User Service und das schlägt den Zweck des Musters.

Fixes: Erlauben Sie dem Gateway nur, die Dienste anzurufen. Anfragen an Dienste außerhalb des Gateways sollten blockiert werden.

Ich weiß, Sicherheit ist ein weites Thema, aber im aktuellen Kontext hoffe ich, dass jemand mich mit der besten Vorgehensweise leiten könnte, um das Problem zu lösen.

Derzeit habe ich eine Guid Hardcodiert in allen Anwendungen, die wiederum Daten abruft, wenn die App gleich ist.

+1

Es gibt tausende Fragen zur Authentifizierung und Autorisierung, was hat Ihre Forschung gezeigt? Natürlich ist alles Statische (wie eine GUID) überhaupt keine Sicherheit, da jemand einfach die GUID aus dem Netzwerkverkehr schnüffeln und eine eigene App erstellen kann, die auch die gleiche GUID sendet. – CodeCaster

+0

Ich bin vertraut mit Authentifizierung und Autorisierung in monolithischen Anwendungen. Die Architektur stellt Herausforderungen. Haben Sie die Micro Service-Architektur schon einmal implementiert? Guid Ansatz ist Temp. –

+0

Müssen Sie Ihre Kunden (Apps) oder Ressourcenbesitzer authentifizieren? –

Antwort

3

bearbeiten

Diese Antwort ist über das Gateway < -> Micro-Service-Kommunikation. Der Anwender sollte natürlich korrekt authentifiziert werden, wenn die App mit dem Gateway spricht

Ende bearbeiten

Vor allem die Mikrodienste sollten nicht aus dem Internet erreichbar sein. Sie sollten nur vom Gateway aus zugänglich sein (das gruppiert werden kann).

Zweitens müssen Sie in der Lage sein, den aktuellen Benutzer zu identifizieren. Sie können es tun, indem Sie die UserId als HTTP-Header übergeben. Erstellen Sie einen WebApi-Filter, der diesen Header übernimmt und daraus eine benutzerdefinierte IPrincipal erstellt.

Schließlich müssen Sie sicherstellen, dass die Anfrage vom Gateway oder einem anderen Mikroservice kommt. Eine einfache Möglichkeit ist die Verwendung der HMAC-Authentifizierung für ein Token.

Speichern Sie den Schlüssel in web.config für jeden Dienst und das Gateway.Dann senden Sie einfach eine Token mit jeder Anforderung (die Sie authentifizieren können einen WebAPI Authentifizierungsfilter)

einen Hash zu erzeugen, verwenden Sie die HMACSHA256 Klasse in .NET:

private static string CreateToken(string message, string secret) 
{ 
    secret = secret ?? ""; 
    var keyByte = Encoding.ASCII.GetBytes(secret); 
    var messageBytes = Encoding.ASCII.GetBytes(message); 
    using (var hasher = new HMACSHA256(keyByte)) 
    { 
     var hashmessage = hasher.ComputeHash(messageBytes); 
     return Convert.ToBase64String(hashmessage); 
    } 
} 

Also in Ihrem MicroServiceClient Sie tun würden, so etwas wie diese:

var hash = CreateToken(userId.ToString(), mySharedSecret); 
var myHttpRequest = HttpRequest.Create("yourUrl"); 
myHttpRequest.AddHeader("UserId", userId); 
myHttpRequest.AddHeader("UserIdToken", hash); 
//send request.. 

Und in dem Mikro-Service erstellen Sie einen Filter wie:

public class TokenAuthenticationFilterAttribute : Attribute, IAuthenticationFilter 
{ 
    protected string SharedSecret 
    { 
     get { return ConfigurationManager.AppSettings["SharedSecret"]; } 
    } 

    public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken) 
    { 
     await Task.Run(() => 
     { 
      var userId = context.Request.Headers.GetValues("UserId").FirstOrDefault(); 
      if (userId == null) 
      { 
       context.ErrorResult = new StatusCodeResult(HttpStatusCode.Forbidden, context.Request); 
       return; 
      } 

      var userIdToken = context.Request.Headers.GetValues("UserIdToken").FirstOrDefault(); 
      if (userIdToken == null) 
      { 
       context.ErrorResult = new StatusCodeResult(HttpStatusCode.Forbidden, context.Request); 
       return; 
      } 

      var token = CreateToken(userId, SharedSecret); 
      if (token != userIdToken) 
      { 
       context.ErrorResult = new StatusCodeResult(HttpStatusCode.Forbidden, context.Request); 
       return; 
      } 


      var principal = new GenericPrincipal(new GenericIdentity(userId, "CustomIdentification"), 
       new[] {"ServiceRole"}); 
      context.Principal = principal; 
     }); 
    } 

    public async Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken) 
    { 
    } 

    public bool AllowMultiple 
    { 
     get { return false; } 
    } 

    private static string CreateToken(string message, string secret) 
    { 
     secret = secret ?? ""; 
     var keyByte = Encoding.ASCII.GetBytes(secret); 
     var messageBytes = Encoding.ASCII.GetBytes(message); 
     using (var hasher = new HMACSHA256(keyByte)) 
     { 
      var hashmessage = hasher.ComputeHash(messageBytes); 
      return Convert.ToBase64String(hashmessage); 
     } 
    } 
} 
+0

Sicher, lassen Sie mich eine Anfrage mit der 'UserId: admin' Kopfzeile erstellen. – CodeCaster

+0

@CodeCaster: Wenn Sie Zugriff auf den Gateway-Server erhalten haben, glauben Sie nicht, dass Sie das System auf verschiedene andere Arten verletzen könnten? – jgauffin

+0

Die erste Regel von Netzwerkprotokollen lautet: Traue dem Absender nicht (nun, zumindest nachdem SMTP, FTP und HTTP erfunden wurden ...). OP spricht über Desktop- und mobile Apps, die mit einem Webservice kommunizieren. Sie können niemals darauf vertrauen, dass ein Netzwerk frei von böswilligen Benutzern ist. Daher muss sich jeder Benutzer über die App authentifizieren. – CodeCaster

2

Option 1 (bevorzugt)

Der einfache Weg ist das Mikro Dienste hinter dem Gateway sein sollten, daher würden Sie Dienste weiße Liste, um sie zu verbinden, das heißt nur autorisierten und vertrauenswürdige Parteien Zugang haben (dh das Gateway nur). Clients sollten keinen direkten Zugriff darauf haben. Das Gateway ist dein Nachtclub Türsteher.

Option 2

Sie eine JWT oder irgendeine Form von Token verwenden und den geheimen Schlüssel zwischen den Diensten teilen. Ich benutze JWT Authorization Bearer Token.

Die anderen Dienste müssen den Benutzerdienst nicht abfragen, sie müssen nur wissen, dass das Token gültig ist, und dann haben sie die Berechtigung, die API zu verwenden. Ich bekomme den JWT vom Client zum Gateway und injiziere ihn in die Anfrage, die an den anderen Dienst gesendet wird, nur einen geraden Durchlauf.

Der dahinterliegende Micro-Dienst muss den gleichen JWT-Verbrauch wie das Gateway für die Autorisierung haben, aber wie bereits erwähnt, bestimmt er nur ein gültiges Token und fragt keinen gültigen Benutzer ab.

Aber dies hat ein Problem, dass, sobald jemand autorisiert ist, sie auf andere Benutzer Daten aufrufen können, wenn Sie etwas wie eine Forderung in das Token enthalten.

Meine Gedanken

Der Teil, den ich eine Herausforderung von Monolithic gefunden Micro Services war, dass Sie wechseln benötigt, wo Sie Ihr Vertrauen schenken. In Monolithic steuern Sie alles, was Sie steuern. Der Punkt von Micro Services ist, dass andere Dienste ihre Domain vollständig kontrollieren. Sie müssen diesem anderen Dienst vertrauen, um seine Verpflichtungen zu erfüllen, und nicht alles auf jeder Ebene, die über das Notwendige hinausgeht, erneut überprüfen und neu autorisieren.

+0

Ok, habe meine Bearbeitung beendet. Hoffentlich erklärt das es. –

+0

Vielen Dank für Ihre Zeit. –