反爬(五)

反爬五

这一次针对此网站的破解,这次的网站破解过程没有前两面的那么复杂(当然对大佬来讲前面几个也是小菜一碟),下面开始介绍这次的破解过程吧。

这里要说明的一点是一开始我也不知道这个网站有加密,直接构造参数做POST请求毫无问题,但是当持续爬取后出现请求被限制的相关问题,才逐渐开始发现问题并解决问题。

1、构造参数做post请求

post请求的具体参数如图中所示,其中比较重要的是queryCondition,其为一个列表类型,每个元素是一个json对象(Python字典对象),并且支持添加多个元素,对应处罚种类、年份等,包括种类、年份以及地区代码等如何设置其实有一个文件写的非常清楚,直接在下面的search框中,搜索诸如“21_s”之类的关键字,就能找到相应的文件,这里不再多说。

这里的ciphertext参数一开始看不出来什么线索,第一反应这可能是个固定的参数值,直接复制到代码中请求果然可以成功请求到数据,可是后来持续爬取了一会发现就爬不到数据了,调式发现请求返回“你的请求已被限制”此类的信息。后来想到可能这个参数有问题,去浏览器中复制了一个新的到程序中执行又可以正常跑,所以此时才明确这个参数不是固定的,会动态变化,所以要去从网站源码中找出其是如何生成的。

2、寻找关键参数ciphertext

非常容易想到的方式就是在下面的搜索框中输入ciphertext进行搜索,然后很轻松的就找到了这样一串代码:

可以清楚地看到,ciphertext参数的值是由ciper函数返回的,下面就是去看ciper函数的功能,接着通过查找我们发现有这样一行代码:var ciper=cipher(),这有点像个小陷阱的意思,如果我们不注意看,一直搜索ciper就啥也找不到了,但是如果搜索cipher一下就找到了下面的核心代码:

这段代码并不复杂,可以很清楚的看到就是对当前时间进行了某些处理,然后将处理好的三个参数传入加密函数,对得到的返回值再进行二进制转换。其中最核心的就是加密函数,接下来看下加密函数到底是什么样的:

3、扣出网站中相关的源代码,使其可以正常执行

配合这个具有良好素养的程序员的注释,我们也是看得一清二楚,这里分别定义了一个加密函数一个解密函数,其实解密函数我们可以不用管,想必是他后台做校验用的,我们只需要调用这个加密函数就行了,可以看到这里用到了CryptoJS,似曾相识,没错前面反爬二里就有遇到,这里不再细讲了,即使没见过相信上网查阅相关资料也可以弄清楚。所以我们自然而然生成了这样一个js文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
const CryptoJS=require('crypto-js')

function random (size){
var str = "",
arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
for(var i=0; i<size; i++){
// Math.round()把不同的数舍入为最接近的整数
str += arr[Math.round(Math.random() * (arr.length-1))];
}
return str;
}

var DES3 = {
iv: function(){
return formatDate(new Date(), "yyyyMMdd");
},
// 3DES加密,使用PKCS7 padding
encrypt : function(input, key, vector) {
if (key) {
return (CryptoJS.TripleDES.encrypt(input, CryptoJS.enc.Utf8.parse(key), {
iv: CryptoJS.enc.Utf8.parse(vector||DES3.iv()),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})).toString();
}
return "";
},
// //3DES解密,CBC/PKCS5Padding
decrypt : function(input, key, vector) {
if (key) {
return CryptoJS.enc.Utf8.stringify(CryptoJS.TripleDES.decrypt(input,
CryptoJS.enc.Utf8.parse(key), {
iv: CryptoJS.enc.Utf8.parse(vector||DES3.iv()),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})).toString();
}
return "";
}
};

function strTobinary(str) {
var result = [];
var list = str.split("");
for (var i = 0; i < list.length; i++) {
if (i != 0) {
result.push(" ");
}
var item = list[i];
var binaryStr = item.charCodeAt().toString(2);
result.push(binaryStr);
};
return result.join("");
}

function cipher() {
var date = new Date();
var timestamp = date.getTime().toString();
var salt = random(24);
var year = date.getFullYear().toString();
var month = (date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date
.getMonth()+1).toString();
var day = (date.getDate() < 10 ? "0" + date.getDate() : date.getDate())
.toString();
var iv = year + month + day;
var enc = DES3.encrypt(timestamp, salt, iv).toString();
var str = salt + iv + enc;
var ciphertext = strTobinary(str);
return ciphertext;
}

console.log(cipher())

执行一下运行结果为:

1
110110 1100100 1010111 1010111 1111001 1100011 1001000 1010111 1010110 110110 1110001 1110000 1001001 1101000 1100011 1110100 110111 1100010 1000001 1110000 1010011 110110 1110110 1110110 110010 110000 110010 110000 110000 110001 110001 110011 1010110 1000111 1011010 101011 1110110 1110000 1001000 1110101 1000011 1100100 1101101 1001111 1101000 1100001 1100111 1000010 1101100 110110 1110101 1001101 1001010 1010001 111101 111101

没毛病,就是我们想要的内容。

4、将其布置为js服务,供程序调用

因为这段js代码导入了外部包crypto-js,所以是无法直接使用Python执行这段js的,我们只能将其布置为js服务, 然后使用Python调用即可。

只需要在上述js代码最后加上:

1
2
3
4
5
6
7
8
module.exports = function marketregulationHandler(){
try {
return cipher()
} catch (err) {
console.error(err.message)
return ''
}
}

相应地,按照反爬二文章中给出的server.js代码,我们只要导入这个文件,并添加相应的路由,就可以了。

5、再说点其他的

基于上面的问题,是否除了使用js服务的方式,真的不能通过Python来执行所有的代码吗?其实不然,如果对CrytoJS或者DES3等技术有所了解,其实DES3是一种常见的加密算法,既然是加密算法,就不局限于某一种语言,每种语言肯定都有自己的实现方法,相应的python也有实现该算法的相应的包,网上出现过cryptopycrypto以及pycryptodome等库的介绍,具体哪个可以用,或者更好用我没有尝试,有兴趣的可以自己去尝试下。

此外,常见的加密算法还有以下这些:

对称加密(加密解密密钥相同):DES、DES3、AES

非对称加密(分公钥私钥):RSA

信息摘要算法/签名算法:MD5、HMAC、SHA

这里记录以下常见算法的名字,加深下印象,如果以后再遇到这些可以快速地看穿网站的意图,寻找解决办法。