Day 4 - Using Argon2 for Salted Password Hashing with ASP.NET Web Forms C# 使用 Argon2 替密码加盐後杂凑加密

=x= 🌵 User Manager - Content Page 替後台管理者密码加盐加密。


密码加盐加密介绍 :

📌 後台的所有页面建议可先上网找套版用的免费资源,由於要讲到密码加密,所以先从存资料开始,後面会再回头讲登入页如何验证密码,本篇重点在於使用 Argon2 替密码加盐後加密再存到资料库,流程为新增使用者的帐号密码後,会先判断帐号是否重复,如果帐号重复则拒绝,帐号不重复则进行密码加密流程,密码加密前先用盐(Salt)产生随机一段字串,并将盐存入资料库,然後将密码与盐组成一段字串再进行杂凑(Hash),结合处理完的密码才存到资料库,盐要分开存的原因是因为之後登入时要用来验证密码,更详细的观念可以参考下面提供的连结。

本来一开始没做加密,後来随便找了内建的 SHA256 做加密,再後来看到後端版再聊加密的事就认真看完讨论串,开始爬专有名词,也了解加盐可以增加原本密码的复杂度增加安全性,密码是先加盐再杂凑加密,不要顺序搞混很重要,而由於杂凑是不可从结果逆推回原始输入的演算法,所以输入的内容复杂度就很重要,可以降低被暴力破解的可能,这也是为什麽要密码要加盐的原因,了解後就试着跟着做做看吧!

👀 杂凑跟加密的不同参考文章 : Password Storage Cheat Sheet

👀 入门强烈推荐好文1 : 听说不能用明文存密码,那到底该怎麽存?

👀 入门强烈推荐好文2 : 密码存明码,怎麽不直接去裸奔算了?浅谈 Hash , 用杂凑保护密码

🧠 上面有提到加盐,一开始听到加盐其实搞不太懂到底在做啥,看完文章才有概念。

👹 题外话: 想查加密原理时,很常在讨论看到类似"你是真的想知道,还是你想做什麽 ?"



User Manager - Argon2 加密实作 :

🧠 前面提到因为看到後端版在讨论加密,建议使用 bcrypt 或 Argon2 但後者好像更优,所以最後选择 Argon2 的来实作。

👀 实作参考资源 : How to Use Argon2 for Password Hashing in C#

👀 同上作者内文提到的必读好文 : How to Securely Store a Password

👀 Argon2 维基百科介绍 : https://en.wikipedia.org/wiki/Argon2

👀 Wikipedia 相关参考知识 : key derivation function (KDF)Key stretchingCryptographic hash functionSalt (cryptography)BLAKE (hash function)

🦠 嗯~ 很多看不懂的东西呢~ 开始实作~

1. MSSQL 建立 Tayana 资料库并新增管理者资料表

https://ithelp.ithome.com.tw/upload/images/20210918/20139487vCKNqQkyVd.jpg

  • 资料表大概长这样,account 可以右键修改 "索引键" 将型别设成 "唯一索引键",避免自己手残乱加,C# 後置程序码也会先做检查有无重复的帐号才加入帐号。

2. 建立套版的 Master Page 并增加使用者管理的排版 Content Page

https://ithelp.ithome.com.tw/upload/images/20210918/20139487M4F8gQuUYx.jpg


3. 在後置程序码中拿掉象徵老板 ID 1 的删除键避免老板删除自己 ? !

  • 在 .aspx 的 GridView 新增 OnDataBound 事件,事件後置程序码参考如下 :
protected void OnDataBind(object sender, EventArgs e)
{
    GridView1.Rows[0].Cells[6].Controls.Clear();
}
  • 🙈 ( 这样老板就能改内容,可以删掉别人,但是不能删掉自己搂~ )

  • 👀 GridView 资料系结选择不把密码秀出来,因为不想处理加密过的密码,减少制作时的难度。

4. 去 Nuget 安装 Konscious.Security.Cryptography.Blake2

https://ithelp.ithome.com.tw/upload/images/20210918/201394871V941SiZG2.jpg


5. 後置程序码加入 Argon2 加密功能如下

using System.Security.Cryptography;
using System.Text;
using Konscious.Security.Cryptography;

// Argon2 加密
//产生 Salt 功能
private byte[] CreateSalt()
{
    var buffer = new byte[16];
    var rng = new RNGCryptoServiceProvider();
    rng.GetBytes(buffer);
    return buffer;
}
// Hash 处理加盐的密码功能
private byte[] HashPassword(string password, byte[] salt)
{
    var argon2 = new Argon2id(Encoding.UTF8.GetBytes(password));

        //底下这些数字会影响运算时间,而且验证时要用一样的值
    argon2.Salt = salt;
    argon2.DegreeOfParallelism = 8; // 4 核心就设成 8
    argon2.Iterations = 4; // 迭代运算次数
    argon2.MemorySize = 1024 * 1024; // 1 GB

    return argon2.GetBytes(16);
}

6. 在新增按钮点击事件中,进行检查帐号有无重复、取栏位填入密码并与新增的盐一起加密、资料库新增"帐号"+"密码加盐加密後的结果"+"盐"

protected void BtnAddAccount_Click(object sender, EventArgs e)
{
    bool haveSameAccount = false;

    SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
    string sqlCheck = "SELECT * FROM managerData WHERE account = @account";
    string sqlAdd = "INSERT INTO managerData (account, password, salt) VALUES(@account, @password, @salt)";
    SqlCommand commandCheck = new SqlCommand(sqlCheck, connection);
    SqlCommand commandAdd = new SqlCommand(sqlAdd, connection);

    //检查有无重复帐号
    commandCheck.Parameters.AddWithValue("@account", TBoxAddAccount.Text);
    connection.Open();
    SqlDataReader readerCountry = commandCheck.ExecuteReader();
    if (readerCountry.Read()) {
        haveSameAccount = true;
        LabelAdd.Visible = true; //帐号重复通知
    }
    connection.Close();

    //无重复帐号才执行加入
    if (!haveSameAccount) {
        //Hash 加盐加密
        string password = TBoxAddPassword.Text;
        var salt = CreateSalt();
        string saltStr = Convert.ToBase64String(salt); //将 byte 改回字串存回资料表
        var hash = HashPassword(password, salt);
        string hashPassword = Convert.ToBase64String(hash);

        commandAdd.Parameters.AddWithValue("@account", TBoxAddAccount.Text);
        commandAdd.Parameters.AddWithValue("@password", hashPassword);
        commandAdd.Parameters.AddWithValue("@salt", saltStr);

        connection.Open();
        commandAdd.ExecuteNonQuery();
        connection.Close();
        //画面渲染
        GridView1.DataBind();
        //清空输入栏位
        TBoxAddAccount.Text = "";
        TBoxAddPassword.Text = "";
        LabelAdd.Visible = false;
    }

}


7. 检查资料表是不是有成功存进资料,完成~



本日总结 :

📢 密码学的东西由於非本科,老实说看不太懂,所以只能尽量跟着参考文章进行,不过看完找到的入门强烈推荐好文,觉得懂了好多东西,有原来加盐要这样加的体悟,虽然维基百科的内容有超级多看不懂的地方,不过还是很有趣,实作的 SQL 写法也都用最简单就能做到的方式,希望大家看得懂。

  • 明日将介绍如何制作後台登入页及 Argon2 如何验证密码。

<<:  Annotation Processor 的运作

>>:  Indexed Element、请 TWGL 替程序码减肥

Day 29 实作 admin_bp (2)

前言 快要结束了,今天要继续写 admin_bp。今天的内容会用到 JS,但我不会多加解释。 pos...

Excel删除100个空白行,同事都只用5秒钟搞定!

在工作中或多或少都会遇到空白行存在的情况。如果只有几个空白行,那麽手动轻松删除即可,但是遇到100行...

D04 / 可不可以用 ConstraintLayout - ConstraintLayout

今天大概会聊到的范围 Constraint Layout in Compose 上一篇提到,有 R...

Day 26 测试 React 元件:使用 React Testing Library 体验 Test Driven Development (TDD) - 6

前面几天我们已经用 TDD 的方式完成了 <Editor /> 元件,但不要忘了 TDD...

Day4 Redis组态档设定-GENERAL

Redis.config SIZE 注意size设定可以用以下方式,不分大小写,但k 与 kb 代表...