当Python爬虫遇到CryptoJS加密

背景

有一个通讯录的网页,因为网站比较老旧,用户体验很不好。所以就想试着写一个更加易用的通讯录查询器。本文只讲了加密的这个过程,其中涉及到加密模式等的内容,可以参照PyCryptodome的文档,https://www.pycryptodome.org/en/latest/index.html,欢迎交流。

登录操作

分析网站的源码,登录时输入的密码会加密传输,加密方法如下:

document.forms[0].j_password.value = desEncrypt(document.forms[0].j_password.value);

从sources中找到了对应的js文件,又遇到了熟悉的 eval(function(p,a,c,k,e,d) 加密代码。这里附上一个在线解密代码的网站http://www.oicqzone.com/tool/eval/,可以一键生成源代码。下面是解密后的代码。

Com_RegisterFile("security.js");
Com_IncludeFile("aes.js");
Com_IncludeFile("base64.js");
var SECURITYKEY = {
    toHexString: function(str) {
        var temp = "";
        for (i = 0; i < str.length; i++) {
            temp += str.charCodeAt(i).toString(16)
        }
        return temp
    },
    _2: function() {
        $.ajax({
            async: false,
            dataType: "script",
            url: Com_Parameter.ResPath + "js/session.jsp?_=" + new Date().getTime()
        });
        var str = "";
        if (window.getSessionId) {
            str = getSessionId()
        }
        return str
    },
    supportEncodings: function() {
        return ["aes", "des"]
    },
    get: function(encodeType) {
        var str = SECURITYKEY._2();
        if (encodeType == null || encodeType == 'aes') {
            if (str.length < 32) {
                str += "abcdefghijklmnopqrstuvwxyz1234567890"
            }
            str = str.toUpperCase();
            var key = {};
            key.key = str.substring(0, 16);
            key.iv = str.substring(16, 32);
            key.security = "\u4435\u5320\u4d35"
        } else {
            if (str.length < 16) {
                str += "abcdefghijklmnopqrstuvwxyz"
            }
            str = str.toUpperCase();
            var key = {};
            key.key = SECURITYKEY.toHexString(str.substring(0, 8));
            key.iv = SECURITYKEY.toHexString(str.substring(8, 16));
            key.security = "\u4445\u5320\u4d45"
        }
        return key
    },
    getCookie: function(c_name) {
        if (document.cookie.length > 0) {
            var cookies = document.cookie.split(";");
            for (i = 0; i < cookies.length; i++) {
                var xc = cookies[i];
                var cn = xc.substring(0, xc.indexOf("=")).toUpperCase();
                cn = cn.replace(/^\s*/, "").replace(/\s*$/, "");
                if (cn == c_name) {
                    return unescape(xc.substring(xc.indexOf("=") + 1, xc.length))
                }
            }
        }
        return ""
    }
};
function base64Convert() {
    return "\u4241\u5345\u3634{" + Base64.encode(arguments[0]) + "}"
}
function _0(xForm) {
    if (xForm == null) {
        xForm = document.forms[0]
    }
    if (xForm != null) {
        if (xForm.encoding == "multipart/form-data") {
            return true
        }
    }
    return false
}
function _1(str, xForm, isX) {
    if (_0(xForm)) {
        return str
    } else {
        var val = str;
        if (str != null && str.length > 0) str = base64Convert(str);
        if (val != str) {
            if (isX == true) {
                val = "\u4645\u5810\u4d40" + str
            } else {
                val = "\u4649\u5820\u4d45" + str
            }
        }
        return val
    }
}
function desEncrypt(value, xForm, type) {
    if (_0(xForm)) {
        return value
    } else {
        var keyObj = {};
        if (type == null || "aes" == type.toLowerCase()) {
            keyObj = SECURITYKEY.get();
            value = CryptoJS.AES.encrypt(value, CryptoJS.enc.Utf8.parse(keyObj.key), {
                iv: CryptoJS.enc.Utf8.parse(keyObj.iv)
            }).toString()
        } else {
            keyObj = SECURITYKEY.get('des');
            value = CryptoJS.DES.encrypt(value, CryptoJS.enc.Hex.parse(keyObj.key), {
                iv: CryptoJS.enc.Hex.parse(keyObj.iv)
            })
        }
        return keyObj.security + value
    }
}
function base64Encode(str, xForm) {
    return _1(str, xForm)
}
function base64Encodex(str, xForm) {
    return _1(str, xForm, true)
}

分析后可以看到加密的过程大概是以下的步骤:

  1. 通过 _2获取浏览器的sessionID
  2. 通过get,将sessionID分为了key和iv
  3. 通过CryptoJS.AES.encrypt方法加密,这里的value是输入的password,第二个参数是key,第三个参数是偏移iv
CryptoJS.AES.encrypt(value, CryptoJS.enc.Utf8.parse(keyObj.key), {iv: CryptoJS.enc.Utf8.parse(keyObj.iv)
  1. 回传加密后的密钥

这里我们通过python来完成这个加密过程,以下是核心步骤,这里用到了python中CryptoJS的库,PyCryptodome。

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

# sessionid为浏览器获取到的sessionID
id2 = sessionid
# 转为byte型
pw = b'password'
# 根据js代码中的过程,将sessionid分为了key和iv,且要进行转码
key = id2[0:16].encode("utf-8")
iv = id2[16:32].encode("utf-8")
# 根据长度,keyObj.security
security = "\u4445\u5320\u4d45"
# 定义一个AES加密方法,key和iv为上述值,AES.MODE_CBC一般为默认的mode
aes = AES.new(key,AES.MODE_CBC,iv)
# 通过pad将密码进行转换
text=aes.encrypt(pad(pw, AES.block_size))
# base64转码
text=str(base64.encodebytes(text))
# 获取相应的字符串
j_password = text[2:][:-3]

后面就是利用加密后的j_password ,可以通过requests来请求sessionid来爬了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值