web-dev-qa-db-ja.com

C#でソルトおよびハッシュされたパスワードを検証する方法

以下の方法を使用して、パスワードをソルトおよびハッシュしました

public string CreateSalt(int size)
{
    var rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
    var buff = new byte[size];
    rng.GetBytes(buff);
    return Convert.ToBase64String(buff);
}
public string GenerateSHA256Hash(String input, String salt)
{
    byte[] bytes = System.Text.Encoding.UTF8.GetBytes(input + salt);
    System.Security.Cryptography.SHA256Managed sha256hashstring =
        new System.Security.Cryptography.SHA256Managed();
    byte[] hash = sha256hashstring.ComputeHash(bytes);
    return Convert.ToBase64String(hash);
}
public void Submit1_click(object sender, EventArgs r)
{

    try
    {
        String salt = CreateSalt(10);
        String hashedpassword = GenerateSHA256Hash(password1.Text, salt);
        string MyConString = "SERVER=localhost;DATABASE=mydb;UID=root;PASSWORD=abc123;";
        MySqlConnection connection = new MySqlConnection(MyConString);
        string cmdText = "INSERT INTO authentication(agentlogin ,password ,question ,answer)VALUES ( @login, @pwd, @question, @answer)";
        MySqlCommand cmd = new MySqlCommand(cmdText, connection);
        cmd.Parameters.AddWithValue("@login", labeluname.Text);
        cmd.Parameters.AddWithValue("@pwd", hashedpassword);
        cmd.Parameters.AddWithValue("@question", ddlquestion.Text);
        cmd.Parameters.AddWithValue("@answer", txtanswer.Text);
        connection.Open();
        int result = cmd.ExecuteNonQuery();
        connection.Close();
        lblmsg.Text = "Registered succesfully";
        lblmsg.ForeColor = System.Drawing.Color.Green;
        Response.Redirect("index.aspx");
    }
    catch (Exception)
    {
        Console.Write("not entered");
        lblmsg.Text = "Registration failed!";
        lblmsg.ForeColor = System.Drawing.Color.Red;
        Response.Redirect("index.aspx");
    }
}

したがって、上記で完全に暗号化されたパスワードを取得しましたが、ここで入力したパスワードを使用してログインできなくなりました。ログイン時にパスワードを解除するにはどうすればよいですか?暗号化に使用したのと同じメソッドを使用してハッシュを解除できると考えましたが、ソルティングでは同じ値が返されません。以下は、検証ページのコードです

    public string GenerateSHA256Hash(String input)
    {
        byte[] bytes = System.Text.Encoding.UTF8.GetBytes(input);
        System.Security.Cryptography.SHA256Managed sha256hashstring =
            new System.Security.Cryptography.SHA256Managed();
        byte[] hash = sha256hashstring.ComputeHash(bytes);
        return Convert.ToBase64String(hash);
    }

    public void Login_click(object sender, EventArgs r)
    {
        String hashedpassword = GenerateSHA256Hash(txtpassword.Text);
        string MyConString = ConfigurationManager.ConnectionStrings["connStr"].ConnectionString;
        MySqlConnection con = new MySqlConnection(MyConString);
        MySqlCommand cmd = new MySqlCommand("select * from authentication where agentlogin=@username and password=@Word", con);
        cmd.Parameters.AddWithValue("@username", txtusername.Text);
        cmd.Parameters.AddWithValue("@Word", hashedpassword);
        MySqlDataAdapter sda = new MySqlDataAdapter(cmd);
        DataTable dt = new DataTable();
        sda.Fill(dt);
        con.Open();
        int i = cmd.ExecuteNonQuery();
        con.Close();
        if (dt.Rows.Count > 0)
        {
            Session["id"] = txtusername.Text;
            Response.Redirect("calendar.aspx");
            Session.RemoveAll();
        }
        else
        {
            lblmsg.Text = "Credential doesn't match!";
            lblmsg.ForeColor = System.Drawing.Color.Red;

        }

    }
4
prkash

ユーザーテーブルに列を作成するUsernameHashSalt

ユーザー登録

1)登録フォームでユーザーからの入力usernameまたはpasswordを取得します。

2)以下の方法で入力パスワードのハッシュとソルトを作成します。

public class HashSalt
{
    public string Hash { get; set; }
    public string Salt { get; set; }
}

public static HashSalt GenerateSaltedHash(int size, string password)
{
    var saltBytes = new byte[size];
    var provider = new RNGCryptoServiceProvider();
    provider.GetNonZeroBytes(saltBytes);
    var salt = Convert.ToBase64String(saltBytes);

    var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, saltBytes, 10000);
    var hashPassword = Convert.ToBase64String(rfc2898DeriveBytes.GetBytes(256));

    HashSalt hashSalt = new HashSalt { Hash = hashPassword, Salt = salt };
    return hashSalt;
}

Rfc2898DeriveBytesクラスは、RFC2898仕様を使用してハッシュを生成するために使用されます。これは、PBKDF2(パスワードベースのキー導出関数#2)と呼ばれる方法を使用し、現在IETF(インターネット技術標準化委員会)によって新しいアプリケーションに推奨されています。

3)次に、このHashおよびSaltをユーザーレコードとともにデータベースに保存しました。

public void Submit1_click(object sender, EventArgs r)
{
    //Your code here

    HashSalt hashSalt = GenerateSaltedHash(64, password1.Text);

    //Your code here

    cmd.Parameters.AddWithValue("@hash", hashSalt.Hash);
    cmd.Parameters.AddWithValue("@salt", hashSalt.Salt);

    //You code here
}

ユーザーログイン

1)ログインフォームでユーザーからの入力usernameまたはpasswordを取得します。

2)Login_clickデータベースからユーザー名ごとにユーザーを取得します。

3)格納されたHashおよびSaltを以下の関数に渡します。

public static bool VerifyPassword(string enteredPassword, string storedHash, string storedSalt)
{
    var saltBytes = Convert.FromBase64String(storedSalt);
    var rfc2898DeriveBytes = new Rfc2898DeriveBytes(enteredPassword, saltBytes, 10000);
    return Convert.ToBase64String(rfc2898DeriveBytes.GetBytes(256)) == storedHash;
}

4)次に、パスワードを確認してユーザーにログインします。

public void Login_click(object sender, EventArgs r)
{
    //You code here

    User user = GetUserByUsername(txtUsername.Text);

    bool isPasswordMatched = VerifyPassword(txtpassword.Text, user.Hash, user.Salt);

    if (isPasswordMatched)
    {
        //Login Successfull
    }
    else
    {
        //Login Failed
    }

    //Your code here
}

参照: 有効なパスワードハッシュ

11
er-sho

ソルトをパスワードに追加してハッシュする前に保存する必要があります。

したがって、誰かがログインしようとすると、パスワードと保存されているソルトを連結し、それをハッシュして、ベースの既存のハッシュと比較できます。

したがって、ユーザーテーブルには少なくとも次の3つの列が必要です:ユーザー名、ハッシュパスワード、ソルト

詳細な説明:ハッシュ関数は確定的ですが、元に戻すことはできないため、ユーザーが初めてパスワードを作成するときは次のようになります。

  • あなたは塩を生成します
  • あなたはパスワードとソルトを連結します
  • パスワードとソルトを連結した結果の文字列をハッシュします
  • ハッシュとソルトの両方を保存します

だからあなたは:hashedpassword = hashingfunction(password + salt)

ログインしようとすると:

  • 入力としてログインとパスワードを取得します
  • ログインを使用すると、ベースのハッシュとソルトを取得できます
  • あなたはすでにハッシュ関数を持っています
  • だからハッシュ関数を処理できます(password_entered_by_user + salt)
  • 結果をhashedpasswordと比較し、同じ場合はユーザーをログに記録します

ハッシュされたパスワードの隣にソルトを置いても安全性が低下することはありません。ソルトの目的は rainbowtable の使用を防ぐことです。

ほとんどの人が多くの異なる場所で同じパスワードとメールを再利用しているため、誰かがデータベースに侵入した場合、おそらくユーザーのメール+パスワードを狙います。

ハッシュ関数は元に戻せないため、攻撃者ができることは、パスワードを推測して辞書を作成することだけです。

guessed_password => hash(guessed_password)

例:

pet345 => 23FD7890F0F3FA3AE468F37CB900402A1F1977CF926F3452CA519056E16985AB
lola78 => 876B42DC10A0822CC52B894DC7517C784A542B43FB033B4A93635ADA67946B2E
lola79 => A7DCAF5195463FA367CDEA6F23688C1280EC98F4AF2B08BC3469D2496537D48D
lola80 => 8D8E1CF212F5DDC3CA1D510900382DF945625A9AE1584CE0D539B2C4D73717CB

hash(guessed_pa​​ssword)がデータベースにある場合、この(これらの)ユーザーのパスワードはguessed_pa​​sswordです。

彼は何十億ものguessed_pa​​sswordsを持つ辞書を生成でき、多くのユーザーは本当に強力なパスワードを使用していないため、彼は彼の辞書でかなりの数のユーザーハッシュを見つけることができるでしょう。したがって、彼が「lola80」と「lola79」のハッシュを生成し、これらが知っている2人のユーザーのパスワードである場合、彼はそれを知っています。

ここで、入力したすべてのパスワードにランダムなソルトを追加すると、ソルトごとに完全な辞書を生成する必要があります。

guessed_password + salt = hash(guessed_password + salt)

Salt '09ç@ p $ 'を持つユーザーAの場合、すべての単語が'09ç@ p $'で終わる完全な辞書を生成する必要があります。

ここで、ソルト「Yuè45gh」に関連付けられたユーザーBのパスワードを推測したい場合、すべての単語が「Yuè45gh」で終わる別の辞書を生成する必要があります。

基本的に、your_number_of_users係数によってユーザーのパスワードを推測するプロセスが遅くなります。

3
Maxime

暗号化に使用したのと同じメソッドを使用してハッシュを解除できると考えましたが、ソルティングでは同じ値が返されません。

ソルトメカニズムを介してソルトパスワードをもう一度送信し、ハッシュされていないクリアパスワードを期待したということですか?これは意味がありません。

したがって、パスワードをソルトしてどこかに保存しました。ここで行うことは、ユーザーがパスワードを入力すると、この新しいパスワードをソルトしてソルトされたパスワードを取得することです。次に、この新しいものを古いものと比較します。一致する場合、それは正しいパスワードでした。

0
RUL