☕ NEW! 完成新手任務即可參加抽獎!LINE 星巴克禮券等你拿,名額有限!        🎉 推廣活動:邀請好友註冊 DevLearn,累積推薦抽 LINE 星巴克禮券! 活動詳情 →        🔥 活動期間 2026/4/1 - 5/31 |已有 0 人參加       
資安 進階

加密與雜湊

雜湊(Hashing)vs 加密(Encryption)

💡 比喻

  • 雜湊 = 碎紙機:把文件丟進去,出來的碎紙無法還原成原文件。 用途:確認兩份文件是否相同(碎出來的樣子一樣就是同一份)
  • 加密 = 保險箱:把文件鎖進去,有鑰匙就能拿出來。 用途:保護文件不被別人看到,需要時可以解鎖取回

差異比較

特性            雜湊(Hash)           加密(Encryption)
──────────────────────────────────────────────────────
可逆性          不可逆(單向)          可逆(可解密)
用途            驗證完整性、密碼存儲    保護機密資料
輸出長度        固定長度               依輸入長度變化
鑰匙            不需要                 需要金鑰

雜湊演算法

MD5 和 SHA-256

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

// MD5 雜湊(128 位元,已不安全)
var md5Input = "Hello, World!";
// 計算 MD5 雜湊值
var md5Bytes = MD5.HashData(Encoding.UTF8.GetBytes(md5Input));
// 轉換成十六進位字串
var md5Hash = Convert.ToHexString(md5Bytes).ToLower();
// 輸出:65a8e27d8879283831b664bd8b7f0ad4
Console.WriteLine($"MD5: {md5Hash}");

// SHA-256 雜湊(256 位元,目前安全)
var sha256Input = "Hello, World!";
// 計算 SHA-256 雜湊值
var sha256Bytes = SHA256.HashData(Encoding.UTF8.GetBytes(sha256Input));
// 轉換成十六進位字串
var sha256Hash = Convert.ToHexString(sha256Bytes).ToLower();
// 輸出:dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f
Console.WriteLine($"SHA-256: {sha256Hash}");
雜湊的特性:
├── 相同輸入 → 永遠相同輸出
├── 微小變化 → 完全不同輸出(雪崩效應)
├── 無法從輸出反推輸入
└── 不同輸入可能相同輸出(碰撞),但機率極低

MD5 vs SHA-256:
├── MD5:速度快,但已被發現碰撞攻擊,不安全
└── SHA-256:目前安全,用於數位簽章、區塊鏈等

密碼雜湊:bcrypt 和 Argon2

為什麼不能用 SHA-256 存密碼?

SHA-256 太快了!駭客可以用 GPU 每秒嘗試數十億次。

bcrypt/Argon2 的設計:
├── 故意很慢(可調整難度)
├── 內建 Salt(防止彩虹表攻擊)
└── 每次雜湊結果都不同(因為 Salt 不同)

bcrypt 範例

// 安裝套件:dotnet add package BCrypt.Net-Next
using BCrypt.Net;

// 雜湊密碼(註冊時)
var password = "mypassword123";
// 自動產生 Salt 並雜湊,workFactor=12 控制難度
var hashedPassword = BCrypt.Net.BCrypt.HashPassword(password, workFactor: 12);
// 輸出類似:$2a$12$LJ3m4ys1Y2bCxYz...(每次都不同!)
Console.WriteLine(hashedPassword);

// 驗證密碼(登入時)
var inputPassword = "mypassword123";
// 比對使用者輸入的密碼和資料庫中的雜湊值
var isValid = BCrypt.Net.BCrypt.Verify(inputPassword, hashedPassword);
// 輸出:True
Console.WriteLine($"密碼正確:{isValid}");

// 錯誤密碼
var wrongPassword = "wrongpassword";
// 錯誤密碼會回傳 false
var isWrong = BCrypt.Net.BCrypt.Verify(wrongPassword, hashedPassword);
// 輸出:False
Console.WriteLine($"密碼正確:{isWrong}");

Salt(鹽)

什麼是 Salt?

Salt 是一串隨機字串,加在密碼前面再雜湊。

沒有 Salt 的問題:
├── 相同密碼 → 相同雜湊值
├── 駭客可以用「彩虹表」(預先計算好的雜湊對照表)快速破解
└── 一旦知道一個人的密碼,所有用同密碼的人都被破解

有 Salt:
├── "password123" + "abc" → 雜湊 A
├── "password123" + "xyz" → 雜湊 B(完全不同!)
└── 每個使用者有不同的 Salt,彩虹表無效
// 手動加 Salt 的概念(bcrypt 自動處理)
var password2 = "mypassword";
// 產生隨機 Salt
var salt = new byte[16];
RandomNumberGenerator.Fill(salt);
// 把 Salt 加在密碼前面
var saltedPassword = Convert.ToBase64String(salt) + password2;
// 再做雜湊
var hash = SHA256.HashData(Encoding.UTF8.GetBytes(saltedPassword));

// 注意:實務上請用 bcrypt 或 Argon2,它們自動處理 Salt

對稱加密:AES

對稱加密:加密和解密用同一把鑰匙

比喻:你和朋友各有一把相同的鑰匙,都能開同一個保險箱

優點:速度快
缺點:如何安全地把鑰匙給對方?
using System.Security.Cryptography;

// AES 對稱加密範例
public static class AesHelper
{
    // 加密
    public static byte[] Encrypt(string plainText, byte[] key, byte[] iv)
    {
        // 建立 AES 加密器
        using var aes = Aes.Create();
        aes.Key = key;   // 設定金鑰(256 位元)
        aes.IV = iv;     // 設定初始向量(128 位元)

        // 建立加密轉換器
        using var encryptor = aes.CreateEncryptor();
        // 把明文轉成 byte 陣列
        var plainBytes = Encoding.UTF8.GetBytes(plainText);
        // 執行加密,回傳加密後的 byte 陣列
        return encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
    }

    // 解密
    public static string Decrypt(byte[] cipherBytes, byte[] key, byte[] iv)
    {
        // 建立 AES 解密器
        using var aes = Aes.Create();
        aes.Key = key;   // 必須用相同的金鑰
        aes.IV = iv;     // 必須用相同的初始向量

        // 建立解密轉換器
        using var decryptor = aes.CreateDecryptor();
        // 執行解密
        var plainBytes = decryptor.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length);
        // 把 byte 陣列轉回字串
        return Encoding.UTF8.GetString(plainBytes);
    }
}

// 使用範例
var key = new byte[32]; // 256 位元金鑰
var iv = new byte[16];  // 128 位元初始向量
// 產生隨機金鑰和 IV
RandomNumberGenerator.Fill(key);
RandomNumberGenerator.Fill(iv);

// 加密
var encrypted = AesHelper.Encrypt("機密資料", key, iv);
// 解密(用相同的 key 和 iv)
var decrypted = AesHelper.Decrypt(encrypted, key, iv);
// 輸出:機密資料
Console.WriteLine(decrypted);

非對稱加密:RSA

非對稱加密:有兩把鑰匙——公鑰和私鑰

比喻:
├── 公鑰 = 郵筒的投信口(任何人都能投信進去)
└── 私鑰 = 郵筒的鑰匙(只有你能打開取信)

用公鑰加密 → 只有私鑰能解密
用私鑰簽章 → 公鑰可以驗證簽章
using System.Security.Cryptography;

// RSA 非對稱加密範例
using var rsa = RSA.Create(2048);  // 產生 2048 位元的金鑰對

// 匯出公鑰和私鑰
var publicKey = rsa.ExportRSAPublicKey();   // 可以公開給任何人
var privateKey = rsa.ExportRSAPrivateKey(); // 必須保密!

// 用公鑰加密(任何人都能加密)
var plainText = "機密訊息";
var plainBytes = Encoding.UTF8.GetBytes(plainText);
// 使用 OAEP 填充模式(比 PKCS1 更安全)
var encrypted2 = rsa.Encrypt(plainBytes, RSAEncryptionPadding.OaepSHA256);

// 用私鑰解密(只有持有私鑰的人能解密)
var decrypted2 = rsa.Decrypt(encrypted2, RSAEncryptionPadding.OaepSHA256);
// 把 byte 陣列轉回字串
Console.WriteLine(Encoding.UTF8.GetString(decrypted2));

HTTPS 與 TLS 憑證

HTTPS 結合了對稱和非對稱加密:

1. 非對稱加密(RSA)→ 安全地交換對稱金鑰
2. 對稱加密(AES)  → 之後的通訊都用快速的對稱加密

為什麼不全程用 RSA?
因為 RSA 太慢了!只用來交換 AES 的金鑰。

TLS 憑證的作用:
├── 證明伺服器的身份(CA 機構簽發)
├── 包含伺服器的公鑰
└── 瀏覽器用公鑰加密「對稱金鑰」傳給伺服器

🤔 我這樣寫為什麼會錯?

❌ 錯誤 1:用 MD5 或 SHA-256 存密碼

// ❌ 錯誤:用 SHA-256 雜湊密碼
var password3 = "user_password";
// SHA-256 太快了,駭客可以暴力破解
var hash3 = SHA256.HashData(Encoding.UTF8.GetBytes(password3));
// 存入資料庫...(危險!)

// ✅ 正確:用 bcrypt(故意很慢,防暴力破解)
var safeHash = BCrypt.Net.BCrypt.HashPassword(password3, workFactor: 12);
// bcrypt 自帶 Salt,每次結果不同
// 存入資料庫...(安全!)

❌ 錯誤 2:把金鑰寫死在程式碼中

// ❌ 錯誤:金鑰寫死在原始碼中
var secretKey = "my-super-secret-key-12345";  // 推上 Git 就洩漏了!

// ✅ 正確:從環境變數或 Secret Manager 讀取
// 開發環境用 User Secrets
// dotnet user-secrets set "Jwt:Key" "your-secret-key"
var secretKey2 = builder.Configuration["Jwt:Key"];

// 正式環境用環境變數或 Azure Key Vault
// 環境變數:export Jwt__Key="your-secret-key"
var secretKey3 = Environment.GetEnvironmentVariable("JWT_KEY");

❌ 錯誤 3:自己發明加密演算法

❌ 錯誤:「我把每個字元的 ASCII 碼加 3,這樣就加密了!」
這不是加密,這是凱薩密碼,2000 年前就被破解了。

✅ 正確:使用經過驗證的加密演算法
├── 對稱加密 → AES-256
├── 非對稱加密 → RSA-2048 或 ECDSA
├── 密碼雜湊 → bcrypt 或 Argon2
└── 雜湊 → SHA-256 或 SHA-3

永遠不要自己發明加密演算法!

💡 重點整理

概念 說明
Hash(雜湊) 單向不可逆,用於驗證和密碼存儲
Encryption(加密) 可逆,用於保護機密資料
bcrypt/Argon2 專門設計來存密碼的雜湊演算法(故意很慢)
Salt 隨機字串加在密碼前面,防止彩虹表攻擊
AES 對稱加密(同一把鑰匙加解密)
RSA 非對稱加密(公鑰加密、私鑰解密)
TLS HTTPS 底層,結合對稱和非對稱加密

💡 大家的想法 · 0

載入中...
💬 即時聊天室 🟢 0 人在線
😀 😎 🤓 💻 🎮 🎸 🔥
➕ 新問題
📋 我的工單
💬 LINE 社群
🔒
需要註冊才能使用此功能
註冊帳號即可解鎖測驗、遊戲、簽到、筆記下載等所有功能,完全免費!
免費註冊