爬虫圈,常见的加密手段,你应该了解一下
常见加密手段
实验介绍
本实验为大家介绍一下常见的加密技术,掌握之后,可以在反爬时加入各加密算法,从而提高爬虫采集难度,本实验为大家介绍三类加密,其一是消息摘要算法/签名算法,其二是对称加密,最后一种是非对称加密,每一类型,都通过 Python 代码进行实践。特别提醒,本实验内容不会对加密算法底层逻辑进行解析,学习重点在应用层。
知识点
- 消息摘要算法/签名算法实践
- 对称加密算法实践
- 非对称加密算法实践
消息摘要算法/签名算法
md5 加密
md5 信息摘要算法,是最常用的密码散列函数,其可以产生 128 位的散列值,也就是 128 个 0 和 1 的二进制串,由于长度太长,故将二进制转换成了 16 进制,每 4 位表示一个十六进制,因此常见的 md5 都是 32 位。
在实践中还存在 16 位的 md5 值,该值是将 32 位 md5 去掉前 8 位,去掉后 8 位得到。
在 Code
目录建立 15_demo
文件夹,然后创建 md5_demo.py
文件,示例代码如下所示:
import hashlib
my_str = '梦想橡皮擦'
hl = hashlib.md5()
hl.update(my_str.encode("utf8"))
hl_my_str = hl.hexdigest()
# 加密之后的数据
print(hl_my_str)
# 加入参数,防止被撞库
hl2 = hashlib.md5(bytes('加盐', encoding='utf-8'))
hl2.update(my_str.encode("utf-8"))
hl2_str = hl2.hexdigest()
print(hl2_str)
md5 信息摘要算法其不可逆,并且有如下特点:
压缩性:任意长度的数据,计算出 md5 长度固定;
易计算:md5 模块使用便捷,计算方便;
抗修改:md5 的原始数据做任何修改,都会导致 md5 发生变化;
抗碰撞:加参数之后,被撞库的概率极低。
SHA1 加密
SHA1 安全哈希算法,是一种数字签名算法,其基于 md5 ,加密后会产生一长度 160 位的散列值,比 md5 多了 32 位,故安全性更高,但速度较慢。
import hashlib
str = "梦想橡皮擦"
a = hashlib.sha1(str.encode("utf-8")).hexdigest()
print("sha1 加密前,字符串为",str)
print("sha1 加密后,字符串为",a)
对称加密算法
DES 加密
DES 是一种比较传统的数据加密标准,属于对称加密,即通过密钥可以还原密码为明文。
在 Python 中可以通过 pyDes 库实现,使用命令 pip3 install pyDes
安装库。
创建 des_demo.py
,代码如下所示:
import base64
from pyDes import *
Des_Key = "xiangpia" # 自定义 Key,长度为 8
Des_IV = "12345678" # 自定义 IV 向量
# 加密函数
def DesEncrypt(code, key=None, iv=None):
if key is None:
key=Des_Key
if iv is None:
iv=Des_IV
k = des(key, CBC, iv, pad=None, padmode=PAD_PKCS5)
EncryptStr = k.encrypt(code)
return base64.b64encode(EncryptStr)
# 解密函数
def DesDecrypt(encode, key=None, iv=None):
if key is None:
key=Des_Key
if iv is None:
iv=Des_IV
k = des(key, CBC, iv, pad=None, padmode=PAD_PKCS5)
b64str = base64.b64decode(encode)
return k.decrypt(b64str)
if __name__ == '__main__':
ret = DesEncrypt("hello lanqiao")
print(ret)
运行代码,得到下述输出:
上述代码中比较重要的内容如下所示:
# 加密核心函数
k = des(key, CBC, iv, pad=None, padmode=PAD_PKCS5)
其中 key 相当于是加密盐,CBC 是加密模式,iv 是加密向量,pad 填充值,padmode 是填充方式,具体说明如下:
初始向量
初始向量缩写为 iv,一般也称作初始变数,它可以与密钥结合使用,为固定长度的值,在实战中一般使用随机数初始化。
加密模式
目前主流的加密和数字认证算法,基本都采用块加密,即将明文分成大小相等的数据块,然后执行加密算法,常见的模式说明如下所示,有兴趣的可以单独进行深入学习:
ECB:电子密码本模式,密文被分隔成长度相等的块,单独进行加密;
CBC:密码块连接模式,使用循环的形式,将前一块的密文和当前块异或之后再加密;
CFB:密码反馈模式,翻转的 CBC 模式;
OFB:输出反馈模式;
CTR:计数器模式。
填充方式 padmode
由于 des 需要将明文分成大小相等的数据块,所以最后一块数据在加密前需要进行填充,常见的填充形式有:
PKCS7:假设数据长度需要填充 n 个字节,那就填充 n 个字节,并且每个字节的大小都是 n;
PKCS5:PKCS7 的子集,块大小固定为 8 字节;
ZeroPadding:所有字节填充为 0;
ISO10126:填充字节为随机数值。
AES 加密
AES 是一种高级加密标准,一般情况下用来替代 DES,故二者逻辑基本一致,实现该加密算法,需要使用 Crypto
库实现,先用命令 pip3 install pycryptodome
进行安装。
建立 aes_demo.py
文件,然后导入模块并定义全局变量。
import base64
from Crypto.Cipher import AES
iv = '1234567887654321'
key = 'xiangxiangxiang1'
data = 'hello lanqiao'
代码说明如下:
iv:初始向量;
key:密钥,长度是 128 bit,故使用长度为 16 的字符串;
data:待加密数据。
接下来编写加密函数:
import base64
from Crypto.Cipher import AES
iv = '1234567887654321'
key = 'xiangxiangxiang1' # 长度为 16
data = 'hello lanqiao'
# 由于 AES 区块固定为 128 bit,所以字节长度最低需要16位
def pad(data):
pad_data = data
for i in range(0, 16 - len(data)):
pad_data = pad_data + ' '
return pad_data
# 实现 AES 加密
def aes_encode(key, data):
# 将长度补齐到 16 位
if len(data) < 16:
data = pad(data)
# 初始化 aes 对象,模式为 CBC
aes_obj = AES.new(key.encode("utf-8"), AES.MODE_CBC, iv.encode("utf-8"))
# 执行加密方法
aes_en_str = aes_obj.encrypt(data.encode("utf-8"))
# 进行 base64编码
aes_en_str = base64.b64encode(aes_en_str)
# 转换成字符串
aes_en_str = aes_en_str.decode("utf-8")
return aes_en_str
if __name__ == '__main__':
data = aes_encode(key, data)
print(data)
密文解码函数如下所示:
def aec_de(key, data):
# 密文进行二进制编码
data = data.encode("utf-8")
# 解 base64 编码
data = base64.b64decode(data)
aes_de_obj = AES.new(key.encode("utf-8"), AES.MODE_CBC, iv.encode("utf-8"))
# 解密
aes_de_str = aes_de_obj.decrypt(data)
# 去空格
aes_de_str = aes_de_str.strip()
# 明文解码
aes_de_str = aes_de_str.decode("utf-8")
return aes_de_str
if __name__ == '__main__':
data = aes_encode(key, data)
ret = aec_de(key, data)
print(ret)
非对称加密算法
采用两个密钥进行加密和解密,对应的分别是公钥和私钥,如使用公钥对数据加密,则必须使用私钥解密。
RSA 加密算法
RSA 加密算法时常见的 非对称加密算法,该算法效率比较低,所以一般用于重要数据加密,在 Python 中可以使用 Crypto
库实现该算法,上文已经对该库进行了安装。
下面优先生成公钥和私钥。
from Crypto import Random
from Crypto.PublicKey import RSA
# 生成伪随机数
random_gen = Random.new().read
# 生成秘钥对实例对象,其中 1024 是秘钥的长度
rsa = RSA.generate(1024, random_gen)
# 获取私钥,保存到文件
private_pem = rsa.exportKey()
with open('private.pem', 'wb') as f:
f.write(private_pem)
# 获取公钥,保存到文件
public_pem = rsa.publickey().exportKey()
with open('public.pem', 'wb') as f:
f.write(public_pem)
公钥创建完毕之后,就可以使用其进行加密了,代码如下。
import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
msg = "梦想橡皮擦"
# 读取公钥
key = open('public.pem').read()
public_key = RSA.importKey(key)
# 加密
pk = PKCS1_v1_5.new(public_key)
encrypt_text = pk.encrypt(msg.encode())
# 加密后进行 base64 编码
result = base64.b64encode(encrypt_text)
# 转换成字符串
result_str = bytes.decode(result)
print(result)
print(result_str)
运行代码得到如下结果:
解密需要通过私钥进行,从 private.pem
读取私钥,然后调用 PKCS1_v1_5.new(private_key).decrypt()
方法即可实现,示例代码如下所示:
import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from Crypto import Random
key = open('private.pem').read()
private_key = RSA.importKey(key)
cipher = PKCS1_v1_5.new(private_key)
# random_generator = Random.new().read
# 待解密字符串:lwiHsq3ZCa6+AogrAm5fMAJrkFvWu5aT2D9znAo3JqnLez3GLvhofQzmI2QaNL5ToCxp9SnngsLiG4weE4V/tavy9q0hVjzHofWOPri4ZfdMFtKWsRUUZwR3ifNaJTmDcmGBX6su5ES3KgL7wGUF1qQgQcpEaY/aKKb/IP5fPJw=
text = cipher.decrypt(base64.b64decode("lwiHsq3ZCa6+AogrAm5fMAJrkFvWu5aT2D9znAo3JqnLez3GLvhofQzmI2QaNL5ToCxp9SnngsLiG4weE4V/tavy9q0hVjzHofWOPri4ZfdMFtKWsRUUZwR3ifNaJTmDcmGBX6su5ES3KgL7wGUF1qQgQcpEaY/aKKb/IP5fPJw="), None)
print(text.decode('utf8'))
运行代码可以得到前文加密内容,临摹该案例注意公钥和私钥的搭配使用。
Base64 编码
Base64 是一种常见 8 位字节编码方式,由于 Base64 编码不可读,所以其也会被用于加密,在 Python 中,可以使用内置 base64 模块进行编码和解码,注意只能用包含 ASCII 的字符或二进制数据进行编码。
示例代码如下所示:
import base64
a = base64.b64encode(b"hello world")
print(a)
b = base64.b64decode(b'aGVsbG8gd29ybGQ=')
print(b)
运行代码输出结果如下所示:
b'aGVsbG8gd29ybGQ='
b'hello world'
Base 64 编码经常出现在其它加密代码中,所以是必备技能。
总结
本实验为大家介绍了三大类加密方式,每种加密方式下都包含多种加密实现,学习不同的加密算法,并将其合理的应用到自己的站点中,可以整体提高爬取难度。
在后续的学习中,可以对每种加密算法进行深入学习,了解其原理和实现,从而在实战项目中,将多种加密手段搭配使用。
- 点赞
- 收藏
- 关注作者
评论(0)