实用脚本能批量加盐吗?

wen 实用脚本 10

本文目录导读:

实用脚本能批量加盐吗?

  1. 核心概念回顾
  2. 方案一:Python 脚本(推荐,最灵活)
  3. 方案二:Bash + OpenSSL(Linux/Mac 环境)
  4. 方案三:Node.js (JavaScript)
  5. 核心总结与安全警告

“批量加盐”这个需求通常出现在需要对一批用户密码(或其他敏感数据)进行安全哈希处理的场景。能,而且非常实用。

如果你是在开发、测试或数据迁移中需要为大量账户生成带盐的哈希密码,使用脚本是标准做法。

下面提供几种主流脚本语言的批量加盐方案,你可以根据实际环境选择。


核心概念回顾

  • 加盐:在密码原文后(或前)拼接一个随机字符串(盐),然后再进行哈希。
  • 目的:防止彩虹表攻击,确保即使两个用户密码相同,存储的哈希值也不同。
  • 最佳实践:使用密码学安全的伪随机数生成器(CSPRNG)生成盐,并使用慢速哈希算法(如 bcrypt、argon2、PBKDF2)。切忌使用 MD5 或 SHA-1 等快速哈希。

Python 脚本(推荐,最灵活)

Python 的 passlibbcrypt 库是实现这一功能的最佳选择。

场景: 你有一个 CSV 文件(users.csv),包含用户名和明文密码,需要生成对应的哈希密码。

# users.csv
username,password
alice,password123
bob,letmein
charlie,Password!

使用 bcrypt(自动生成盐)

安装库:pip install bcrypt

import bcrypt
import csv
import os
def hash_password_bcrypt(password: str) -> str:
    # bcrypt.gensalt() 自动生成随机盐,rounds 控制计算成本(默认12,越慢越安全)
    salt = bcrypt.gensalt(rounds=12)
    hashed = bcrypt.hashpw(password.encode('utf-8'), salt)
    return hashed.decode('utf-8')
def process_file(input_file: str, output_file: str):
    with open(input_file, 'r') as infile, open(output_file, 'w', newline='') as outfile:
        reader = csv.DictReader(infile)
        # 在输出文件中添加 hash 字段
        fields = reader.fieldnames + ['hashed_password']
        writer = csv.DictWriter(outfile, fieldnames=fields)
        writer.writeheader()
        for row in reader:
            password = row['password']
            row['hashed_password'] = hash_password_bcrypt(password)
            writer.writerow(row)
if __name__ == "__main__":
    process_file('users.csv', 'users_hashed.csv')
    print("批量加盐哈希完成!输出文件: users_hashed.csv")

输出文件 users_hashed.csv 格式:

username,password,hashed_password
alice,password123,$2b$12$... (一串包含盐的bcrypt哈希)
bob,letmein,$2b$12$...
charlie,Password!,$2b$12$...

关键点: bcrypt 的哈希值本身就已经包含了盐,无需额外存储盐字段。

使用 hashlib + os.urandom(手动建 Salt)

如果你受限于环境,只能使用标准库,可以手动生成盐并拼接:

import hashlib
import os
import csv
def hash_with_salt(password: str, salt: bytes) -> str:
    return hashlib.pbkdf2_hmac(
        'sha256',
        password.encode('utf-8'),
        salt,
        100000  # 迭代次数,越高越安全
    ).hex()
def process_file(input_file: str, output_file: str):
    with open(input_file, 'r') as infile, open(output_file, 'w', newline='') as outfile:
        reader = csv.DictReader(infile)
        fields = reader.fieldnames + ['salt_hex', 'hash_hex']
        writer = csv.DictWriter(outfile, fieldnames=fields)
        writer.writeheader()
        for row in reader:
            salt = os.urandom(16)  # 每个用户生成唯一盐,建议16字节
            row['salt_hex'] = salt.hex()
            row['hash_hex'] = hash_with_salt(row['password'], salt)
            writer.writerow(row)
if __name__ == "__main__":
    process_file('users.csv', 'users_hashed.csv')

注意: 手动存盐,你需要同时存储 salt_hexhash_hex


Bash + OpenSSL(Linux/Mac 环境)

适合简单的、一次性的任务,但不推荐用于生产环境的安全敏感场景(OpenSSL 默认用 SHA256,不够专为密码设计)。

#!/bin/bash
# Input file example: passwords.txt
# Line format: username:password
# Output: username:hashed_password
INPUT_FILE="passwords.txt"
OUTPUT_FILE="hashed_passwords.txt"
> "$OUTPUT_FILE"
while IFS=':' read -r username password; do
    # 生成随机盐 (16字节, hex编码)
    salt=$(openssl rand -hex 16)
    # 使用 PBKDF2 (100,000 次迭代) 生成哈希
    # 注意: OpenSSL 1.1.1+ 支持 pbkdf2
    hash=$(echo -n "$password$salt" | openssl dgst -sha256 -binary | xxd -p -c 256)
    # 更安全的方式: 使用 openssl enc -pbkdf2 (但较复杂)
    echo "$username:$salt:$hash" >> "$OUTPUT_FILE"
done < "$INPUT_FILE"
echo "完成! 输出文件: $OUTPUT_FILE"

严重提醒: 这种纯 Shell 方法没有密码学伪随机数保证,且性能极快(容易被暴力破解),仅适用于非安全测试场景。


Node.js (JavaScript)

如果你所在团队主要用 JavaScript,这也是不错的选择。

安装依赖:npm install bcrypt

const bcrypt = require('bcrypt');
const fs = require('fs');
const readline = require('readline');
const csv = require('csv-parser'); // 需要安装: npm install csv-parser
const createCsvWriter = require('csv-writer').createObjectCsvWriter;
const inputFile = 'users.csv';
const outputFile = 'users_hashed.csv';
const SALT_ROUNDS = 12;
async function hashPassword(password) {
    const salt = await bcrypt.genSalt(SALT_ROUNDS);
    return await bcrypt.hash(password, salt);
}
async function processFile() {
    const results = [];
    const rl = readline.createInterface({
        input: fs.createReadStream(inputFile),
        crlfDelay: Infinity
    });
    // 简单 CSV 解析(或使用 csv-parser 库)
    const lines = fs.readFileSync(inputFile, 'utf8').split('\n');
    const headers = lines[0].split(',');
    for (let i = 1; i < lines.length; i++) {
        if (!lines[i].trim()) continue;
        const [username, password] = lines[i].split(',');
        const hashedPassword = await hashPassword(password);
        results.push({ username, password, hashedPassword });
    }
    const csvWriter = createCsvWriter({
        path: outputFile,
        header: [
            { id: 'username', title: 'username' },
            { id: 'password', title: 'password' },
            { id: 'hashedPassword', title: 'hashed_password' }
        ]
    });
    await csvWriter.writeRecords(results);
    console.log(`完成! 输出文件: ${outputFile}`);
}
processFile();

核心总结与安全警告

  1. 绝对不要用 “MD5 + 固定盐”,这等同于没加盐,彩虹表依然可以碰撞。
  2. 绝对不要用 “SHA-1 或 SHA-256 直接哈希密码 + 盐”,虽然加了盐,但现代 GPU 可以极高速度计算这些哈希,攻击者仍然可以暴力破解。
  3. 必须使用慢速哈希函数
    • 首选bcrypt(推荐,应用最广)
    • 次选argon2(抗 GPU 攻击能力最强,但库支持稍差)
    • 备选PBKDF2(标准库自带,可接受)
  4. 盐必须是唯一且随机的:每个用户的盐都不同,长度建议 16 字节或 22 字符(对于 bcrypt)。
  5. 存储哈希即存储盐:bcrypt 和 argon2 的哈希值自带盐,不需要额外字段,手动方式才需要存 salt_hex

你的最佳路径: 如果是在 Web 开发中,直接把上面方案一 Python 版(用 bcrypt)放入 pre-commit hook数据迁移流程 里,批量加盐处理结果可以直接导入数据库的密码字段。

如果需要修改这个脚本来适配你的特定文件格式,可以告诉我你的输入数据是什么样的(比如是 JSON/CSV/数据库导出的 SQL),我可以帮你调整解析逻辑。

抱歉,评论功能暂时关闭!