Skip to content

前端安全问题

按照 MECE(相互独立,完全穷尽) 原则,全面列出前端安全问题,可以从以下维度进行分类:输入验证数据传输资源加载身份认证与授权浏览器特性依赖及配置

常用总结

  1. 输入验证与处理: 前端对与后端进行交互的数据进行验证和处理(包括字符长度、类型、文件大小等),防止恶意输入导致的安全问题。

    核心点:不符合要求的数据,过滤掉,不传给后端。

  2. 数据传输: 前端与后端进行数据传输时(不要使用硬编码将项目敏感信息泄露),需要确保数据的安全性,防止数据被窃取或篡改。

    核心点:敏感信息,不要直接传输,需要加密。

  3. 身份认证与授权:前端需要与后端进行身份认证和授权,确保只有合法用户才能访问敏感信息或执行敏感操作。

    核心点:资源谁能访问,怎么访问,访问权限要严格控制。

  4. 请求限制:前端需要限制请求次数,防止恶意请求导致的服务器压力。

    核心点:限制请求次数,防止恶意请求。

一、输入验证与处理

  1. 跨站脚本攻击(XSS)

    解决方案:使用框架自带的防 XSS 功能(如 Vue.js 和 React 的模板自动转义)。

    • 直接插入恶意脚本导致数据窃取或页面劫持。
    • 类型:存储型、反射型、DOM 型。
    • 防范:对输入进行转义、使用内容安全策略(CSP)。
  2. SQL 注入
    • 未验证的输入被拼接成 SQL 语句,影响数据库安全。
    • 防范:使用参数化查询或预编译语句,或 ORM 框架。
  3. 命令注入
    • 用户输入被用作命令执行参数,导致服务器被攻击。
    • 防范:对输入进行过滤,避免使用用户输入构建命令。
  4. 路径遍历攻击
    • 未验证的文件路径输入可能导致访问非授权文件。
    • 防范:对文件路径进行验证和规范化。
  5. 输入过长攻击
    • 输入长度未限制,导致内存溢出或拒绝服务。
    • 防范:限制输入长度,使用流式处理。
  6. 文件上传漏洞
    • 上传恶意文件如脚本文件,可能被执行。
    • 防范:验证文件类型和内容,限制文件大小。

二、数据传输与存储

  1. 明文传输
    • 数据通过 HTTP 明文传输,易被窃听和篡改。
    • 防范:使用 HTTPS 加密传输。
  2. 中间人攻击(MITM)
    • 数据传输过程中被拦截并修改。
    • 防范:使用 HTTPS,验证证书。
  3. Cookie 泄露
    • 不安全的 Cookie 被窃取,导致会话劫持。
    • 防范:设置 HttpOnly 和 Secure 标志。
  4. 本地存储泄露
    • 本地存储中保存敏感信息,易被恶意脚本或浏览器扩展窃取。
    • 防范:使用 HTTPS,限制存储内容。
  5. JSON 劫持
    • JSON 数据被外部脚本获取并利用。
    • 防范:使用 Content-Type 头部设置为 application/json,避免 JSONP。
  6. Token 曝露
    • API Token 等敏感信息硬编码到前端或泄露。
    • 防范:避免硬编码,使用环境变量或配置文件。

三、资源加载与依赖

  1. 第三方资源攻击
    • 引入的第三方脚本、库或框架中包含恶意代码。
    • 防范:验证第三方资源来源,使用内容安全策略(CSP)。
  2. 依赖漏洞
    • 使用的第三方库存在已知漏洞。
    • 防范:定期更新依赖,使用依赖管理工具。
  3. 资源完整性破坏
    • 外部资源被篡改为恶意版本。
    • 防范:使用内容哈希或数字签名验证资源完整性。
  4. 恶意 CDN 攻击
    • 不可信的 CDN 服务提供篡改后的资源。
    • 防范:选择可靠的 CDN 服务,验证资源来源。
  5. 动态资源加载
    • 动态插入的外部资源可能被恶意利用。
    • 防范:验证动态加载的资源,限制资源类型。

四、身份认证与授权

  1. 跨站请求伪造(CSRF)
    • 利用用户登录态发送恶意请求。
    • 防范:验证 Referer 头部,使用 CSRF Token。
  2. 暴力破解
    • 使用自动化脚本尝试破解用户密码。
    • 防范:限制登录尝试次数,使用验证码。
  3. Session 劫持
    • 窃取用户的会话 ID 并冒充用户。
    • 防范:使用安全的会话 ID,定期更换会话 ID。
  4. 权限提升
    • 利用漏洞获得高于实际授权的权限。
    • 防范:严格权限控制,限制用户操作。
  5. OAuth 2.0 相关漏洞
    • 未验证的重定向 URL 或 Token 曝露。
    • 防范:验证重定向 URL,限制 Token 权限。
  6. 多角色用户数据泄露
    • 前端未正确区分用户角色的数据展示。
    • 防范:根据用户角色展示数据,避免敏感信息泄露。

五、浏览器特性滥用

  1. 点击劫持(Clickjacking)
    • 页面嵌套透明 iframe 诱导用户操作。
    • 防范:使用 X-Frame-Options 头部,限制页面嵌入。
  2. DOM 劫持
    • 恶意扩展或脚本篡改页面 DOM 结构。
    • 防范:验证 DOM 操作,限制脚本权限。
  3. 浏览器缓存敏感数据
    • 敏感数据被缓存,可能被不可信用户获取。
    • 防范:使用 HTTP 缓存控制头部,避免缓存敏感数据。
  4. 窗口劫持(Tabnabbing)
    • 通过替换窗口内容钓鱼用户。
    • 防范:使用 Content-Security-Policy 头部,限制窗口内容来源。
  5. 服务工作者滥用
    • 攻击者通过劫持 Service Worker 控制离线资源。
    • 防范:验证 Service Worker 的来源,限制其权限。

六、配置与部署问题

  1. CSP 配置不当
    • Content-Security-Policy 配置错误,未限制可信来源。
    • 防范:正确配置 CSP,限制可信资源。
  2. 不安全的 HTTP Header
    • 未设置安全响应头(如 X-Frame-Options, X-Content-Type-Options)。
    • 防范:设置安全响应头,增强页面安全性。
  3. 缓存配置不当
    • 敏感页面或数据被客户端缓存。
    • 防范:设置合适的缓存策略,避免敏感数据缓存。
  4. 错误日志泄露
    • 部署环境暴露调试信息或错误日志。
    • 防范:避免在生产环境中暴露调试信息,限制错误日志输出。
  5. API 接口暴露
    • 前端代码泄露了后端接口,未加以隐藏。
    • 防范:使用混淆或加密技术保护 API 接口。
  6. 默认配置使用
    • 使用框架或工具的默认配置导致安全漏洞。
    • 防范:检查并更新框架或工具的配置,避免使用默认配置。

七、其他潜在风险

  1. 社交工程攻击
    • 利用社会信任传播恶意链接或脚本。
    • 防范:提高用户安全意识,避免点击不明链接。
  2. 恶意脚本扩展
    • 用户安装的恶意浏览器扩展干扰页面行为。
    • 防范:定期更新和审查浏览器扩展,避免安装未知扩展。
  3. 时间与流量分析攻击
    • 分析页面响应时间或流量模式获取敏感信息。
    • 防范:使用加密通信,防止流量分析。
  4. 拒绝服务攻击(DoS)
    • 大量请求导致页面或服务器无法响应。
    • 防范:使用负载均衡和限流策略,防止 DoS 攻击。
  5. WebSocket 滥用
    • 不安全的 WebSocket 通信被劫持。
    • 防范:使用 WSS 协议,并验证 WebSocket 连接。

八、常见的具体实践

基于 输入验证与处理数据传输身份认证与授权请求限制 的四个核心安全点,在 Vue 3 项目中可以通过以下代码示例来实现安全设计:

1. 输入验证与处理

实现目标: 确保用户输入数据符合预期格式,防止 XSS、SQL 注入、命令注入等问题。

vue
<template>
  <form @submit.prevent="handleSubmit">
    <input
      v-model="username"
      type="text"
      maxlength="20"
      placeholder="Enter your username"
    />
    <input v-model="email" type="email" placeholder="Enter your email" />
    <button type="submit">Submit</button>
  </form>
</template>

<script>
import { ref } from "vue";

export default {
  setup() {
    const username = ref("");
    const email = ref("");

    const handleSubmit = () => {
      // 1. 前端验证输入
      if (!/^[a-zA-Z0-9]{3,20}$/.test(username.value)) {
        alert("Invalid username. Use 3-20 alphanumeric characters.");
        return;
      }
      if (!/^\S+@\S+\.\S+$/.test(email.value)) {
        alert("Invalid email format.");
        return;
      }

      // 2. 数据发送到后端
      const payload = {
        username: username.value.trim(),
        email: email.value.trim(),
      };

      fetch("/api/submit", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(payload),
      });
    };

    return { username, email, handleSubmit };
  },
};
</script>

关键点:

  • 使用正则表达式和 maxlength 限制输入内容。
  • 对输入数据进行 trim 去除多余空格。
  • 在提交给后端之前再次验证。

2. 数据传输

实现目标: 加密敏感信息,防止数据被窃取或篡改。

javascript
// utils/encryption.js
import CryptoJS from "crypto-js";

// 对敏感数据进行加密
export const encryptData = (data, secretKey) => {
  return CryptoJS.AES.encrypt(JSON.stringify(data), secretKey).toString();
};

// 解密数据
export const decryptData = (encryptedData, secretKey) => {
  const bytes = CryptoJS.AES.decrypt(encryptedData, secretKey);
  return JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
};
vue
<script>
import { encryptData } from "@/utils/encryption";

export default {
  setup() {
    const secretKey = "your-secret-key"; // 建议从后端获取

    const sendData = async () => {
      const sensitiveData = { creditCard: "1234-5678-9876-5432", cvv: "123" };
      const encryptedPayload = encryptData(sensitiveData, secretKey);

      await fetch("/api/secure-endpoint", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ data: encryptedPayload }),
      });
    };

    return { sendData };
  },
};
</script>

关键点:

  • 敏感数据通过 AES 加密后传输。
  • 后端解密后再处理敏感信息。

3. 身份认证与授权

实现目标: 使用 Token 验证用户身份,限制访问权限。

javascript
// api/auth.js
import axios from "axios";

const apiClient = axios.create({
  baseURL: "/api",
  headers: {
    "Content-Type": "application/json",
  },
});

// 添加请求拦截器(附加 Token)
apiClient.interceptors.request.use((config) => {
  const token = localStorage.getItem("authToken");
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

// 用户登录
export const login = async (credentials) => {
  const response = await apiClient.post("/login", credentials);
  const token = response.data.token;
  localStorage.setItem("authToken", token); // 存储 Token
  return token;
};

// 获取用户信息
export const getUserInfo = async () => {
  return await apiClient.get("/user");
};
vue
<script>
import { login, getUserInfo } from "@/api/auth";

export default {
  setup() {
    const handleLogin = async () => {
      try {
        const token = await login({ username: "user", password: "pass" });
        console.log("Logged in successfully, token:", token);

        // 获取用户信息
        const userInfo = await getUserInfo();
        console.log("User info:", userInfo.data);
      } catch (error) {
        console.error("Login failed:", error);
      }
    };

    return { handleLogin };
  },
};
</script>

关键点:

  • 使用 localStoragesessionStorage 存储 Token。
  • 在 API 请求中通过拦截器自动附加 Token。

4. 请求限制

实现目标: 防止恶意请求(如暴力破解、DoS 攻击)。

vue
<script>
import axios from "axios";
import _ from "lodash";

export default {
  setup() {
    // 限制请求频率
    const rateLimitedFetch = _.throttle(async () => {
      try {
        const response = await axios.get("/api/rate-limited-endpoint");
        console.log(response.data);
      } catch (error) {
        console.error("Request failed:", error);
      }
    }, 3000); // 每 3 秒允许发送一次请求

    return { rateLimitedFetch };
  },
};
</script>

关键点:

  • 使用 lodashthrottledebounce 限制请求频率。
  • 服务端同样需要配合限流策略(如 Redis 记录用户请求频率)。