Einfache Authentifizierung in ASP.NET MVC 5

73123
Jason

Ich baue eine ASP.NET MVC 5-Anwendung, und ich versuche aus Gründen, die zu diesem Zeitpunkt irrelevant sind, meine eigenen Mittel zur Authentifizierung von Benutzern aufzubauen. Beim Programmieren bin ich noch sehr neu, vor allem bei so etwas, und mir ist klar, dass das, was für mich gut aussieht, voller Probleme sein kann. Daher präsentiere ich meinen Code, der zu Demonstrationszwecken vereinfacht ist, zur Überprüfung.

Das ContactModell:

public class Contact
{
    [Key]
    public int ContactID { get; set; }

    [Required]
    public string Email { get; set; }

    [Required]
    public string Password { get; set; }
}

Die LoginAktion:

[HttpPost]
public ActionResult Login(Contact contact)
{
    bool validEmail = db.Contacts.Any(x => x.Email == contact.Email);

    if (!validEmail)
    {
        return RedirectToAction("Login");
    }

    string password = db.Contacts.Where(x => x.Email == loginForm.Email)
                                 .Select(x => x.Password)
                                 .Single();

    bool passwordMatches = Crypto.VerifyHashedPassword(password, loginForm.Password);

    if (!passwordMatches)
    {
        return RedirectToAction("Login");
    }

    string authId = Guid.NewGuid().ToString();

    Session["AuthID"] = authId;

    var cookie = new HttpCookie("AuthID");
    cookie.Value = authId;
    Response.Cookies.Add(cookie);

    return RedirectToAction("Private");
}

Aktionen, bei denen der Benutzer angemeldet sein muss, sehen folgendermaßen aus:

public ActionResult Private()
{
    try
    {
        if (Request.Cookies["AuthID"].Value == Session["AuthID"].ToString())
        {
            return View();
        }
        else
        {
            return RedirectToAction("Index");
        }
    }
    catch
    {
        return RedirectToAction("Index");
    }
}

Ich habe das Gefühl, dass dies wahrscheinlich sehr schlecht ist. Allerdings scheint jede "Lösung", die ich finde, zu komplex und / oder es fehlt an Dokumentation, die es mir ermöglichen würde, einen Sinn daraus zu machen.

Ich möchte nur sicherstellen, dass der Benutzer über einen gültigen Benutzernamen und ein gültiges Kennwort verfügt, bevor er eine Bestellung aufgibt oder sein Konto aktualisiert. Wird mein Code dies sicher tun?

Antworten
11
Ich hätte nur eine Frage an Sie: Warum wollten Sie nicht die verwenden, die mit einem neuen Lernprogramm geliefert wird? Ein eigenes Authentifizierungssystem zu erstellen, ist eine verdammt gute Arbeit. Marc-Andre vor 6 Jahren 3
Nun, ich "weiß" nicht wirklich, dass es eine verdammt gute Arbeit ist, weil es (für meine unerfahrenen Augen) scheint, dass das, was ich geschrieben habe, funktioniert. Ich hatte auch das Gefühl, ich müsste mein eigenes schreiben, weil ich zu diesem Zeitpunkt die Standardauthentifizierungsprozesse von MVC überhaupt nicht verstehe. Außerdem muss ich eine vorhandene Tabelle mit Benutzerkontodaten verwenden, sodass ich die Authentifizierung von MVC nicht verstehe und am Ende selbst versucht habe, dies zu tun. Jason vor 6 Jahren 4
Es ist normal, wenn Sie gerade erst nach Authentifizierung gesucht haben, aber ich kann Ihnen versichern, dass es viel zu denken gibt. Wie speichern Sie das Passwort? Sind sie gesalzen? Wie melden Sie sich ab, wie werden sie authentifiziert? Ist es sicher Es ist gut, dass du es selbst ausprobiert hast, aber es ist schwer etwas gut zu machen. Marc-Andre vor 6 Jahren 0
Denken Sie nicht, dass der "Login" -Controller zu viele Dinge tut: Verbindung zur Datenbank herstellen, das Kennwort überprüfen und die Sitzung erstellen? Können Sie über S nach dem SOLID-Prinzip denken? vor 6 Jahren 0
Wie ich in meinem ersten Beitrag gesagt habe, ist mein Code "zu Demonstrationszwecken vereinfacht", also könnte mein Controller verbessert werden, usw. Mein Anliegen ist es lediglich, herauszufinden, ob es Sicherheitslücken bei meinem grundlegenden Versuch der Authentifizierung gibt Ein Benutzer. Jason vor 6 Jahren 0

3 Antworten auf die Frage

9
Marc-Andre

Ich befürchte, dass die Berechtigungsnachweise von einem Angreifer entdeckt werden können, wenn er während des Verbindungsvorgangs auf ihn hört. Wenn https nicht aktiviert ist, kann das Angreifer das Kennwort (wenn es keinen Schutz gibt) während der HTTP-Anforderungen sehen.

Dieser Punkt bezieht sich nicht direkt darauf, wie Sie Ihren Code implementiert haben, aber er wird einen großen Beitrag dazu leisten, wie Ihr Code sicher ist.


string authId = Guid.NewGuid().ToString();  

Ich bin kein Sicherheitsexperte, aber ich würde die Verwendung von GUID zu Sicherheitszwecken empfehlen. Es scheint ein Stirnrunzeln zu sein :

GUIDs wurden nicht als Bestandteil eines Sicherheitssystems entwickelt. Ihre Verwendung in einem Sicherheitssystem ist "off label" und daher eine sehr schlechte Idee. Ich kann im Moment nicht viel sehen, was den Mechanismus bricht.

Sie sollten diesen Rat so nehmen, wie er ist, und weitere Nachforschungen anstellen. Ich würde einen Kommentar zu einer Frage nicht als eine gute Referenz nehmen, aber ich würde mich fragen, ob sie tatsächlich eine gute Idee ist.


Es gibt eine Menge Dokumentation, die Sie bei der Entwicklung eines sicheren Authentifizierungssystems unterstützen wird, aber diese großartige Frage zu SO würde die meisten wichtigen Dinge abdecken.


Der Authentifizierungsmechanismus sieht für mich gut aus. Das Speichern eines Cookies und das Überprüfen des Werts in Sessionist eine gute Möglichkeit, um sicherzustellen, dass der Benutzer authentifiziert wird.

Der einzige Nachteil besteht darin, dass jemand, der die Sitzung und den Cookie entführt, sich nicht mit Anmeldeinformationen anmelden muss, da das Token ihm versichert, dass das System ihn als authentifizierten Benutzer sieht. Es gibt nicht viel in Ihrem Code, den Sie tun könnten, um dies zu verhindern.

Was Sie am meisten vermissen werden, wenn Sie Ihren eigenen Mechanismus rollen, ist ein gewisser "Vorteil" durch die Verwendung der .NET-Implementierung. Was ich zuvor in der Schule und bei der Suche getan habe, werden Sie die [Authorize][3]Eigenschaften vermissen, in denen Ihr Code aussehen könnte:

[Authorize]
public ActionResult Private()
{
    return View();

}

Welcher Code würde den gesamten Cookie verbergen. Das könnte Ihnen helfen, wenn Sie aus einem bestimmten Grund keine Cookies verwenden können, müssen Sie nicht den Ort ändern, an dem Sie die Identität Ihres Nutzers überprüft haben. Dies ist nur für die Lesbarkeit und Wartung von Code, dies hat nichts mit der Sicherheit zu tun.

Siehe Bearbeiten zu meinem ursprünglichen Post / Code bezüglich der Passwörter. In Bezug auf die GUID habe ich hier eine Lösung gefunden (http://stackoverflow.com/questions/1402696/how-deterministic-are-net-guids), die besser zu sein scheint. Nachdem diese Dinge abgedeckt wurden, sehe ich immer noch nicht, warum mein Code nicht ausreicht. Es scheint (für mich) zu verhindern, dass der Benutzer auf geschützte Seiten zugreift, es sei denn, er hat ein Cookie, das den korrekten und äußerst schwer zu duplizierenden Wert enthält. Der einzige Haken, den ich mir vorstellen kann, ist, wenn jemand diesen Keks gestohlen hat. Ansonsten kann ich nicht sehen, was daran falsch ist. Jason vor 6 Jahren 0
@ Jason Ein Teil des Gesamtbildes ist, wie Sie Ihr Passwort speichern. Die Realität ist, dass das Passwort nicht korrekt funktioniert, wenn Sie das Passwort nicht korrekt speichern. Wenn Sie keinen sicheren Mechanismus haben, um den Schutz des Kontos zu gewährleisten, funktioniert dies nicht. Wenn ich irgendwie auf Sie zugreifen kann und ein klares Passwort sehen kann, kann ich mit jedem Konto, das Sie auf Ihrer Website haben, eine Verbindung herstellen und es ist mir nicht einmal wichtig, einen Cookie zu stehlen. Marc-Andre vor 6 Jahren 0
@ Jason http://security.stackexchange.com/questions/41447/why-is-password-hashing-considered-so-important Marc-Andre vor 6 Jahren 0
Ich entschuldige mich dafür, dass ich meine Behandlung der Passwörter nicht klarer formuliert habe: Ich hasse die Passwörter. Ich verwende `Crypto.HashPassword (registrationForm.Password)` während der Benutzerregistrierung. Jason vor 6 Jahren 0
@ Jason Nein, es tut mir leid, dass ich diese Zeile im Schnitt nicht gesehen habe. Weißt du, das ist ein guter Anfang! Ich werde meine Antwort später noch einmal bearbeiten. Ihre Implementierung sieht "gut" aus, aber ich möchte etwas hinzufügen, das nicht aus Sicherheitsgründen ist, aber ich habe eine Besprechung. Marc-Andre vor 6 Jahren 0
"Es gibt nicht viel in Ihrem Code, den Sie tun könnten, um das zu verhindern." Mein Plan, sich mit der Entführung zu befassen, besteht darin, dass der Benutzer nach dem Klicken auf "Zur Kasse" das Passwort erneut eingeben muss (ähnlich wie bei Amazon). Von diesem würde ich wissen, dass der Benutzer, der auf "Checkout" geklickt hat, gültige Anmeldeinformationen hat. Ich würde dann ein Token generieren und es in das Formular "Senden" der Checkout-Ansicht einfügen. Wenn der Benutzer auf "Senden" klickt, verifiziere ich die ASP.NET_SessionId, meine eigene AuthID und das Checkout-Token. Ich kann nicht sehen, wie jemand durchkommen kann, ohne HTTPS zu überwinden oder das Passwort des Benutzers zu erhalten. Jason vor 6 Jahren 0
7
Rama

Sie können eine benutzerdefinierte Berechtigungsklasse erstellen, die ActionFilterAttribute erbt

public class AuthorizationFilter : ActionFilterAttribute
{
  public override void OnActionExecuting(ActionExecutingContex   filterContext)
  {
  //Write you authentication logic here . you can use Request headers,cookies ,..etc 
  }

}

Dann dekoriere deine Aktionsmethode mit [AuthorizationFilter]

[AuthorizationFilter]
public ActionResult GetAllEmployee()
{
  //Action method logic
}
Dies ist eigentlich das, was ich nicht allzu lange nach meinem ursprünglichen Beitrag getan habe. Es hat bisher für mich super funktioniert. Jason vor 5 Jahren 1
2
David

Eine Ergänzung zu dem, was gesagt wurde:

Es reicht nicht aus, um sicherzustellen, dass die Anmeldung über https erfolgt, da das Authentifizierungs-Cookie nicht bei nicht sicheren Anfragen übermittelt werden soll, da es von jedem abgefangen werden könnte, der auf den Netzwerkverkehr wartet.

Sie benötigen also beide der folgenden Bedingungen, um wahr zu sein:

  1. Das Authentifizierungs-Cookie muss als sicher markiert sein, damit es nur bei HTTPS-Anforderungen übermittelt wird.
  2. Alle Aktionen, für die eine Authentifizierung erforderlich ist, müssen nur über HTTPS verfügbar sein.

Wenn in der Praxis HTTPS für alles auf der gesamten Site (und für andere Subdomains, die jemand eingerichtet hat) erzwungen wird, könnte Punkt 1 vermieden werden. Dies ist jedoch kein Grund.