server端处理WebAPI请求的使用安全问题:
请求重放 (eg. 月饼抢购场景中,程序员通过脚本直接访问接口) 参数篡改 (eg. 会话劫持场景中,前端I请求进将应该抢购到的行签月饼归属人改为自己) 脚本攻击 (eg. 综合前两种场景,使用技术手段构建的使用请求进行攻击,如信息窃取,前端I请求进漏洞攻击) 可信客户端请求 (eg. 以上所有场景根因均为访问客户端不可信并不可证伪)总体流程如下图所示:
前端使用示例(TypeScript Vue3 版本):
<script setup> import { onMounted } from "vue"; import initWasm,前端I请求进 { sign} from "./pkg/sign.js"; // 通过wasm-pack打包生成的二进制包的入口文件 import { v4 as uuidv4 } from uuid; // 此示例以生成的UUID作为cnonce随机字符串 onMounted(async () => { await initWasm() }) const sendRequest = () => { const cnonce = uuidv4() const params: EncryptedParams = { name: John, age: 23, breed: dog, ts: Date.now() } const wasmSignature = sign(JSON.stringify(params), cnonce); ... axios.post(something); } </script>签名机制示例,server端接受到请求时,行签应该同时获得签名值以及cnonce一次性字符串,使用按照下面同样的前端I请求进签名顺序进行签名,高防服务器比对前端传入的行签签名以及server端生成的签名进行校验:
const encryptedSign = (message: string, cnonce: string): string => { const secret = XXXXXXX // 该签名盐值可以自行生成,生成之后需要重新编译rust应用,使用生成新的前端I请求进wasm包 const hashDigest = sha256(`${ cnonce}|${ message}`) const hmacDigest = Base64.stringify(hmacSHA512(hashDigest.toString().toUpperCase(), secret)) return hmacDigest.toString().toUpperCase() }签名机制示例 (rust 版本):
extern crate wasm_bindgen; use ring::hmac; use ring::digest::{ Context, SHA256}; use data_encoding::BASE64; use data_encoding::HEXUPPER; use wasm_bindgen::prelude::*; #[wasm_bindgen] pub fn ron_weasley_sign (message: &str, cnonce: &str) -> String { const SECRET: &str = std::env!("SECRET"); let mut context = Context::new(&SHA256); context.update(format!("{ }|{ }", cnonce, message).as_bytes()); let sha256_result = context.finish(); let sha256_result_str = format!("{ }", HEXUPPER.encode(sha256_result.as_ref())); let key = hmac::Key::new(hmac::HMAC_SHA512, SECRET.as_bytes()); let mac = hmac::sign(&key, sha256_result_str.as_bytes()); let b64_encoded_sig = BASE64.encode(mac.as_ref()); return b64_encoded_sig.to_uppercase(); }首先在项目的github地址
https://github.com/swearer23/ron-weasley 下载源代码
之后按照README文件的步骤安装编译环境(以*nix环境为例)
由于我们使用cargo作为rust环境的管理器,所以第一步安装cargo
安装完成后在命令行输入cargo -v 查看是否安装成功
cargo -v # 可能需要重新启动终端 Rusts package manager USAGE: cargo [+toolchain] [OPTIONS] [SUBCOMMAND] OPTIONS: -V, --version Print version info and exit --list List installed commands --explain <CODE> Run `rustc --explain CODE` -v, --verbose Use verbose output (-vv very verbose/build.rs output) -q, --quiet No output printed to stdout --color <WHEN> Coloring: auto, always, never --frozen Require Cargo.lock and cache are up to date --locked Require Cargo.lock is up to date --offline Run without accessing the network --config <KEY=VALUE>... Override a configuration value (unstable) -Z <FLAG>... Unstable (nightly-only) flags to Cargo, see cargo -Z help for details -h, --help Prints help information Some common cargo commands are (see all commands with --list): build, b Compile the current package check, c Analyze the current package and report errors, but dont build object files clean Remove the target directory doc, d Build this packages and its dependencies documentation new Create a new cargo package init Create a new cargo package in an existing directory run, r Run a binary or example of the local package test, t Run the tests bench Run the benchmarks update Update dependencies listed in Cargo.lock search Search registry for crates publish Package and upload this package to the registry install Install a Rust binary. Default location is $HOME/.cargo/bin uninstall Uninstall a Rust binary See cargo help <command> for more information on a specific command.要构建二进制包,需要一个额外工具 wasm-pack。它会帮助我们把代码编译成 WebAssembly 并构建出适用于web环境的wasm包。使用下面的命令可以下载并安装:
cargo install wasm-packwasm-pack安装成功后,执行下面的云服务器命令以编译wasm包
SECRET= wasm-pack build --target=web --release<your-secret>替换为你的签名盐值
第一次构建和编译时间会比较长,需要下载依赖的rust库并编译,请耐心等待
如果速度仍然很慢,建议更换cargo国内源
在你的cargo文件夹下新建 config 文件
macos中,文件夹地址在 ~/.cargo
cd ~/.cargo touch config然后编辑config文件,添加如下内容:
[source.crates-io] registry = "https://github.com/rust-lang/crates.io-index" replace-with = ustc [source.ustc] registry = "git://mirrors.ustc.edu.cn/crates.io-index"即可更换为ustc的源
执行wasm-pack命令打包会得到一个名为pkg的文件夹,位于项目的根目录下
将其放入要使用的前端项目中,即可以像上面代码示例章节所描述的方式进行集成和调用