我是前端彭于晏,我喂自己袋盐
作为一名前端开发者,了解 Web 安全基础是基本操作。本文精简整理常见网络攻击和应对策略,并分享我如何通过 request 封装、sig 签名、FormData 等技术,打造安全输入体系。
一、常见 Web 安全攻击
1. XSS (Cross-Site Scripting)
漏洞原理: 网站对用户输入缺乏过滤,导致恶意脚本被添加到页面并在其他用户浏览时被执行
| 类型 | 特点 | 危害示例 |
|---|---|---|
| 存储型XSS | 恶意脚本持久存储在服务器上(如评论区、数据库) | 业务逻辑被乱用,失此Cookie |
| 反射型XSS | 恶意脚本通过URL传递,服务器直接返回到页面 | 骗取用户点击与上传数据 |
| DOM型XSS | 前端JS本地修改DOM,未根据规范处理用户输入 | 执行恶意脚本、添加惨犯链接 |
其实我们最常遇到的XSS就是评论区、搜索结果页这类。
2. CSRF (Cross-Site Request Forgery)
漏洞原理: 惊骗已登录用户在未知情出发惨犯请求,利用浏览器自动带上 Cookie 证明身份
| 类型 | 规则 | 危害示例 |
|---|---|---|
| 登录CSRF | 以惨犯账号进行登录并记录业务 | 骗取用户填写信用卡信息 |
| 存储型CSRF | 通过XSS/添加隐藏请求 | 被选上的页面一打开就执行操作 |
CSRF不能盗数据,但可以强制你做操作。
3. XSS vs CSRF 对比
| 维度 | XSS | CSRF |
|---|---|---|
| 攻击方向 | 可写可读,能编辑DOM和取数据 | 只能发起请求,不能阅读数据 |
| 依赖条件 | 不需要登录 | 需要登录且Cookie有效 |
| 恶意代码位置 | 页面自身 | 第三方网站 |
二、Vue 和 React 对于安全的默认防护
▶ Vue
- 在
{{ userInput }}中自动将HTML中的特殊字符转义,防止XSS
▶ React
- JSX中实值传入会被封装和转义,也是防止XSS的本质机制
▶ CSRF
-
Vue / React 本身不提供CSRF防护,需要合作后端:
- 通过 token / 签名 / https / post 等手段
三、我是如何实现安全接口封装
1. 封装基本 axios 请求
export const instance: AxiosInstance = axios.create({
baseURL: BASE_URL,
headers: {
"Content-Type": "multipart/form-data",
},
});
2. 请求拦截 - 添加 token
instance.interceptors.request.use(async (config) => {
const store: EnhancedStore = await import("@/store").then((m) => m.default);
const state: RootState = store.getState();
config.headers.Authorization = `${state?.app?.userInfo?.user_token}`;
return config;
});
3. 签名 sig 和 admin_user_id 处理
- 支持
FormData和普通对象 - 将所有字符串换行符等组合 hash
- 根据请求方法分配 data/或 params
4. 输出文件模式
instance.interceptors.response.use((response) => {
if (response.config.responseType === "blob") {
return Promise.resolve(response); // 直接返回完整 blob
}
const { data } = response;
if (data?.code == 0) return Promise.resolve(response.data);
message.error(data?.msg || "请求失败");
return Promise.reject(data);
});
四、安全组件展示:FormData + sig + 防CRSF
签名规则
- 签名 = md5(sortParams(params) + SIG)
SIG是预经编码定义好的密钥
实现:
if (params instanceof FormData) {
params.append("admin_user_id", adminId);
// 展开 entries 清洗
for (const [key, val] of params.entries()) {
if (!isFileOrBlob(val)) {
const v = (val as string).replace(/\r\n/g, "\n");
sigParams[key] = v;
params.set(key, v);
}
}
params.append("sig", md5(sortParams(sigParams) + SIG));
}
五、FormData 短定理解
FormData是构造 multipart/form-data 数据的 API- 支持上传文件
- 不能 JSON.stringify()
常用 API
| API | 说明 |
|---|---|
| .append | 添加数据(可重复键) |
| .set | 设置数据(会覆盖) |
| .get | 获取值 |
| .delete | 删除键 |
| .entries | 遍历所有数据 |
六、频隔控制 + URL 加密
1. 对 id 加密(展示型安全)
export function encryptId(id:number|string) {
const encrypted = CryptoJS.AES.encrypt(id.toString(), SIG);
return encodeURIComponent(encrypted.toString());
}
2. 解密:
export function decryptId(encryptedStr:string) {
const decoded = decodeURIComponent(encryptedStr);
const bytes = CryptoJS.AES.decrypt(decoded, SIG);
return bytes.toString(CryptoJS.enc.Utf8);
}
七、使用 HTTPS 或升级 HTTP
在一切表单与数据交互之上,都推荐使用 HTTPS:
- HTTPS 使用加密连接,能阻止中间人窃听和篡改
- 浏览器对非 HTTPS 网站会显示“🔓不安全”
- 使用 SSL/TLS 可以提升信任与 SEO 收录效果
⚠️ 总结对比图:
| 比较项 | HTTP | HTTPS |
|---|---|---|
| 安全性 | 差 | 高 |
| 加密 | ❌ 明文 | ✅ SSL/TLS 加密 |
| 身份验证 | ❌ 无 | ✅ 有证书(CA)验证 |
| 被劫持风险 | 高 | 低 |
| SEO 友好 | 较差 | 优先收录 |
| 浏览器标识 | 🔓不安全提示 | 🔒绿色锁/安全提示 |
结论
从性能、编程、安全看,我们应该强化对 Web 安全的意识,尽可能在前端做好:
- Token 验证
- 拦截器签名结合 FormData
- POST 接口
- HTTPS 保障
- 用 AES + 签名 做 URL id 加密
我们无法止止全部攻击,但能做的是把我们的表单、接口、线上用户护在背后。安全不是结束,是开始。不要乱搞,做安全handsome man👏👏👏