小黑在喜茶店点了一杯美式咖啡,整理了一下上周学习的路飞爬虫内容:base64编码 md5 aes常见的加密与解密实现

urlencode:对传递参数进行编码

# ASCII编码 GBK unicode utf8(针对ASCII一个字节,针对汉字三个字节)
from urllib import parse

# 值编码
value = parse.quote('&&222==333')
print(value)
# 键值编码
data = {'wd':'&&7www', 'name':'小黑'}
print(parse.urlencode(data))

%26%26222%3D%3D333
wd=%26%267www&name=%E5%B0%8F%E9%BB%91

base64编码

示例

import base64

s = '#!$'
print(s.encode())

print(bin(ord('#')))
print(bin(ord('!')))
print(bin(ord('$')))

# 001000 110010 000100 100100
# 8 50 4 36 ========> I y E k
ret = base64.b64encode(s.encode())
print(ret.decode())

b’#!$’
0b100011
0b100001
0b100100
IyEk

编码与解码

import base64



print('++++++++++++++案例1+++++++++++++')
# base64编码后结果
ret = 'IyEkPQ=='
# base64解码
ret = base64.b64decode(ret)
print(ret.decode())
print('++++++++++++++案例2+++++++++++++')
# 案例2
s = 'you!'
ret = base64.b64encode(s.encode())
print(ret.decode())
print(base64.b64decode(ret))

++++++++++++++案例1+++++++++++++
#!$=
++++++++++++++案例2+++++++++++++
eW91IQ==
b’you!’

RSA算法

生成公钥和私钥

from Crypto.PublicKey import RSA


# 构建RSA算法对象
rsakey = RSA.generate(1024)
# 生成公钥
# print('公钥:', rsakey.public_key().exportKey())
with open('rsa.public.pem', 'wb') as f:
    f.write(rsakey.public_key().exportKey())
# 生成私钥
with open('rsa.private.pem', 'wb') as f:
    f.write(rsakey.exportKey())
# print('私钥:', rsakey.exportKey())

公钥加密

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64


data = 'alex is a monkey!'

# rsa: 公钥加密私钥解密,用于数据加密
# rsa: 私钥加密公钥解密,用于数字签名

with open('rsa.public.pem', 'r') as f:
    pk = f.read()
    # 获取公钥对象
    rsa_pk = RSA.importKey(pk)
    # 获取rsa算法对象
    rsa = PKCS1_v1_5.new(rsa_pk)
    # 基于rsa进行加解密
    encrypt_data = rsa.encrypt(data.encode())
    print('encrypt_data:', encrypt_data)
    # 为了在网络中正确传输,进行一个base64封装
    base64_encrypt_data = base64.b64encode(encrypt_data)
    print('base64编码:', base64_encrypt_data.decode())

私钥解密

import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5


base64_encrypt_data = 'luWJ/+VE2DAMnTCk6ewOTUGc3Qkx0W4TIEtFGlCvr2dBNkbyiZvVMGHFcE+8p6/x+/saD0is='
# base解码
encrypt_data = base64.b64decode(base64_encrypt_data)
print('encrypt_data:', encrypt_data)
# 解密
with open('rsa.private.pem', 'r') as f:
    prikey = f.read()
    # 生成钥匙对象
    rsa_pk = RSA.importKey(prikey)
    # 生成算法对象
    rsa = PKCS1_v1_5.new(rsa_pk)
    # 解密
    data = rsa.decrypt(encrypt_data, None)
    print('解密原数据:', data)

md5

# 摘要算法 md5
from hashlib import md5, sha1, sha256, sha512

data = '123'
m = md5('yuanlaoshidashuaige'.encode())
m.update(data.encode())
print(m.hexdigest())
# 总结: 摘要算法
# (1) 不可逆
# (2) 相同值计算结果必相同
# (3) 不同值计算长度固定,内容不固定

# 摘要算法应用
# 数据库加密

AES(CBC)

加密

# AES对称加密
# 先加密,再base64编码
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import base64
# 原文数据,必须是16的倍数
data = 'alex is a monkey!'
data = pad(data.encode(), block_size=16)
print(data)
key = 'asdfghjkl1234567'.encode()    # 必须是16字节
iv = '1234567890abcdef' .encode()   # 必须是16字节
aes = AES.new(key=key, mode=AES.MODE_ECB)
aes = AES.new(key=key, mode=AES.MODE_CBC, IV=iv)
# 基于aes算法对象对数据做加密
encrypt_data = aes.encrypt(data)
print('ase加密:', encrypt_data)
# base64编码
b64encode_encrypt_data =  base64.b64encode(encrypt_data)
print(b64encode_encrypt_data.decode())

b’alex is a monkey!\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f’
ase加密: b’\xa8\x05\x9c\xaa5\xe2P1\xaamb\xc8\xdc\xb5\x12|\x93\xbbA<\xec\xf5\x94\x95n\xb0=B\x17\xf5\xa1p’
qAWcqjXiUDGqbWLI3LUSfJO7QTzs9ZSVbrA9Qhf1oXA=

解密

import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad

b64encode_encrypt_data = 'qAWcqjXiUDGqbWLI3LUSfJO7QTzs9ZSVbrA9Qhf1oXA='
print('base64编码: ', b64encode_encrypt_data, '准备进行base64解码')
# 先进行base64解码
encrypt_data = base64.b64decode(b64encode_encrypt_data)
print('encrypt_data:', encrypt_data, '准备进行AES的CBC解密')
# aes解密
key = 'asdfghjkl1234567'.encode()    # 必须是16字节
iv = '1234567890abcdef' .encode()   # 必须是16字节
aes = AES.new(key=key, mode=AES.MODE_CBC, IV=iv)
ret = aes.decrypt(encrypt_data)
print('解密结果:', ret, '准备去除填充')
# 去除填充
ret = unpad(ret, block_size=16)
print('去除填充后:', ret)

base64编码: qAWcqjXiUDGqbWLI3LUSfJO7QTzs9ZSVbrA9Qhf1oXA= 准备进行base64解码
encrypt_data: b’\xa8\x05\x9c\xaa5\xe2P1\xaamb\xc8\xdc\xb5\x12|\x93\xbbA<\xec\xf5\x94\x95n\xb0=B\x17\xf5\xa1p’ 准备进行AES的CBC解密
解密结果: b’alex is a monkey!\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f’ 准备去除填充
去除填充后: b’alex is a monkey!’

AES使用JS加密,python解密,爬取数据demo

js对参数params加密,发送给后端

   // 获取四大名著
    // js代码  JS:事件驱动
    var dom = document.getElementsByTagName("p")[1]
    function get_page_books (page) {
        // 查询参数
        var params = {
            'page':page.toString()
        }

        // 数据加密 aes-128
        function encrypt_data(data){

            // AES算法
            var key = CryptoJS.enc.Utf8.parse('0123456789abcdef');
            var iv = CryptoJS.enc.Utf8.parse('0123456789abcdef');
            // 待加密数据
            var plaintext = JSON.stringify(data);
            // 进行AES-128加密,使用CBC模式和PKCS7填充
            var encrypted = CryptoJS.AES.encrypt(
                plaintext, key, {
                    iv: iv,
                    mode: CryptoJS.mode.CBC,
                    padding: CryptoJS.pad.Pkcs7
                }
            );
            // 获取加密后密文
            var ciphertext = encrypted.toString()
            return ciphertext
        }
        var sign = encrypt_data(params);
        params.sign = sign;
        // 发送发ajax,应该JS的代码,但是JS
        $.ajax({
            url: "http://127.0.0.1:5000/books",
            type: "get",
            data: params,
            success: function (res) {
                console.log("res:::", res)
                // dom
                var p3 = $("p").eq(-1)
                p3.html(res.map(item=>`${item}`))

            }
        })

    }

后端python对比加密值是否正确

比对加密结果是否正确,如果正确则认定为正常用户请求,返回数据给前端正常数据,否则不返回数据。

def verify_sign(params, sign):
    try:
        # base64编码
        encrypt_data = base64.b64decode(sign)
        # AES解密,key,iv必须为16字节
        key = '0123456789abcdef'.encode()
        iv = '0123456789abcdef'.encode()
        aes = AES.new(key=key, mode=AES.MODE_CBC, iv=iv)
        data = aes.decrypt(encrypt_data)
        data = unpad(data, 16)
        print('解密成功')
        res = json.loads(data.decode())
        if res == params:
            print('比对成功!!请进')
            return True
        print('比对失败!')
    except Exception as e:
        print('解密报错', e)
        return False
@app.get("/books")
def get_books():
    # 查询参数
    params = request.args.to_dict()
    # 校验sign值
    if 'sign' not in params:
        return jsonify(['非法入侵!!滚出去'])
    sign = params.pop('sign')
    verify = verify_sign(params, sign)
    if not verify:
        return jsonify(['非法入侵!!滚出去'])
    page_num = int(params.get('page', 1))
    books = ["聊斋志异", "金瓶梅", "国色天香", "剪灯新话", "西游记", "三国演义", "水浒传", '大黑驴', '小黑驴', '宿舍黑驴']
    # random_books = random.sample(books, 4)
    start_index = (page_num - 1) * 2
    end_index = page_num * 2
    page_book_list = books[start_index:end_index]
    return jsonify(page_book_list)

爬虫通过手动加密,伪装成浏览器获取数据

import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import base64
import json
url = 'http://127.0.0.1:5000/books'
# 进行base64编码
for i in range(1, 6):
    param = {"page":str(i)}
    # json.dumps一定要去除空格
    s = json.dumps(param, separators=(',', ':'))
    # 填充,以便准备进行AES.CBC加密算法
    s = pad(s.encode(), block_size=16)
    #print(s)
    # 进行AES加密
    key = '0123456789abcdef'
    iv = '0123456789abcdef'
    # 构造AES对象
    aes = AES.new(key=key.encode(), iv=iv.encode(), mode=AES.MODE_CBC)
    s = aes.encrypt(s)
    #print(s)
    encrypt_data = base64.b64encode(s)
    # 构造请求参数
    param['sign'] = encrypt_data.decode()
    # 发送请求
    response = requests.get(url=url, params=param)
    print(response.json())

坑了小黑好长时间的bug,python中为了美化,序列化结果多加了一个空格:‘{“小黑黑”: “爱你哟”}’ ,而js序列号的结果是:‘{“小黑黑”:“爱你哟”}’ ),导致其json.dumps序列化结果与JS中JSON.stringify不一致,所以导致加密后对比失败!!!小黑通过调试了俩小时才发现(),解决方法是dumps函数中加入参数separators=(‘,’, ‘:’)

加油小黑黑,准备写入党申请书!!(上次打回来了)

小黑在喜茶店点了一杯美式咖啡,整理了一下上周学习的路飞爬虫内容:base64编码 md5 aes常见的加密与解密实现_第1张图片

你可能感兴趣的:(路飞JS逆向爬虫课程学习,学习,爬虫,前端)