什么是哈希函数?

哈希函数(Hash Function)是一种将任意长度的数据映射为固定长度字符串的算法。哈希函数具有以下特点:

  • 确定性:相同的输入总是产生相同的输出
  • 快速计算:能够快速计算出任意输入的哈希值
  • 雪崩效应:输入的微小变化会导致输出完全不同
  • 不可逆性:无法从哈希值反推出原始数据
  • 抗碰撞性:难以找到两个不同输入产生相同哈希值

支持的哈希算法

MD5128 位

Message Digest Algorithm 5,产生 128 位(16 字节)哈希值。

⚠️ 已被破解,不推荐用于安全场景
SHA-1160 位

Secure Hash Algorithm 1,产生 160 位(20 字节)哈希值。

⚠️ 已被破解,逐渐被淘汰
SHA-256256 位

SHA-2 家族成员,产生 256 位(32 字节)哈希值。

✅ 目前推荐使用
SHA-384384 位

SHA-2 家族成员,产生 384 位(48 字节)哈希值。

✅ 高安全性场景
SHA-512512 位

SHA-2 家族成员,产生 512 位(64 字节)哈希值。

✅ 最高安全性场景

哈希值示例

输入文本
Hello World
MD5
b10a8db164e0754105b7a99be72e3fe5
SHA-1
0a4d55a8d778e5022fab701977c5d840bbc486d0
SHA-256
a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e
SHA-512
2c74fd17edafd80e8447b0d46741ee243b7eb74dd2149a0ab1b9246fb30382f2...

编程语言中生成哈希

JavaScript / Node.js

const crypto = require('crypto');

// MD5(不推荐用于安全场景)
const md5 = crypto.createHash('md5').update('Hello World').digest('hex');
console.log(md5);

// SHA-256
const sha256 = crypto.createHash('sha256').update('Hello World').digest('hex');
console.log(sha256);

// SHA-512
const sha512 = crypto.createHash('sha512').update('Hello World').digest('hex');
console.log(sha512);

// 浏览器环境(Web Crypto API)
async function hash(text, algorithm = 'SHA-256') {
  const encoder = new TextEncoder();
  const data = encoder.encode(text);
  const hashBuffer = await crypto.subtle.digest(algorithm, data);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}

Python

import hashlib

text = 'Hello World'

# MD5(不推荐用于安全场景)
md5 = hashlib.md5(text.encode()).hexdigest()
print(md5)

# SHA-1
sha1 = hashlib.sha1(text.encode()).hexdigest()
print(sha1)

# SHA-256
sha256 = hashlib.sha256(text.encode()).hexdigest()
print(sha256)

# SHA-512
sha512 = hashlib.sha512(text.encode()).hexdigest()
print(sha512)

Java

import java.security.MessageDigest;

public class HashExample {
    public static String hash(String text, String algorithm) throws Exception {
        MessageDigest md = MessageDigest.getInstance(algorithm);
        byte[] digest = md.digest(text.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
    
    public static void main(String[] args) throws Exception {
        System.out.println(hash("Hello World", "MD5"));
        System.out.println(hash("Hello World", "SHA-1"));
        System.out.println(hash("Hello World", "SHA-256"));
        System.out.println(hash("Hello World", "SHA-512"));
    }
}

PHP

// MD5
$md5 = md5('Hello World');
echo $md5 . "\n";

// SHA-1
$sha1 = sha1('Hello World');
echo $sha1 . "\n";

// SHA-256
$sha256 = hash('sha256', 'Hello World');
echo $sha256 . "\n";

// SHA-512
$sha512 = hash('sha512', 'Hello World');
echo $sha512 . "\n";

// 支持的算法列表
$algorithms = hash_algos();
print_r($algorithms);

Go

package main

import (
    "crypto/md5"
    "crypto/sha1"
    "crypto/sha256"
    "crypto/sha512"
    "encoding/hex"
    "fmt"
)

func main() {
    text := []byte("Hello World")
    
    // MD5
    md5Hash := md5.Sum(text)
    fmt.Println(hex.EncodeToString(md5Hash[:]))
    
    // SHA-1
    sha1Hash := sha1.Sum(text)
    fmt.Println(hex.EncodeToString(sha1Hash[:]))
    
    // SHA-256
    sha256Hash := sha256.Sum256(text)
    fmt.Println(hex.EncodeToString(sha256Hash[:]))
    
    // SHA-512
    sha512Hash := sha512.Sum512(text)
    fmt.Println(hex.EncodeToString(sha512Hash[:]))
}

C#

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

class Program {
    static string Hash(string text, HashAlgorithm algorithm) {
        byte[] bytes = Encoding.UTF8.GetBytes(text);
        byte[] hash = algorithm.ComputeHash(bytes);
        return Convert.ToHexString(hash).ToLower();
    }
    
    static void Main() {
        Console.WriteLine(Hash("Hello World", MD5.Create()));
        Console.WriteLine(Hash("Hello World", SHA1.Create()));
        Console.WriteLine(Hash("Hello World", SHA256.Create()));
        Console.WriteLine(Hash("Hello World", SHA512.Create()));
    }
}

Ruby

require 'digest'

text = 'Hello World'

# MD5
puts Digest::MD5.hexdigest(text)

# SHA-1
puts Digest::SHA1.hexdigest(text)

# SHA-256
puts Digest::SHA256.hexdigest(text)

# SHA-512
puts Digest::SHA512.hexdigest(text)

Shell / 命令行

# MD5
echo -n "Hello World" | md5sum
# macOS: md5 -s "Hello World"

# SHA-1
echo -n "Hello World" | sha1sum

# SHA-256
echo -n "Hello World" | sha256sum

# SHA-512
echo -n "Hello World" | sha512sum

# OpenSSL 方式
echo -n "Hello World" | openssl dgst -sha256

哈希函数常见应用场景

🔐 密码存储

存储密码的哈希值而非明文,配合盐值使用提高安全性

📁 文件校验

验证文件完整性,检测文件是否被篡改或损坏

🔑 数字签名

对数据进行哈希后签名,确保数据来源可信

📦 数据去重

通过哈希值快速判断数据是否相同,用于去重

🗃️ 哈希表

数据结构中的哈希表,实现快速查找

⛓️ 区块链

区块链中区块链接和数据完整性验证

常见问题

Q: MD5 还能使用吗?

A: MD5 已被证明存在碰撞漏洞,不应再用于安全敏感场景(如密码存储、数字签名)。但仍可用于非安全场景,如文件校验、数据去重等。

Q: SHA-256 和 SHA-512 哪个更安全?

A: 两者都属于 SHA-2 家族,都足够安全。SHA-512 产生更长的哈希值,理论上更难碰撞,但 SHA-256 对于大多数应用已经足够。选择时主要考虑性能和存储需求。

Q: 为什么密码存储要加盐?

A: 加盐(Salt)可以防止彩虹表攻击。即使两个用户使用相同密码,由于盐值不同,哈希值也不同。建议使用 bcrypt、Argon2 等专门设计的密码哈希算法。

Q: 哈希值可以解密吗?

A: 哈希是单向函数,不可逆。无法从哈希值"解密"出原始数据。但可以通过彩虹表或暴力破解尝试找到产生相同哈希值的输入。