又有人在群里问,“Python怎么加密?”
这问题,真不是一两句话能说明白的。听着像个入门问题,但里头的道道儿,深着呢。很多人以为调个库、喊个函数就完事了,结果搞出来的东西,比纸糊的窗户还不经捅。今天,我就掰开了揉碎了,跟你聊聊这事儿。别指望我给你一套“万能代码”,我只告诉你,在不同的场景下,脑子该怎么转,手该怎么动。
先说说最常见的:密码,你可别再明文存了!
这是底线,也是红线。如果你还在把用户的密码原文直接塞进数据库,赶紧停下,现在,立刻,马上!
正确的姿势是啥?用哈希 (Hashing)。
啥是哈希?你可以把它想象成一个“数据指纹”生成器。无论你给它多长多复杂的数据(比如用户的密码),它都能给你返回一个固定长度的、看起来乱七八糟的字符串。这玩意儿有几个牛掰的特性:
- 不可逆:你从密码能算出哈希值,但从哈希值,你绝对、绝对、绝对算不回原来的密码。就像你把一头大象剁碎了做成香肠,你再也变不回那头活生生的大象了。
- 输入敏感:哪怕你输入的密码只改动一个字母,甚至一个大小写,生成的哈希值都会变得面目全非。
- 防碰撞(理论上):很难找到两个不一样的输入,它们能生成同一个哈希值。
Python里搞这个,用内置的hashlib
库就够了。比如用个现在还算皮实的SHA-256
算法:
“`python
import hashlib
password = “my_super_secret_password123”
必须编码成bytes
hashed_password = hashlib.sha256(password.encode(‘utf-8’)).hexdigest()
print(f”原始密码: {password}”)
print(f”哈希后: {hashed_password}”)
输出: 哈希后: 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8
“`
看到没?一串乱码,鬼知道原来是啥。
但是,这就安全了吗?天真了。如果两个用户设置了同一个密码,他们的哈希值也会一模一样。黑客们手里有个叫“彩虹表”的玩意儿,里面存着海量常用密码和它们对应的哈希值。一比对,你的裤衩都得被扒下来。
所以,专业选手都会加盐 (Salting)。
盐(Salt)是啥?就是一串随机生成的字符串,在给密码做哈希之前,先拼在密码上。每个用户的盐都必须是独一无二的!
“`python
import hashlib
import os
password = “my_super_secret_password123”
生成一个安全的随机盐
salt = os.urandom(16)
把盐和密码拼一起再哈希
hashed_password = hashlib.pbkdf2_hmac(
‘sha256’,
password.encode(‘utf-8’),
salt,
100000 # 迭代次数,越高越慢,越安全
)
存数据库的时候,要把盐和哈希后的密码一起存!
比如存成 “salt$hashed_password” 的格式
print(f”盐 (bytes): {salt}”)
print(f”加盐哈希后 (bytes): {hashed_password}”)
验证的时候,从数据库里把盐取出来,用同样的办法处理用户输入的密码,再比对结果。
``
pbkdf2_hmac`,它更专业,专门为密码哈希设计,还包含了迭代拉伸的功能,能大大增加暴力破解的难度。记住,存密码,必须用带盐的哈希,这是常识,也是职业道德。
这里我用了
当你需要“加密”也需要“解密”时:对称加密
哈希是单程票,有去无回。但很多时候,我们需要的是双程票。比如,你要在数据库里存一些敏感信息,像用户的身份证号、API密钥之类的,这些信息以后你还得拿出来用。这时候,对称加密就登场了。
对称加密,顾名思义,就是加密和解密用的是同一把密钥。就像你家的门锁,用同一把钥匙开,也用同一把钥匙锁。
Python里做这个,我强烈推荐cryptography
库,别去用那些老掉牙的pycrypto
或者pycryptodome
了,坑多。cryptography
的Fernet
模块,简直是为懒人准备的,封装得特别好,安全性也考虑得很周全。
“`python
from cryptography.fernet import Fernet
1. 生成一把密钥 (这步只需要做一次,然后把密钥安全地存起来!)
key = Fernet.generate_key()
print(f”生成的密钥: {key.decode()}”)
2. 用密钥创建一个加密器实例
cipher_suite = Fernet(key)
3. 要加密的数据
sensitive_data = b”This is my top secret user data!”
4. 加密
encrypted_data = cipher_suite.encrypt(sensitive_data)
print(f”加密后: {encrypted_data.decode()}”)
5. 解密 (用同一个cipher_suite,也就是同一把密钥)
decrypted_data = cipher_suite.decrypt(encrypted_data)
print(f”解密后: {decrypted_data.decode()}”)
“`
看起来很简单,对吧?但真正的难点,也是最容易出事的地方,是那个key
。你的密钥放哪儿?
- 硬编码在代码里?蠢哭了,代码一泄露,底裤都没了。
- 放配置文件里?稍微好点,但能接触到服务器的人,一个
cat
命令就看光了。 - 放环境变量里?也行,但还是在服务器上裸奔。
密钥管理,这才是对称加密的命门。专业的做法是用专门的密钥管理服务(KMS),比如AWS KMS、HashiCorp Vault等。对于小项目,也得想办法把密钥和代码、和普通配置文件隔离开,并且严格控制访问权限。密钥的生命周期管理,比加密算法本身复杂得多。
终极武器:非对称加密
对称加密最大的痛点是啥?密钥分发。我想给你发个加密消息,我得先把密钥安全地给你。可如果我俩之间已经有一条安全通道了,我还加密个鬼啊?这就有点“鸡生蛋还是蛋生鸡”的悖论了。
非对称加密就是来解决这个问题的。
这玩意儿有两把钥匙,一把叫公钥 (Public Key),一把叫私钥 (Private Key)。
- 公钥是公开的,你可以随便发给任何人,贴在脑门上都行。
- 私钥是你自己死死藏好的,打死都不能给别人。
它们的关系很奇妙:用公钥加密的数据,只有对应的私钥才能解开。
这就好比,你造了一个只能投信不能取信的邮箱(公钥),把它放在大马路上。任何人想给你写信,就把信塞进去。但只有你,拿着唯一的钥匙(私钥),才能打开邮箱看到信。
这在数据传输和数字签名领域,简直是神一般的存在。我们每天都在用的HTTPS,它的核心就是非对称加密。
在Python里,还是用cryptography
库来玩转RSA(一种常用的非对称加密算法)。
“`python
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization, hashes
1. 生成私钥和公钥
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
public_key = private_key.public_key()
(实际应用中,你会把私钥保存到安全的地方,把公钥分发出去)
2. 准备要加密的消息
message = b”This message is for your eyes only.”
3. 用公钥加密
encrypted = public_key.encrypt(
message,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
print(f”用公钥加密后,内容很长…”)
4. 用私钥解密
decrypted = private_key.decrypt(
encrypted,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
print(f”用私钥解密后: {decrypted.decode()}”)
“`
非对称加密虽然强大,但它也有个缺点:慢。它的计算量比对称加密大得多,不适合用来加密大块的数据。
所以,在实际应用中,大家都是“混合双打”:
- 用非对称加密(比如RSA)来安全地传输一个对称加密的密钥。
- 然后双方用这个对称密钥,通过对称加密(比如AES,Fernet底层就是它)来高速地传输真正的大量业务数据。
这就是HTTPS干的事。
总结一下,到底该用哪个?
别再问“Python怎么加密”这种笼统的问题了,先问问你自己,你的场景是啥?
- 存用户密码? -> 加盐哈希 (
hashlib.pbkdf2_hmac
),没得商量。 - 加密自己应用内部的数据,且数据需要被还原? -> 对称加密 (
cryptography.fernet
),速度快,但你得操心密钥怎么存。 - 需要跟别人安全地通信,或者搞数字签名验证身份? -> 非对称加密 (
cryptography
的RSA模块),或者更现代的ECC。它是解决信任和密钥分发问题的钥匙。
最后,记住一句大白话:安全是个系统工程,不是一个函数调用。你代码里的加密逻辑写得再天花乱坠,服务器被人黑了,密钥被人从内存dump走了,一切都是白搭。别迷信任何单一的技术,时刻保持敬畏。
评论(0)