爬虫逆向加密技术详解之Base64编码(伪加密)

部署运行你感兴趣的模型镜像

一、Base64编码的起源

Base64 编码并非一种加密算法,它的起源可追溯到电子邮件诞生初期。在当时,电子邮件只能传输 ASCII 字符,而二进制文件(像图片、音频等)无法直接传输。为解决该问题,Base64编码应运而生,它将二进制数据转换为一种由64个可打印字符组成的字符串表示,从而方便在文本环境中传输复杂的数据。

二、Base64的应用场景

  1. 电子邮件附件:早期的电子邮件系统通过Base64编码来传输二进制附件。
  2. JSON数据传输:在网络通信中,将二进制数据(如图片、文件)的Base64编码嵌入到JSON对象中,便于跨域传输。
  3. URL编码:Base64编码常用于对URL中的参数进行编码,以确保参数的合法性。
  4. 数据存储:在某些需要存储二进制数据的系统中,先将其转换为Base64编码的字符串,可以简化存储和管理。
  5. 加密与解密:虽然Base64本身不是加密算法,但它常被用于加密数据的传输或存储前的编码处理。

三、Base64的编码与解码过程

3.1 Base64编码过程

  1. 分组:把原始二进制数据按每 3 个字节(即 24 位)一组进行划分。

  2. 拆分:每组 24 位再拆分成 4 个 6 位的小组。

  3. 补位:每个 6 位小组前面补 2 个 0,使其变成 8 位。

  4. 映射:将每个 8 位小组的值映射到 Base64 字符集里对应的字符。

  5. 填充:若原始数据长度不是 3 的倍数,剩余部分用=填充。

3.2 Base64解码过程

  1. 去除填充:把 Base64 编码字符串末尾的=去除。

  2. 映射:将每个 Base64 字符映射回对应的 6 位二进制值。

  3. 合并:把这些 6 位二进制值合并成 24 位一组。

  4. 拆分:每组 24 位拆分成 3 个 8 位字节。

四、如何一眼看出Base64编码?

4.1 验证字符集

检查密文字符串是否仅包含,Base64编码使用的字符集(64个字符):

A-Z24个大写字母
a-z:24个小写字母
0-9
+
/
=:用作填充字符

URL安全变种:在 URL 安全的 Base64 编码中,+/分别被-_替代,并且填充字符=会被省略

4.2 长度判断

验证密文长度:是否为4的倍数(或补齐后为4的倍数)。

4.3 搜索特征码

  • ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

  • ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789

4.4 使用工具验证

百度搜索Base64编码解码:通过解码工具或代码快速确认。

4.5 示例

下面是一些 Base64 编码字符串示例,你可以观察其特征:

  • SGVsbG8sIFdvcmxkIQ==:长度为 20(是 4 的倍数),由 Base64 字符集内的字符组成,末尾有两个填充字符 =。
  • dGVzdA==:长度为 8(是 4 的倍数),由 Base64 字符集内的字符组成,末尾有两个填充字符 =。
  • TWFu:长度为 4(是 4 的倍数),由 Base64 字符集内的字符组成,没有填充字符。

五、JavaScript实现Base64编码和解码

5.1 JavaScript原生实现Base64编码解码

编码函数 base64Encode

  • 把输入字符串转换为 UTF - 8 字节数组。
  • 每次处理 3 个字节的数据,将其组合成一个 24 位的组。
  • 把 24 位的组拆分成 4 个 6 位的组,再将每个 6 位组映射到 Base64 字符集对应的字符。
  • 若输入数据的长度并非 3 的倍数,使用 = 进行填充。

解码函数 base64Decode

  • 构建一个 Base64 字符到索引的映射表。
  • 去掉输入字符串末尾的填充字符 =。
  • 每次处理 4 个 Base64 字符,将它们转换为一个 24 位的组。
  • 把 24 位的组拆分成 3 个 8 位的字节。
  • 依据是否有填充字符,决定是否添加相应的字节到输出字符串。
  • 最后把输出字符串从 UTF - 8 字节数组转换回原始字符串。
function base64Encode(input) {
    const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    let output = '';
    let i = 0;

    // 将输入字符串转换为 UTF-8 字节数组
    const utf8Bytes = unescape(encodeURIComponent(input));

    while (i < utf8Bytes.length) {
        const byte1 = utf8Bytes.charCodeAt(i++);
        const byte2 = i < utf8Bytes.length ? utf8Bytes.charCodeAt(i++) : NaN;
        const byte3 = i < utf8Bytes.length ? utf8Bytes.charCodeAt(i++) : NaN;

        const group = (byte1 << 16) | ((byte2 || 0) << 8) | (byte3 || 0);

        const char1 = (group >> 18) & 63;
        const char2 = (group >> 12) & 63;
        const char3 = (group >> 6) & 63;
        const char4 = group & 63;

        output += base64Chars[char1];
        output += base64Chars[char2];
        output += isNaN(byte2) ? '=' : base64Chars[char3];
        output += isNaN(byte3) ? '=' : base64Chars[char4];
    }

    return output;
}

function base64Decode(input) {
    const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    const base64Map = {};
    for (let i = 0; i < base64Chars.length; i++) {
        base64Map[base64Chars[i]] = i;
    }

    input = input.replace(/=+$/, '');
    let output = '';
    let i = 0;

    while (i < input.length) {
        const char1 = base64Map[input[i++]];
        const char2 = base64Map[input[i++]];
        const char3 = base64Map[input[i++]];
        const char4 = base64Map[input[i++]];

        const group = (char1 << 18) | (char2 << 12) | ((char3 || 0) << 6) | (char4 || 0);

        const byte1 = (group >> 16) & 255;
        const byte2 = (group >> 8) & 255;
        const byte3 = group & 255;

        if (char3!== undefined) {
            output += String.fromCharCode(byte1);
        }
        if (char4!== undefined) {
            output += String.fromCharCode(byte2);
            output += String.fromCharCode(byte3);
        }
    }

    return decodeURIComponent(escape(output));
}

// 测试示例
const testString = 'Hello, World!';
const encoded = base64Encode(testString);
console.log('编码后:', encoded);
const decoded = base64Decode(encoded);
console.log('解码后:', decoded);

运行结果:

编码后: SGVsbG8sIFdvcmxkIQ==
解码后: Hello, World

特征码(重点)ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

5.2 内置API实现Base64编码解码

JavaScript提供了内置的btoa()atob()函数,分别用于Base64编码和解码。

// 待编码的二进制数据(字符串形式)
const binaryData = "Hello, World!";

// 使用 btoa() 进行 Base64 编码
const encodedData = btoa(binaryData);
console.log("编码后:", encodedData);  

// 使用 atob() 进行 Base64 解码
const decodedData = atob(encodedData);
console.log("解码后:", decodedData);

运行结果:

编码后: SGVsbG8sIFdvcmxkIQ==
解码后: Hello, World!

5.3 Buffer实现Base64编码解码

除了JavaScript内置的API外,许多第三方库也提供了Base64编码功能,如Node.js中内置的Buffer对象。

// Node.js 中使用 Buffer 对象进行 Base64 编码和解码
const binaryData = "Hello, World!";

// 编码
const buffer = Buffer.from(binaryData, 'utf8');
const encodedData = buffer.toString('base64');
console.log("编码后:", encodedData);

// 解码
const decodedBuffer = Buffer.from(encodedData, 'base64');
const decodedData = decodedBuffer.toString('utf8');
console.log("解码后:", decodedData);

运行结果:

编码后: SGVsbG8sIFdvcmxkIQ==
解码后: Hello, World!

5.4 CryptoJS实现Base64编码解码

// 引入 CryptoJS 库
const CryptoJS = require('crypto-js');

// 待编码的二进制数据(字符串形式)
const binaryData = "Hello, World!";

// 使用 CryptoJS 进行 Base64 编码
const wordArray = CryptoJS.enc.Utf8.parse(binaryData);
const encodedData = CryptoJS.enc.Base64.stringify(wordArray);
console.log("编码后:", encodedData);

// 使用 CryptoJS 进行 Base64 解码
const decodedWordArray = CryptoJS.enc.Base64.parse(encodedData);
const decodedData = decodedWordArray.toString(CryptoJS.enc.Utf8);
console.log("解码后:", decodedData);

运行结果:

编码后: SGVsbG8sIFdvcmxkIQ==
解码后: Hello, World!

5.5 Python实现Base64编码解码

Python中可以使用 base64 库对字符串进行 Base64 编码和解码:

import base64

# 待编码的二进制数据(字符串形式)
binary_data = "Hello, World!"

# 将字符串转换为字节类型
byte_data = binary_data.encode('utf-8')

# 使用 base64 进行编码
encoded_data = base64.b64encode(byte_data)
print("编码后:", encoded_data.decode('utf-8'))

# 使用 base64 进行解码
decoded_data = base64.b64decode(encoded_data)
print("解码后:", decoded_data.decode('utf-8'))

运行结果:

编码后: SGVsbG8sIFdvcmxkIQ==
解码后: Hello, World!

六、Base64小技巧扩展

个人经验总结:AES DES RSA加密最后都会调用一下Base64,那么在Base64(AES DES RSA)编码位置 或者 特征码位置 下断点,是不是就可以往前跟栈找到加密函数了???!!!

您可能感兴趣的与本文相关的镜像

Python3.11

Python3.11

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值