Web前端安全,持久保护不限时。

143 阅读4分钟

我是前端彭于晏,我喂自己袋盐
作为一名前端开发者,了解 Web 安全基础是基本操作。本文精简整理常见网络攻击和应对策略,并分享我如何通过 request 封装、sig 签名、FormData 等技术,打造安全输入体系。


image.png

一、常见 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 对比

维度XSSCSRF
攻击方向可写可读,能编辑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 收录效果

⚠️ 总结对比图:

比较项HTTPHTTPS
安全性
加密❌ 明文✅ SSL/TLS 加密
身份验证❌ 无✅ 有证书(CA)验证
被劫持风险
SEO 友好较差优先收录
浏览器标识🔓不安全提示🔒绿色锁/安全提示

结论

从性能、编程、安全看,我们应该强化对 Web 安全的意识,尽可能在前端做好:

  • Token 验证
  • 拦截器签名结合 FormData
  • POST 接口
  • HTTPS 保障
  • 用 AES + 签名 做 URL id 加密

我们无法止止全部攻击,但能做的是把我们的表单、接口、线上用户护在背后。安全不是结束,是开始。不要乱搞,做安全handsome man👏👏👏