网络异常,图片无法展示
|
前言
我们公司鉴权走的是JWT,
但是有些数据走Cookie更方便通讯,
纵观今天,网上一大把说Cookie不好的文章.
但是我们还是要用,那怎么安全一丢丢呢?
Cookie的痛点
- 不同浏览器支持的数量不等,比较新的主流浏览器还好
- 信息承载量有限,一般不能超过4kb
- 容易遭受CSRF(跨站请求伪造)等攻击
聚焦场景
非敏感信息依赖cookie通讯(需要一定的安全性支持)
解决姿势
CSRF及XSS
常规姿势有这么写(请求头):
- Content Security Policy
- Referer: 判断来源ip或者url
- Token: 自定义请求头对比也是可行的
- HttpOnly: 客户端只读状态
- SameSite: Strict会完全阻止第三方cookie,lax会宽松些
加密Cookie信息
若是觉得服务端的一些限制条件还不够,
我们可以适当采取一些手段来加密我们的Cookie!
哪怕暴露了Cookie也不会直接把数据暴露!!
比如,我经手过的落地姿势有: Base64+AES+UUID!
这个方案是很直白,支持度也很好(前后端).
具体加密原理可以自行引擎了解!
我们在这里讨论姿势,前端的支持如下!
- Base64: IE10+起步就原生支持(
window.atob
,window.btoa
)
- Can I Use: Base64 Encoding and Decoding
- AES: 非常流行的块加密姿势, 密文块匹配正确才能解码,破解还是相当难的,一般人玩不来!
- UUID: 简称通用唯一识别码,其实你搞个随机数或者其他都行.这里用来混淆!
- github.com/ai/nanoid : nanoid也能生成随机字符(贼快)
我们在AES的前后拼接特殊字符串或者nanoid是为了增大破解难度,
不至于Base64解码后就是Raw AES Text!!!
演示代码
此处用了Vue Cli初始化了一个项目来演示,
部分边缘情况判断就没有考虑很全了,
然而我们实际项目中,
更倾向于把这部分逻辑抽成utils或者hooks!
里面会考虑的边缘情况比较全面!
<script> import {nanoid} from 'nanoid' import AES from "crypto-js/aes"; import EncUTF8 from "crypto-js/enc-utf8"; export default { name: "App", data() { return { info: Object.freeze({ version: "v1.0.0", EngineCode: "312312fasdfasrewrwe", }), // 需要加密的文本 tempInfo: {}, // 中间变量,缓存转换的 }; }, methods: { isJSON(str) { if (!str) return false; if (typeof str === "string") { try { let obj = JSON.parse(str); if (typeof obj === "object" && obj) { return true; } else { return false; } } catch (e) { console.log("error:" + str + "!!!" + e); return false; } } }, }, created() { console.time('nanoid 8位数生成时间') console.log(nanoid(8)); console.timeEnd('nanoid 8位数生成时间') console.time('加密时间') console.log('%c 🍩 加密前信息: ', 'font-size:20px;background-color: #33A5FF;color:#fff;', this.info); // aes加密后的纯文本 let encryptText = AES.encrypt(JSON.stringify(this.info), "cqmyg").toString(); console.log('%c 🍩 encryptText: ', 'font-size:20px;background-color: #33A5FF;color:#fff;', encryptText); // 拼接八位数的随机字符作为前缀(用来混淆) let UUIDText = `${nanoid(8)}${encryptText}` console.log('%c 🥡 UUIDText: ', 'font-size:20px;background-color: #42b983;color:#fff;', UUIDText); // base64 this.tempInfo = window.btoa(UUIDText); console.log( "%c 🌰 AES+NanoID+Base64加密后的文本: ", "font-size:20px;background-color: #EA7E5C;color:#fff;", this.tempInfo ); console.timeEnd('加密时间') }, mounted() { console.time("解密时间"); if(this.tempInfo && typeof this.tempInfo === 'string'){ let aesText = window.atob(this.tempInfo).slice(8); console.log('%c 🥫 aesText: ', 'font-size:20px;background-color: #ED9EC7;color:#fff;', aesText); let infoText = AES.decrypt(aesText, "cqmyg").toString(EncUTF8); console.log('%c 🍨 infoText: ', 'font-size:20px;background-color: #E41A6A;color:#fff;', infoText); let rawInfo = this.isJSON(infoText) ? JSON.parse(infoText): infoText; console.log('%c 🍐 解密得出的信息: ', 'font-size:20px;background-color: #EA7E5C;color:#fff;', rawInfo); } console.timeEnd("解密时间"); }, render(){ return <div class="app"> 我是app </div> } }; </script>
测试结果
网络异常,图片无法展示
|
多次测试下,浏览器端平均时长均在5ms以下,
但是我觉得主流浏览器波动都不会相差太大,
顶多20ms内,这个时间是可以接受的~
若是你还是觉得有点长,
可以去掉base64和nanoid,
只保留AES加解密!!