使用 Python 执行 JavaScript

news2024/9/21 10:59:10

案例引入

网站: https://spa7.scrape.center

这里是一个简单的 NBA 球星的网站, 用卡片形式展示了一些球星的基本信息。另外,每张卡片其实都有一个加密字符串,这个加密字符串其实和球星的信息是由关联的, 并且每个球星的加密字符串也是不同的。

所以,这里我们要做的就是找出这个加密字符串的加密算法并且用程序把加密字符串的生成过程模拟出来

准备工作

这里我们要使用 Python 来执行 JS , 需要用的库叫作 PyExecJS 

安装: pip install pyexecjs

PyExecJS 是用于执行 JS 的, 但执行 JS 的功能需要依赖于 JS 的运行环境, 所以除了安装这个库之外,还需要一个 JS 的环境, 例如 Node.js , 具体安装方式请查阅资料

都安装好之后检测环境

import execjs

print(execjs.get().name)

Node.js (V8)

如果你成功安装了,那么对应的输出就一样,如果是其他环境,那么就找对应的测试方法

分析

我们在这里很快就可以找到加密字符串的生成逻辑(因为这里主要说的是在 Python 执行 JS)

这里首先声明了 球员的列表, 然后对每个球员调用加密算法对其进行信息加密,这里加入断点看一下,其实 getToken 方法的输入就是单个球员的信息, 就是上面列表的每个元素信息,this.key 就是一个固定的字符串。整个加密逻辑就是提取球员的各项信息,先进行 Base64 编码,然后进行 DES 加密,最后返回结果

加密算法怎么实现的呢 ? 其实是依赖了 crypto-js 库, 使用 CryptoJS 对象来实现的。

那么 , CryptoJS 这个对象哪里来的呢? 其实这个网站直接引用 crypto-js 库

执行 crypto-js 库对应的这个 JS 文件之后 , CryptoJS 就会被注入浏览器全局环境下,一次我们就可以在别的方法里直接使用 CryptoJS 对象里的方法了

模拟调用

首先我们要模拟的其实就是 getToken 方法, 输入球员相关信息,得到最终的加密字符串。这里我们直接把 key  替换下, 把 getToken 方法稍微改写一下

function getToken(player) {
    let key = CryptoJS.enc.Utf8.parse("fipFfVsZsTda94hJNKJfLoaqyqMZFFimwLt");
    const {name, birthday, height, weight} = player;
    let base64Name = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(name));
    let encrypted = CryptoJS.DES.encrypt(
        `${base64Name}${birthday}${height}${weight}`,
        key,
        {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7,
        }
    );
    return encrypted.toString();
}

因为这个方法的模拟执行需要 CryptoJS 对象, 如果我们直接调用这个方法,肯定会报 CryptoJS 未定义的错误

我们只需要再模拟执行一下刚才看到的 crypto-js.min.js 就好了

因此我们需要模拟执行的内容就是一下两部分

1. 模拟运行 crypto-js.min.js 里面的 JavaScript 。 用于声明 CryptoJS 对象

2. 模拟运行 getToken 方法的定义,用于声明 getToken 方法

接着我们就把 crypto-js.min.js 里面的代码和 上面的 getToken 方法的代码复制一下,都粘贴到一个 JS 文件里面, 比如叫作 crypto.js 

接下来,我们就用  PyExecJS 模拟执行一下

import execjs
import json

item = {
    'name': '凯文-杜兰特',
    'image': 'durant.png',
    'birthday': '1988-09-29',
    'height': '208cm',
    'weight': '108.9KG'
}
file = 'crypto.js'
node = execjs.get()
ctx = node.compile(open(file).read())

js = f"getToken({json.dumps(item, ensure_ascii=False)})"
print(js)
result = ctx.eval(js)
print(result)

这里单独定义了一个球员的信息, 并将其赋值 item 变量。然后使用execjs 的 get 方法获取 JS 执行环境, 赋值为 node

接着我们调用 node 的 compile 方法, 这里给它传入刚才定义的 crypto.js 文件的文本内容。 compile 方法会返回一个 JS 的上下文对象, 我们将其赋给 ctx 。 执行到这里,其实就可以理解为, ctx 对象里面就执行过了 crypto-js.min.js , CryptoJS 就声明好了,然后紧接着 getToken 方法的声明代码也被执行,所以 getToken 方法也定义好了, 相当于完成了一些初始化工作

接着我们只需要定义我们想要执行的 JS 代码。 我们定义了 js 变量,其实就是模拟调用了 getToken 方法并传入了球员信息。 并打印出了 球员信息

接着,调用 ctx 对象的 eval 方法并传入了 js 变量, 其实就是模拟执行这句代码, 照理说最终返回的就是加密字符串了,但是却报错了

这里说 CryptoJs is not defined

问题其实出现在 crypto-js.min.js ,可以看其中声明了一个 JS 的自执行方法

!function(t, e) {
    "object" == typeof exports ? module.exports = exports = e() : "function" == typeof define && define.amd ? define([], e) : t.CryptoJS = e()
}(this, function() 

自执行方法: 就是声明了一个方法,然后接着调用执行。 格式:

!(function(a,b){ console.log('result', a, b)})(1, 2)

这里我们先声明了一个 function , 它接收 a 和 b 两个参数,然后把内容输出出来,接着我们把这个 function 用小括号括起来。 这其实就是一个方法, 可以被直接调用,怎么调用呢? 后面在跟上对应的参数就好了, 比如这里传入 1, 2 执行结果就是

result 1 2

同理,crypto-js.min.js  也符合这个格式,它接收 t, e 两个参数, t 就是 this , 其实就是浏览器中的 widow 对象, e 就是一个 function (用于定义 CryptoJS 和核心内容)

我们再来看下 crypto-js.min.js 开头的定义

"object" == typeof exports

? module.exports = exports = e()

: "function" == typeof define && define.amd

? define([], e)

: t.CryptoJS = e() }(this, function()

在 Node.js 中, 其实 exports 用来就一些对象的定义导出, 这里 " object " == typeof exports 的结果其实就是 true , 所以执行了 module.exports = exports = e() 这段代码, 这相当于把 e() 作为整体导出, 而这个 e()其实就是对应后面整个 function 里面定义了加密相关的各个实现,其实就是代指整个加密算法库

但是在在浏览器中,其结果就不一样了, 浏览器环境中并没有 exorts 和 define 这两个对象,所以,上述代码在浏览器中最后执行的就是 t.CryptoJS = e() 这段代码, 其实这里就是把 CryptoJS 对象挂在到了 this 上面, 而 this 就是浏览器中的全局 window 对选哪个, 后面就可以直接用了。如果我们把这段代码放在浏览器中,没有任何问题

然而,使用的 PyExecJS 是依赖于一个 Node.js 执行环境的, 所以上述代码其实执行的是 module.exports = exports = e() , 这里面饼没有声明 CryptoJS 对象,也没有把 CryptoJS 挂在到全局对象里面, 所以就报错了

我们在这里只需要声明一个 CryptoJS 变量, 然后手动声明一下它的初始化就好了

!function(t, e) {
    CryptoJS = e();
    "object" == typeof exports ? module.exports = exports = e() : "function" == typeof define && define.amd ? define([], e) : t.CryptoJS = e()
}(this, function()

我们就加了  CryptoJS = e();  然后重新运行

DG1uMMq1M7OeHhds71HlSMHOoI2tFpWCB4ApP00cVFqptmlFKjFu9RluHo2w3mUw

得到了加密 字符串

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1995394.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据库范式及其示例,看完这一篇足够

1. 什么是数据库规范化? 1.1 规范化概念 规范化是一种数据库设计技术,可减少数据冗余并消除插入、更新和删除异常等不良特征。规范化规则将较大的表划分为较小的表并使用关系链接它们。SQL 中的规范化的目的是消除冗余(重复)数据…

Java面试题:Spring循环引用(循环依赖)

Spring中的循环引用 在创建A时需要B,创建B时需要A 三级缓存解决循环依赖问题 在Spring中定义了一个类 DefaultSingletonBeanRegistry 中定义了三个map singletonObjects 一级缓存 单例池,存放完整初始化的bean对象 earlySingletonObjects 二级缓存 缓存早期的bean对象…

【JavaEE初阶】CAS(比较和交换)

目录 🌲 什么是 CAS 🌳 CAS的应用 🚩 实现原子类 🚩 实现自旋锁 🎄 CAS 的 ABA 问题 🚩 什么是 ABA 问题 🚩 ABA 问题引来的 BUG 🚩 解决方案 🍀CAS相关面试题 …

自动化测试客户端程序 时,选择使用什么自动化测试工具?

自动化测试客户端程序时,可以选择多种自动化测试工具,这些工具根据测试的具体需求、目标平台以及开发语言等因素有所不同。以下是一些常用的自动化测试工具,它们分别适用于不同的测试场景: 1. Appium 简介:Appium是一…

你要动态建表,还要动态导入Excel?

背景 ⭐⭐⭐⭐⭐转载请注明出处:https://juejin.cn/post/7400945359192866828 前几天和公司的小伙伴聊天的时候,得知他们的项目里正要做一个功能。大概就是每家公司都会建一张表,这张表会有什么字段不确定,可能有的表10个字段,有的8个字段。然后会有导入的功能,就是给这张…

java实现解析pdf格式发票

为了减少用户工作量及误操作的可能性&#xff0c;需要实现用户上传PDF格式的发票&#xff0c;系统通过解析PDF文件获取发票内容&#xff0c;并直接将其写入表单。以下文章记录了功能实现的代码。 发票样式 发票内容解析 引用Maven 使用pdfbox <dependency><groupI…

API可观察性对于现代应用程序的最大好处

API可观察性是提升性能、加速问题诊断和增强安全的关键。它在理解和管理错综复杂的API交互方面发挥着至关重要的作用。利用API可观察性&#xff0c;您可以深入洞察API的工作状态&#xff0c;保障服务的可靠性&#xff0c;并优化用户体验。 在当今的数字环境中&#xff0c;API …

kubernetes集群部署sql server数据库服务

背景&#xff1a; 因业务上线需要&#xff0c;研发中心要求在kubernetes测试集群部署一个sql server 2017的数据库&#xff0c;用于业务功能调试。 一、实施部署sql server数据库&#xff1a; 1、拉取sql server 2017的镜像&#xff1a; [rootharbor-02 ~]# docker pull mcr…

POI导出复杂Excel表格

记录在遇到复杂统计报表业务时&#xff0c;无法使用Excel模板生成对应报表&#xff0c;则采用最原始poi方式进行创建生成 业务所需统计报表如下图 麻烦所在各类型订单下方餐别为动态数据&#xff0c;废话不多说直接上代码 new CellRangeAddress(起始行号, 终止行号, 起始列号,…

Android Studio 设置打开layout.xml文件的默认视图split

Android Studio 设置打开layout.xml文件的默认视图 Android Studio 设置打开layout.xml文件的默认视图 androd studio 在使用的时候打开我们自己的布局文件默认展示的视图为Design,我们想要编辑的时候还有手动切换成splite 视图或者Code视图&#xff0c;不上很方便&#xff0c…

CA证书和openssl介绍

文章目录 一、加密和算法常见的安全攻击加密算法和协议对称加密非对称加密算法 二、CA和证书中间人攻击CA和证书安全协议SSL/TLS协议介绍HTTPS 三、opensslopenssl介绍使用openssl实现对称加密使用openssl命令生成加密密码生成随机密码建立私有CA证书申请颁发建立私有CA实际例子…

Java-数据库基本概念

数据库DataBase 定义: 保存一组数据的仓库就是数据库 例 BirdBoot项目中&#xff0c;我们为了保存一组用户信息&#xff0c;创建了一个目录users。里面用若干个文件保存每一个用户信息 此时users目录就可以称为是一个数据库 只不过对于这些数据的维护操作&#xff0c;要么…

【最多可以参加的会议数目】python刷题记录

R4-贪心篇 结束时间升序排列优先队列 class Solution:def maxEvents(self, events: List[List[int]]) -> int:dictdefaultdict(list)for i,val in enumerate(events):dict[val[0]].append(val[1])#优先队列&#xff08;小根堆&#xff09;h[]ret0for i in range(1,100001)…

C语言求平方和倒数

文章目录 1. 代码实现float类型数据double类型数据使用 double 类型的调整 2. 魔数与位级别操作浮点数表示位级别魔数操作 3. 牛顿迭代4. 复杂代码具体解释具体解释&#xff1a;目的&#xff1a;举例&#xff1a; 5.感谢 平方和倒数 广泛用于计算机图形学中&#xff0c;尤其是在…

Qt实现类似淘宝商品展示看板功能简版

前一篇文章的简化版本只有浏览功能&#xff0c;前一篇文章链接如下&#xff1a; Qt实现类似淘宝商品看板的界面&#xff0c;带有循环翻页以及点击某页跳转的功能 效果如下&#xff1a; 代码留给有需要的人。 #ifndef ModelDashboardGroup_h__ #define ModelDashboardGroup_…

DC-DC PCB 布线参考

在DC-DC芯片的应用设计中&#xff0c;PCB布板是否合理对于芯片能否表现出其最优性能有着至关重要的影响。不合理的PCB布板会造成芯片性能变差如线性度下降&#xff08;包括输入线性度以及输出线性度&#xff09;、带载能力下降、工作不稳定、EMI辐射增加、输出噪声增加等&#…

容量 动效 仪表盘 Canvas 2D API

容量动效 <!DOCTYPE html> <html lang"zh"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Canvas 内部圆形波浪</title><…

【区块链+乡村振兴】基于区块链的农权抵押贷款平台 | FISCO BCOS应用案例

当前两权抵押贷款业务逐渐活跃&#xff0c;但因参与两权抵押的相关方独立运营各自的管理系统&#xff0c;办理农权抵押贷款业务时&#xff0c; 存在多方信息不对称、业务办理过程繁琐、低效等问题&#xff0c;且不利于相关部门对农权抵押情况进行监督管理。具体表现在&#xff…

《数据资产管理核心技术与应用》相关分享章节

【图书推荐】《数据资产管理核心技术与应用》-CSDN博客 图书《数据资产管理核心技术与应用》介绍-CSDN博客 本文用于快速了解数据资产管理的概念及其技术范围。 数据资产通常是指那些可以通过分析来揭示价值、支持企业决策制定、优化企业流程、预测行业的未来趋势或产生更大…

dhcp+checkkickstar的实验理解

文章目录 实验介绍使用的服务介绍PXE服务dhcp服务Kickstart 服务tftp服务 第一部分&#xff08;基础部分&#xff09;代码展示注意点第一点![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/13c0f4aabb664655a4dd285dd8e5527a.png)第二点 结果展示 第二部分&#xff08…