当前位置: 首页 > news >正文

spiderdemo第22题与webassembly的跨域

目录

前言

正文

前置分析

继续分析

建立wasm项目

前置准备

编写爬虫

加密参数

请求头

发送请求的函数

跨域

反向代理

试试登录与退出

登录

退出

全部代码如下

Cargo.toml

lib.rs

index.html

cors.py

总结


前言

直言的说,这道题很简单,但笔者有其他好玩的想法

笔者决定使用rust来写爬虫,而且笔者想使用wasm,在wasm里面发送请求。

(0.0)(0.0)(0.0)(0.0)(0.0)(0.0)

正文

页面如下

T22-对称加密https://www.spiderdemo.cn/authentication/symmetry_challenge/?challenge_type=symmetry_challenge

前置分析

多次点击下一页,观察参数和请求头,可以发现有四个参数需要加密,如下

直接搜关键字,比如X-Aes-Token,就可以发现关键信息

可以发现是在symmetry_challenge.js文件中,下载下来,继续分析看看

继续分析

给出关键代码

 var n, t, r, o = e.url.match(/\/page\/(\d+)\//);if (o) {var a = parseInt(o[1]), c = new URLSearchParams(e.url.split("?")[1] || "").get("challenge_type") || "symmetry_challenge", s = Date.now(), i = "".concat(a, "_").concat(c, "_").concat(s);e.headers["X-Aes-Token"] = (n = i,t = CryptoJS.enc.Utf8.parse("1234567890123456"),r = CryptoJS.enc.Utf8.parse(u),CryptoJS.AES.encrypt(n, t, {iv: r,mode: CryptoJS.mode.CTR,padding: CryptoJS.pad.NoPadding}).toString()),e.headers["X-Des-Token"] = l(i);var p = function(e) {var n = CryptoJS.enc.Utf8.parse("12345678901234567890123456789012"), t = CryptoJS.enc.Utf8.parse(u);return CryptoJS.AES.encrypt(e, n, {iv: t,mode: CryptoJS.mode.OFB,padding: CryptoJS.pad.NoPadding}).toString()}(i), f = l(i + "_param"), d = e.url.includes("?") ? "&" : "?";e.url += "".concat(d, "aes_sign=").concat(encodeURIComponent(p), "&des_sign=").concat(encodeURIComponent(f), "&t=").concat(s)}

加密的方法是很显然的,分别是AES加密和DES加密,相关参考如下

【密码学】DES算法和AES算法(Rijndael算法)数学原理及实现 - stackupdown - 博客园https://www.cnblogs.com/wangzming/p/7991322.htmlJS实现AES和DES_des js-CSDN博客https://blog.csdn.net/qq_39706570/article/details/147025994#:~:text=%E4%BA%86%E8%A7%A3%20AES%20%E5%92%8CDES%E7%9A%84%E7%89%B9%E7%82%B9%E5%B9%B6%E7%94%A8JS%E5%AE%9E%E7%8E%B0%E3%80%82%20%E7%BF%BB%E8%AF%91%20%E8%BF%87%E6%9D%A5%E5%8F%AB%20%E6%95%B0%E6%8D%AE%E5%8A%A0%E5%AF%86%E6%A0%87%E5%87%86%E3%80%82,%E5%AE%83%E6%9C%895%E7%A7%8D%E5%8A%A0%E5%AF%86%E6%A8%A1%E5%BC%8F%EF%BC%88CTR%E3%80%81OFB%E3%80%81CFB%E3%80%81CBC%E3%80%81ECB%EF%BC%89%EF%BC%8C%E5%9C%A8JS%E4%B8%AD%EF%BC%8C%E4%B8%8D%E5%90%8C%E5%8A%A0%E5%AF%86%E6%A8%A1%E5%BC%8F%E8%AF%AD%E6%B3%95%E7%BB%93%E6%9E%84%E5%87%A0%E4%B9%8E%E4%B8%80%E8%87%B4%EF%BC%8C%E4%B8%BB%E8%A6%81%E5%8C%BA%E5%88%AB%E5%B0%B1%E6%98%AFmode%E8%AE%BE%E7%BD%AE%E5%92%8C%E6%98%AF%E5%90%A6%E9%9C%80%E8%A6%81iv%EF%BC%88%E5%88%9D%E5%A7%8B%E5%8C%96%20%E5%90%91%E9%87%8F%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%90%86%E8%A7%A3%E4%B8%BA%E7%AC%AC%E4%BA%8C%E4%B8%AA%E5%AF%86%E9%92%A5%EF%BC%89%EF%BC%8C%E5%85%B6%E4%B8%AD%20ECB%E4%B8%8D%E9%9C%80%E8%A6%81iv%EF%BC%8C%E5%85%B6%E4%BB%96%E6%A8%A1%E5%BC%8F%E9%83%BD%E9%9C%80%E8%A6%81%E3%80%82%20%E5%AE%83%E5%85%B7%E6%9C%89%E4%BB%A5%E4%B8%8B%E7%89%B9%E7%82%B9%EF%BC%9A%20%E5%AF%86%E9%92%A5%E9%95%BF%E5%BA%A6%EF%BC%9A56%E4%BD%8D%EF%BC%88%E5%AE%9E%E9%99%85%E4%B8%8A%E6%98%AF64%E4%BD%8D%EF%BC%8C%E4%BD%86%E6%AF%8F8%E4%BD%8D%E4%B8%AD%E6%9C%891%E4%BD%8D%E7%94%A8%E4%BA%8E%E5%A5%87%E5%81%B6%E6%A0%A1%E9%AA%8C%EF%BC%89%E3%80%82%20%E5%88%86%E7%BB%84%E5%8A%A0%E5%AF%86%EF%BC%9A64%E4%BD%8D%E5%88%86%E7%BB%84%E3%80%82二者都是对称加密。

看代码

首先,先对url里面进行了正则匹配,获取了n,t,r,o

然后,if判断o是否为true,如果存在,把o解析成int,

说白了a就是page,是一个int类型的


c——是一个定值symmetry_challenge

s是13为时间戳

i是a,c,s通过下划线拼接二次的,


X-Aes-Token使用的是Aes加密,密钥key是1234567890123456,被解析成CryptoJS里面的类型是WordArray

偏移量iv是通过u解析来的,而u是一个定值,如下

使用的模式是CTR,填充方式是NoPadding——不进行任何填充。


X-Des-Token调用l函数

如下

    function l(e) {var n = CryptoJS.enc.Utf8.parse("6f726c64"), t = CryptoJS.enc.Utf8.parse("01234567");return CryptoJS.DES.encrypt(e, n, {iv: t, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7}).toString()}

类似的。


aes_sign和des_sign也是类似都,调用对应的加密方法,各自的密钥。


总之,没有js混淆那些,加密是很显然的。

建立wasm项目

笔者使用rust,需要安装一个工具

cargo install wasm-pack

安装完成后,初始化一个wasm项目

 wasm-pack new wasm-app

删除一下没有用的东西,添加爬虫需要的依赖,关键的Cargo.toml文件如下

[package]
name = "wasm-app"
version = "0.1.0"
edition = "2024"[lib]
crate-type = ["cdylib"][dependencies]
wasm-bindgen = "0.2.105"

前置准备

新建一个index.html

文件目录如下

其中index.html,暂时的内容如下

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script><script>console.log(Crypto)</script>
</head>
<body></body>
</html>

导入了加密库,顺便打印一下

没有报错,没问题


====明天再说=======


题外话,笔者先安装一个工具

cargo install cargo-make

cargo-make rust 任务执行以及构建工具 - 荣锋亮 - 博客园https://www.cnblogs.com/rongfengliang/p/17910340.html为了后面构建。


继续,在wasm-z目录下新建一个main.js文件,结合前面的分析,main.js文件的内容如下

function l(e) {var n = CryptoJS.enc.Utf8.parse("6f726c64"), t = CryptoJS.enc.Utf8.parse("01234567");return CryptoJS.DES.encrypt(e, n, {iv: t, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7}).toString()
}
export function get_params(page) {let n, t, r;let c = "symmetry_challenge"let s = Date.now()let i = "".concat(page, "_").concat(c, "_").concat(s)let u = "abcdefghijklmnop"let aes_token = (n = i,t = CryptoJS.enc.Utf8.parse("1234567890123456"),r = CryptoJS.enc.Utf8.parse(u),CryptoJS.AES.encrypt(n, t, {iv: r,mode: CryptoJS.mode.CTR,padding: CryptoJS.pad.NoPadding}).toString())let des_token = l(i)let aes_sign = function (e) {n = CryptoJS.enc.Utf8.parse("12345678901234567890123456789012")t = CryptoJS.enc.Utf8.parse(u);return CryptoJS.AES.encrypt(e, n, {iv: t,mode: CryptoJS.mode.OFB,padding: CryptoJS.pad.NoPadding}).toString()}(i)let des_sign = l(i + "_param")return {aes_token: aes_token,des_token: des_token,aes_sign: aes_sign,des_sign: des_sign,timestamp: s.toString(),}
}

不需要那个symmetry_challenge.js文件了

这个main.js文件就是用来加密的,可以在wasm项目中导入

在wasm-app/src/lib.rs文件的内容如下

use wasm_bindgen::prelude::*;
use reqwest::Client;
use web_sys::console::log_1;#[wasm_bindgen(module="/main.js")]
extern "C" {#[wasm_bindgen(js_name = get_params)]fn get_params_js(page: u32) -> JsValue;
}#[wasm_bindgen]
pub fn get_request(page:u32)->u32{let a=get_params_js(1);// 打印看看log_1(&a.into());1
}

暂时打包

如果使用cargo make

则Makefile.toml文件的内容如下

[tasks.build-wasm]
command = "wasm-pack"
args = ["build", "--target", "web", "--out-dir", "../t22/pkg", "--no-pack"]

或者

直接打包

wasm-pack build

笔者打包后,目录如下

在index.html中引入js文件

    <script type="module">import init,{get_request} from "./pkg/wasm_app.js";init().then(() => {let a=get_request(1);console.log(a)});</script>

运行index.html

输出如下

可以看到生成了参数,好

编写爬虫

慢慢来,首先,写请求头

加密参数

前面通过js文件获取加密后的数据,这个数据的类型是JsValue,需要将其变成Rust的类型——结构体。还与wasm有关,因此,需要新的crate

serde = {version = "1", features = ["derive"]}
serde-wasm-bindgen = {version = "0.6"}

考虑参数,aes、des分别两个,还有一个时间戳

因此,结构体定义如下

#[derive(Debug, Deserialize)]
struct Params {aes_token: String,des_token: String,aes_sign: String,des_sign: String,timestamp: String,
}

把JsValue变成Params,需要使用serde-wasm-bindgen

use serde_wasm_bindgen::from_value;
let params = from_value::<Params>(a).unwrap();

当然,如果要打印params到控制台上,可以变成字符串,即

log_1(&JsValue::from_str(&format!("{:?}", params)));

结果如下

也可以为Params实现From这个trait。代码如下

impl From<JsValue> for Params {fn from(v: JsValue) -> Self {from_value(v).unwrap()}}

实现了From,代码如下

let params = Params::from(a);

差不多。

如果反过来,Params变成JsValue,这其实很简单,实现Serialize就可以

代码如下

#[derive(Debug, Deserialize, Serialize)]
struct Params {aes_token: String,des_token: String,aes_sign: String,des_sign: String,timestamp: String,
}
log_1(&to_value(&params).unwrap());

打印结果如下

可以发现前面把params的打印是字符串,而实现Serialize后的打印是JS对象。

还是有点区别的。

请求头

直接给出代码

fn headers(aes_token: String, des_token: String) -> HeaderMap {let mut headers = HeaderMap::new();headers.insert(CONTENT_TYPE, "application/json".parse().unwrap());headers.insert("Cookie",HeaderValue::from_static("xxxxxxx"));headers.insert("X-Aes-Token", HeaderValue::from_str(&aes_token).unwrap());headers.insert("X-Des-Token", HeaderValue::from_str(&des_token).unwrap());headers
}

需要三个参数。

发送请求的函数

直接给出代码

#[derive(Serialize)]
struct Query {challenge_type: String,aes_sign: String,des_sign: String,t: String,
}
async fn get_response(page: u32, params: Params) -> String {let url = format!("https://www.spiderdemo.cn/authentication/api/symmetry_challenge/page/{}/",page);let request = Client::new();let query = Query {challenge_type: "symmetry_challenge".to_string(),aes_sign: params.aes_sign.clone(),des_sign: params.des_sign.clone(),t: params.timestamp.clone(),};let headers = headers(params.aes_token, params.des_token);let res=request.get(url).query(&query).headers(headers).send().await.map_err(|err| log_1(&JsValue::from_str(&err.to_string()))).unwrap().text().await.unwrap();log_1(&JsValue::from_str(&res));res
}

感觉有点重复,算了

最终的调用

#[wasm_bindgen]
pub async fn get_request(page: u32) -> u32 {let a = get_params_js(1);let params = Params::from(a);log_1(&to_value(&params).unwrap());get_response(page, params).await;1
}

调用get_requests

    <script type="module">import init,{get_request} from "./pkg/wasm_app.js";init().then(() => {get_request(1).then((data)=>{console.log(data);});});</script>

然后,结果如下

index.html?_ijt=3nbld9mcoqmquitkecmlltr0al&_ij_reload=RELOAD_ON_SAVE:1  Access to fetch at 'https://www.spiderdemo.cn/authentication/api/symmetry_challenge/page/1/?challenge_type=symmetry_challenge&aes_sign=%2BmSkBuYfTT5lH37rJl9qpeN9ZqcuSC4cEuw7ejPS58tYTQ%3D%3D&des_sign=l39NBujH1q5MFjdmTys13Hmm2c5eDA%2B1KhqP5p9fq2yV8ezI1WAyoK%2FBd2SwRwaX&t=1762438661611' from origin 'http://localhost:64542' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

什么报错——跨域

跨域

笔者搜了搜,看到了wasm-bindgen官网的一个案例

web-sys:使用 fetch - `wasm-bindgen` 指南 - Rust 和 WebAssemblyhttps://wasm.rust-lang.net.cn/docs/wasm-bindgen/examples/fetch.html啊,这,笔者发现前面写的都没有用。呜呜呜呜呜呜。

写了个寂寞

然后,笔者也尝试了,

案例的方式,也不行。。。。。。。。。。。。。。。。。。。。

不是,看来服务器没有Access-Control-Allow-Origin为*

确实,笔者想的太简单了。。。。。

笔者发现这好像是wasm致命的问题。啊啊啊啊啊

Reqwest WASM跨域请求中的凭证传递问题解析 - GitCode博客https://blog.gitcode.com/a210f0fb238c5d9c8e8ebb55e79ec3b6.htmlwebassembly跨域访问_webassembly 跨域加载wasm-CSDN博客https://blog.csdn.net/henreash/article/details/108530401




笔者到处搜索,发现不行,看来只能反向代理,一条路走到黑了

mitmproxy.orghttps://www.mitmproxy.org/(30 封私信 / 86 条消息) 实战|手把手教你如何使用抓包神器MitmProxy - 知乎https://zhuanlan.zhihu.com/p/396398412

直言的说,笔者还从来没有使用过这个东西,正好学习和使用一下


=========算了,明天再来=======


反向代理

笔者看到可以使用python去下载mitmproxy,那为什么不直接用python写爬虫

给自己整笑了,算了。。。。。。。。。。。

首先,思考一下自身

  1. 笔者在wasm里面发送请求
  2. wasm文件在html里面
  3. 笔者使用的是rustrover打开的html

因此,需要知道rustrover里面打开html的端口号,如下

可以看到是63342,这个端口号可能会变,随机应变,无所谓。

  1. 需要拦截options方法,不发送到服务器,也就是不发送到spiderdemo.cn,直接回 204 No Content
  2. 还需要设置响应头,比如Access-Control-Allow-Origin之类的,已经请求头参数
  3. 以及需要cookie,需要凭证

那么,搞事情

在某个python项目中,安装依赖,新建一个cors.py文件

from mitmproxy import httpALLOWED_ORIGIN = "http://localhost:63342"def responseheaders(flow: http.HTTPFlow):flow.response.headers["Access-Control-Allow-Origin"]  = ALLOWED_ORIGINflow.response.headers["Access-Control-Allow-Credentials"] = "true"flow.response.headers["Access-Control-Allow-Headers"] = "X-Aes-Token,X-Des-Token,Content-Type"flow.response.headers["Access-Control-Allow-Methods"] = "GET,POST,OPTIONS"def request(flow: http.HTTPFlow):if flow.request.method == "OPTIONS":flow.response = http.Response.make(204, b"",{"Access-Control-Max-Age": "86400"})

运行

mitmproxy --mode reverse:https://www.spiderdemo.cn@8082 -s cors.py

监听8082端口,为什么是8082,因为笔者8080和8081被占用,可以切换。

把127.0.0.1:8082代理到https://www.spiderdemo.cn

那么,修改url

    let url = format!("http://127.0.0.1:8082/authentication/api/symmetry_challenge/page/{}/",page);

打包,并运行inde.html

但是结果如下

options是过去了,但是没有cookie,笔者明明设置了

但是,请求头里面没有cookie,就没有cookie,不是

为什么?????????????

笔者去学习了一下

cookie带不上?响应头拿不到数据?后端返回了cookie但是前端请求时候灭有自动带上?后端响应头返回了东西,但是前端 - 掘金https://juejin.cn/post/7363115064729059343笔者看了看,笔者明白了

  1. 需要credentials: 'include'
  2. 响应头里面设置cookie
  3. 后设置cookie时候需要需要设置这两个选项sameSite: 'none'; secure: 'false'

在reqwest里面如下设置credentials,根据前面引用的url

Reqwest WASM跨域请求中的凭证传递问题解析 - GitCode博客https://blog.gitcode.com/a210f0fb238c5d9c8e8ebb55e79ec3b6.html可以设置fetch_credentials_include,哦

cookie可以在mitmproxy里面修改

因此,代码如下

在lib.rs文件中

代码如下

async fn get_response(page: u32, params: Params) -> String {let url = format!("http://127.0.0.1:8082/authentication/api/symmetry_challenge/page/{}/",page);let request = Client::builder().build().unwrap();let query = Query {challenge_type: "symmetry_challenge".to_string(),aes_sign: params.aes_sign.clone(),des_sign: params.des_sign.clone(),t: params.timestamp.clone(),};let headers = headers(params.aes_token, params.des_token);let res=request.get(url).query(&query).headers(headers).fetch_credentials_include().send().await.map_err(|err| log_1(&JsValue::from_str(&err.to_string()))).unwrap().text().await.unwrap();log_1(&JsValue::from_str(&res));res
}

设置了fetch_credentials_include

在python的cors.py文件中

from mitmproxy import httpALLOWED_ORIGIN = "http://localhost:63343"def responseheaders(flow: http.HTTPFlow):# 只在反向代理模式下给**响应**加头flow.response.headers["Access-Control-Allow-Origin"]  = ALLOWED_ORIGINflow.response.headers["Access-Control-Allow-Credentials"] = "true"flow.response.headers["Access-Control-Allow-Headers"] = "X-Aes-Token,X-Des-Token,Content-Type"flow.response.headers["Access-Control-Allow-Methods"] = "GET,POST,OPTIONS"flow.response.headers['Set-Cookie']="sessionid=******;SameSite=None;Secure=false;"def request(flow: http.HTTPFlow):if flow.request.method == "OPTIONS":flow.response = http.Response.make(204, b"",{"Access-Control-Max-Age": "86400"})

再次打包,虽然说会报错

但是build没有问题

运行html

终于成功了,笔者搞了寂寞。等同于自己部署了项目。

既然mitmproxy可以代理,那应该也可以拦截,那么直接把这个get请求给拦截了,添加cookie不就可以了,搞了个寂寞,因此,修改一下python代码

def request(flow: http.HTTPFlow):if flow.request.method == "OPTIONS":flow.response = http.Response.make(204, b"",{"Access-Control-Max-Age": "86400"})if flow.request.method=="GET":flow.request.headers["Cookie"]="sessionid=xxxxx"

再次运行,如下

没有cookie,但是成功了

全部问题解决。

试试登录与退出

但是笔者想看一看登录,如下

看看响应标头里面有没有Set-Cookies

还真有,笔者发现这个cookie是会刷新的,因此,直接给出来

这就有点意思了,笔者发现还有退出

既然如下,用wasm写一个登录,mitmproxy拦截,cookie存储到mitmproxy里面,

退出的时候,cookie清除,没问题。

登录

登录成功返回的结果如下

会返回success。代码如下

#[derive(Serialize)]
struct Login {username: String,password: String,
}
#[derive(Deserialize)]
struct LoginResponse {success: bool,
}
#[wasm_bindgen]
pub async fn login(username: String, password: String) -> bool {let mut h = HeaderMap::new();h.insert("Content-Type", "application/json".parse().unwrap());let response = Client::new().post("http://127.0.0.1:8082/admin_I/api/auth/login").headers(h).json(&Login {username,password,}).send().await.unwrap().json::<LoginResponse>();response.await.unwrap().success
}

退出

#[wasm_bindgen]
pub async fn logout()->bool {let mut h = HeaderMap::new();h.insert("Content-Type", "application/json".parse().unwrap());let response = Client::new().post("http://127.0.0.1:8082/admin_I/api/auth/logout").headers(h).send().await.unwrap().json::<LoginResponse>();response.await.unwrap().success
}

很简单,不必多言。

全部代码如下

走到这里,直接给出代码

Cargo.toml

[package]
name = "wasm-app"
version = "0.1.0"
edition = "2024"[lib]
crate-type = ["cdylib"][dependencies]
wasm-bindgen = "0.2.105"
serde = {version = "1", features = ["derive"]}
serde-wasm-bindgen = {version = "0.6"}
wasm-bindgen-futures = {version = "0.4"}
reqwest = {version = "0.12.24",features = ["json"]}
web-sys = { version = "0.3", features = ['console'] }

lib.rs

use reqwest::header::{HeaderMap, HeaderValue, CONTENT_TYPE};
use reqwest::Client;
use serde::{Deserialize, Serialize};
use serde_wasm_bindgen::from_value;
use wasm_bindgen::prelude::*;
use web_sys::console::log_1;#[wasm_bindgen(module = "/main.js")]
extern "C" {#[wasm_bindgen(js_name = get_params)]fn get_params_js(page: u32) -> JsValue;
}#[derive(Debug, Deserialize, Serialize)]
struct Params {aes_token: String,des_token: String,aes_sign: String,des_sign: String,timestamp: String,
}
impl From<JsValue> for Params {fn from(v: JsValue) -> Self {from_value(v).unwrap()}
}
fn headers(aes_token: String, des_token: String) -> HeaderMap {let mut headers = HeaderMap::new();headers.insert(CONTENT_TYPE, "application/json".parse().unwrap());headers.insert("X-Aes-Token", HeaderValue::from_str(&aes_token).unwrap());headers.insert("X-Des-Token", HeaderValue::from_str(&des_token).unwrap());headers
}
#[derive(Serialize)]
struct Query {challenge_type: String,aes_sign: String,des_sign: String,t: String,
}
#[derive(Deserialize)]
struct Response {page_data: Vec<u32>,
}
#[derive(Serialize)]
struct Login {username: String,password: String,
}
#[derive(Deserialize)]
struct LoginResponse {success: bool,
}
async fn get_response(page: u32, params: Params) -> u32 {let url = format!("http://127.0.0.1:8082/authentication/api/symmetry_challenge/page/{}/",page);let request = Client::builder().build().unwrap();let query = Query {challenge_type: "symmetry_challenge".to_string(),aes_sign: params.aes_sign.clone(),des_sign: params.des_sign.clone(),t: params.timestamp.clone(),};let headers = headers(params.aes_token, params.des_token);let res = request.get(url).query(&query).headers(headers).send().await.map_err(|err| log_1(&JsValue::from_str(&err.to_string()))).unwrap().json::<Response>().await.unwrap();res.page_data.into_iter().sum()
}
#[wasm_bindgen]
pub async fn get_data(page: u32) -> u32 {let a = get_params_js(page);let params = Params::from(a);get_response(page, params).await
}
#[wasm_bindgen]
pub async fn login(username: String, password: String) -> bool {let mut h = HeaderMap::new();h.insert("Content-Type", "application/json".parse().unwrap());let response = Client::new().post("http://127.0.0.1:8082/admin_I/api/auth/login").headers(h).json(&Login {username,password,}).send().await.unwrap().json::<LoginResponse>();response.await.unwrap().success
}
#[wasm_bindgen]
pub async fn logout()->bool {let mut h = HeaderMap::new();h.insert("Content-Type", "application/json".parse().unwrap());let response = Client::new().post("http://127.0.0.1:8082/admin_I/api/auth/logout").headers(h).send().await.unwrap().json::<LoginResponse>();response.await.unwrap().success
}

index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script><script type="module">import init, {get_data, login,logout} from "./pkg/wasm_app.js";init()window.getOne = async function () {try {const data = await get_data(1);console.log("第一页数据:", data);} catch (e) {alert("获取数据失败:" + e);}};window.doLogin = async function () {const username = document.getElementById("username").value.trim();const password = document.getElementById("password").value.trim();if (!username || !password) {alert("请输入用户名和密码");return;}try {const msg = await login(username, password);console.log("登录成功:", msg);} catch (e) {console.error("登录失败:", e);}};window.logoutPage=async ()=>{let res=await logout()console.log("退出成功:", res);};</script>
</head><body>
<input id="username" type="text" placeholder="用户名">
<input id="password" type="password" placeholder="密码">
<button onclick="doLogin()">登录</button>
<button onclick="getOne()">获取第一页数据</button>
<button onclick="logoutPage()">登出</button>
</body>
</html>

cors.py

from mitmproxy import httpALLOWED_ORIGIN = "http://localhost:63343"
COOKIE = ""def responseheaders(flow: http.HTTPFlow):# 只在反向代理模式下给**响应**加头global COOKIE# 只拦截登录接口(反向代理后 URL 已经是 spiderdemo 的)if (flow.request.method == "POST"and flow.request.path == "/admin_I/api/auth/login"and flow.response):cookies = flow.response.headers.get_all("Set-Cookie")COOKIE = "; ".join(c.split(";", 1)[0] for c in cookies)flow.response.headers["Access-Control-Allow-Origin"] = ALLOWED_ORIGINflow.response.headers["Access-Control-Allow-Credentials"] = "true"flow.response.headers["Access-Control-Allow-Headers"] = "X-Aes-Token,X-Des-Token,Content-Type"flow.response.headers["Access-Control-Allow-Methods"] = "GET,POST,OPTIONS"def request(flow: http.HTTPFlow):global COOKIEif flow.request.method == "OPTIONS":flow.response = http.Response.make(204, b"",{"Access-Control-Max-Age": "86400"})if flow.request.method in ("GET", "POST"):flow.request.headers["Cookie"] = COOKIE

登录与退出的结果

运行,爬虫结果如下

没问题。

总结

笔者写了几天,没绷住,就问题本身就是其实很简单,没用wasm也不会遇到跨域问题,

笔者以前还不知道,正好使用一些mitmproxy这个代理,用起来感觉可以,相关参考如下

钩子签名触发时机典型用途能否修改请求/响应?
def request(flow: http.HTTPFlow)客户端→mitmproxy 刚到代理层,还未发往服务器改请求头、改路径、直接返回假响应、丢弃请求✅ 可改 flow.request
def response(flow: http.HTTPFlow)服务器→mitmproxy 刚到代理层,还未发回客户端改响应头、改 body、存 Cookie、打日志✅ 可改 flow.response
def responseheaders(flow: http.HTTPFlow)服务器→mitmproxy 仅响应头已到达,body 还在路上只改头、不改 body,节省内存✅ 可改 flow.response.headers
def http_connect(flow: tcp.HTTPFlow)CONNECT 隧道建立前拦截 HTTPS 隧道✅ 可丢弃
def client_connected(client: tcp.Client)TCP 三次握手完成记录 IP、端口❌ 不能改 HTTP 内容

说起来,想不到还可以这么玩,哈哈哈哈哈

有点意思,以后再来试试

http://www.dtcms.com/a/581065.html

相关文章:

  • 【MySQL | 基础】通用语法及SQL分类
  • 【爬虫】分析天气网后,整理的一点理论上的理解
  • Web安全-文件上传漏洞-黑白名单及其它绕过思路(附思维导图)
  • WPF 高级 UI 定制:深入解析 VisualStateManager 与 Adorner
  • 全景相机市占率“罗生门”:影石的数据迷雾
  • 【2025】16届蓝桥杯 Java 组全题详解(省赛真题 + 思路 + 代码)
  • flas网站开发工具网店美工课程
  • 网站广告连接如何做wordpress.shop
  • Geobuilding模型转换,深圳市科技风贴图建筑物3dtiles倾斜摄影数据
  • CentOS 系统升级 OpenSSH 和 OpenSSL 的完整方案
  • PPIO上线Kimi K2 Thinking,兼容Anthropic协议
  • 本地项目上传至GitHub仓库标准操作手册
  • 如何做发表文章的网站网页设计模板图片家乡
  • 不停服务快速创建一个MySQL从节点加入已经存在的MGR集群中
  • TCP建立连接:三次握手(每次握手发的字段及字段值的解释)
  • 【SpringBoot】34 核心功能 - 指标监控- Spring Boot Actuator 指标监控开启与禁用与 Endpoint 定制
  • 【软考】信息系统项目管理师-资源管理论文范文
  • 标准nodejs项目工程
  • 定制网站开发公司种子网站模板
  • Maven前奏
  • C++面试高级篇——内存管理(一)
  • kanass零基础学习,如何进行工时管理,有效度量项目资源
  • 恋爱ppt模板免费下载网站官方网站建立
  • Spark-3.5.7文档1 - 快速开始
  • Java_Map接口实现类Properties
  • 【底层机制】Android对Linux线程调度的移动设备优化深度解析
  • 2025制品管理工具选型,Jfrog or Hadess一文全面测评
  • 3.2、Python-元组
  • PyTorch之父发离职长文,告别Meta
  • 微信小程序与网站连接厦门 网站优化