C# Password Hashing und speichern in C# und .net

Lordwurst

Ensign
Registriert
Okt. 2008
Beiträge
181
Moin alle zusammen,

ich habe ein kleines Problem. Zur Zeit versuche ich in einem .NET Projekt einen password hash einzubauen da ich keine raw passwords in der Datenbank speichern will. Die Mechanik wie das geht verstehe ich schon aber sind da noch ein paar offene fragen.

1. Ich habe nun öfters gelesen das salt hashing gut sein soll und schlecht. Nun wollte ich euch mal dazu fragen?

2. Wenn ich eine hash generiere für jedes password individual wie muss dann die Validation beim login aussehen?

3. Wie genau würde man so was ein bauen in eine Registration page?

Ich poste mal meine code mit den ich zur zeit habe.
Das ist meine Page
Code:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Regestration.aspx.cs" Inherits="Regestratioon" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Regestration</title>
    <style type="text/css">
        .style1 {
            width: 100%;
        }
        .style2
        {
            width: 120px;
        }
        .style3
        {
            width: 120px;
            height: 26px;
        }
        .style4
        {
            height: 26px;
        }
        .style5
        {
            width: 204px;
        }
        .style6
        {
            height: 26px;
            width: 204px;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
        Regestration Page
        
        <table class="style1">
        <tr>
            <td class="style2">
                UserName</td>
            <td class="style5">
                <asp:TextBox ID="TextBoxUN" runat="server" MaxLength="15" Width="180px"></asp:TextBox>
            </td>
            <td>
                <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" 
                    ControlToValidate="TextBoxUN" ErrorMessage="Enter user name" ForeColor="Red"></asp:RequiredFieldValidator>
            </td>
        </tr>
        <tr>
            <td class="style3">
                Password</td>
            <td class="style6">
                <asp:TextBox ID="TextBoxP" runat="server" MaxLength="15" Width="180px" 
                    TextMode="Password"></asp:TextBox>
            </td>
            <td class="style4">
                <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" 
                    ControlToValidate="TextBoxP" ErrorMessage="Enter pass" ForeColor="Red"></asp:RequiredFieldValidator>
            </td>
        </tr>
        <tr>
            <td class="style2">
                Retype Password</td>
            <td class="style5">
                <asp:TextBox ID="TextBoxPS" runat="server" MaxLength="15" Width="180px" 
                    TextMode="Password"></asp:TextBox>
            </td>
            <td>
                <asp:RequiredFieldValidator ID="RequiredFieldValidator3" runat="server" 
                    ControlToValidate="TextBoxPS" ErrorMessage="enter pass" ForeColor="Red"></asp:RequiredFieldValidator>
                    <br />
                <asp:CompareValidator ID="CompareValidator1" runat="server" 
                    ErrorMessage="Compare PW" ControlToCompare="TextBoxP" 
                    ControlToValidate="TextBoxPS" ForeColor="Red"></asp:CompareValidator>
            </td>
        </tr>
        <tr>
            <td class="style2">
                Email address</td>
            <td class="style5">
                <asp:TextBox ID="TextBoxEA" runat="server" Width="180px"></asp:TextBox>
            </td>
            <td>
                <asp:RequiredFieldValidator ID="RequiredFieldValidator4" runat="server" 
                    ControlToValidate="TextBoxEA" ErrorMessage="email" ForeColor="Red"></asp:RequiredFieldValidator>
            </td>
        </tr>
        <tr>
            <td class="style2">
                Full name</td>
            <td class="style5">
                <asp:TextBox ID="TextBoxFN" runat="server" Width="180px"></asp:TextBox>
            </td>
            <td>
                <asp:RequiredFieldValidator ID="RequiredFieldValidator5" runat="server" 
                    ControlToValidate="TextBoxFN" ErrorMessage="name" ForeColor="Red"></asp:RequiredFieldValidator>
            </td>
        </tr>
        <tr>
            <td class="style2">
                &nbsp;</td>
            <td class="style5">
                <asp:Button ID="Submit" runat="server" onclick="Submit_Click" Text="Submit" />
            </td>
            <td>
                &nbsp;</td>
        </tr>
    </table>
        </div>
    </form>
    
</body>
</html>

Der Code
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.SqlClient;
using System.Configuration;
using System.Security;

public partial class Regestratioon : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["RegConnectionString"].ConnectionString);
        con.Open();
        string cmdStr = "select count(*) from Registratoin where USerName='" + TextBoxUN.Text + "'";
        SqlCommand userExist = new SqlCommand(cmdStr, con);
        int temp = Convert.ToInt32(userExist.ExecuteScalar().ToString());
        if (temp == 1)
        {
            Response.Write("User name Already exist.... use a other user name plz");
        }
    }
    protected void Submit_Click(object sender, EventArgs e)
    {
       SqlConnection con= new SqlConnection(ConfigurationManager.ConnectionStrings["RegConnectionString"].ConnectionString);
       con.Open();
       string insCmd = "Insert into Regestration (UserName, Password, email, FullName) values (@UserName, @Password, @email, @FullName)";
       SqlCommand insertUser = new SqlCommand(insCmd, con);
       insertUser.Parameters.AddWithValue("@UerName", TextBoxUN.Text);
       insertUser.Parameters.AddWithValue("@Password", TextBoxP.Text);
       insertUser.Parameters.AddWithValue("@email", TextBoxEA.Text);
       insertUser.Parameters.AddWithValue("@FullName", TextBoxFN.Text);

       try
       {
           insertUser.ExecuteNonQuery();
           con.Close();
           Response.Redirect("Login.aspx");
       }
       catch (Exception er)
       {
           Response.Write("End of the world plz try again!");
       }
       finally
       { 
        //extensions that can be implemented here!!
       }
       
    }
}
Ich dachte mir das ich im meiner Datenbank noch ein weiteres column anlegen muss um darin den hash für die passwords zu speicher und die werden dann benutzt bei dem login.

Wenn mir jemand weiter helfen kann wäre sehr nett oder ein Tutorial verlinken kann.

Vielen Dank für die Hilfe.
 
Du generierst einfach irgend eine zufällige Zeichenfolge, speicherst diese zum eigentlichen Passwort mit ab, generierst aus dem richtigen Passwort und Salt den Hash und beim Login, machst du es genauso. Für den User ist es vollkommen irrelevant, dieser muss nur sein Passwort eingeben.
 
Ok, das heißt ich das alles müsste ich dann in die Submit_Click Funktion rein bauen oder liege ich da falsch?
Mehrere beispiele zeigen immer was von class NAmE{ und hier dann der code drin}
 
Genau, erstell eine weitere Spalte salt, in dieser speicherst du die zufällige Zeichenfolge ab (wie du das machst ist dir überlassen). Danach wirfst du den Salt und das Passwort zusammen und hashst beides, welches du wiederum in die richtige Spalte password speicherst. Somit kann man man umgehen, dass das Passwort in Rainbow tables gefunden wird.
 
OK cool,
vielen dank dafür, habe es zum laufen bekommen :D
 
Und falls das wirklich mal irgendwo eingesetzt werden sollte, verwende doch bitte lieber https://www.google.com/search?q=bcrypt+c# anstatt selbst irgendwelche Kryptosachen zu implementieren oder zu erfinden.

Es heißt übrigens "Registration", und auch sonst hast du da in deinem Codebeispiel relativ kreative Rechtschreibungen drinnen:
Regestratioon
from Registratoin where USerName=
User name Already exist.... use a other user name plz
Insert into Regestration

Spannend, dass das trotzdem läuft! ;)
 
Wozu so kompliziert?

Ich würde zur Registrierung einfach ein Username- und ein Passwort-Eingabefeld machen.
Aus dem eingegebenen Passwort kann man dann ganz einfach einen Hash-Erzeugen und dann in der Datenbank speichern.

Beim Anmelden wird aus dem vom Benutzer eingegebenen Passwort wiederum ein Hash erzeugt und mit dem in der Datenbank gespeicherten Hash verglichen.

Im .NET Namespace findet man eine Anzahl von Hash-Klassen. Man kann auch eigenen schreiben wenn mans kann.

Es gibt im Namespace System.Security.Cryptography als fertige Varianten: MD5, SHA1, SHA256, SHA384 und SHA512.
 
...und dann kommt jemand mit einer Datenbank aus Milliarden vorberechneter Klartexte + Hashes und knackt alle Passwörter mit ~7-8 beliebigen Zeichen (oder noch länger, ich hab schon länger nicht nach Rainbowtables gesucht) in ein paar Sekunden.

Hashes ohne Salz und Mehrfachhashing um Vorberechnung und BruteForce teuer zu machen sind leichte Beute, genauso wie hausgemachte Lösungen ("Man könnte doch ganz einfach..."). Bcrypt ist jetzt auch nicht die definitive Lösung, besser als selbstgeschriebene oder -ausgedachte Lösungen ist es aber allemal - besser als reines crypt ist es wegen der längeren Key-setup Phase, die auf GPUs nicht gut läuft.

Alternativ gibt's gratis 2-factor Auth von Google z.B. oder man verwendet OAuth. Dabei müsste man aber online sein und einem anderen Anbieter vertrauen.
 
Wenn man sowas grundlegendes richtig machen möchte, würde ich Lösungen suchen, die das bereits gut umsetzen.

In der ASP.Net-Welt gibt es zum Thema Web-Authentication die (SQL-) Membership-Provider. Das ist "Out of the Box" ohne irgendwelche Zusatzsoftware im .Net-Framework drin, man muss halt auf seinem SQL-Server ein paar Tabellen anlegen, und die entsprechenden Controls und Klassen verwenden.

Wie das geht, steht hier:

http://www.asp.net/web-forms/tutori...eating-the-membership-schema-in-sql-server-cs
 
Gute Anlaufstelle um die Theorie und alle möglichen Formen des Hashens und Salzens mal kurz zu überblicken:

http://crackstation.net/hashing-security.htm

Mit Erklärung und Beispiel, wie man es "richtig" macht in ASP.NET (C#) oder PHP.

"Richtig" in Anführungsstrichen, weil es immer Sicherheitslücken gibt in der Mensch-Komponente ;)
 
Zuletzt bearbeitet:
Zurück
Oben