阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 安全编码规范

安全编码规范

作者:陈川 阅读数:58284人阅读 分类: JavaScript

JavaScript作为一门动态、弱类型的脚本语言,在开发过程中容易因编码不规范导致安全漏洞。遵循安全编码规范能有效减少潜在风险,提升代码质量和应用安全性。

变量声明与作用域控制

始终使用constlet替代var声明变量,避免变量提升和全局污染。对于需要保护的常量,使用Object.freeze()进行深度冻结:

// 不安全做法
var apiKey = '12345'; 

// 安全做法
const CONFIG = Object.freeze({
  API_KEY: '12345',
  MAX_RETRY: 3
});

// 尝试修改会静默失败
CONFIG.API_KEY = 'hack'; // 严格模式下报错

函数作用域内避免声明全局变量,使用IIFE封装敏感操作:

(function() {
  const secretToken = generateToken();
  // 安全的作用域操作
})();

输入验证与过滤

所有外部输入都应视为不可信数据。使用严格验证库如Joi或Yup:

import * as yup from 'yup';

const userSchema = yup.object().shape({
  username: yup.string()
    .required()
    .matches(/^[a-zA-Z0-9_]+$/, '仅允许字母数字和下划线'),
  age: yup.number()
    .integer()
    .min(13)
    .max(120)
});

// 验证示例
try {
  await userSchema.validate({
    username: "admin'--",
    age: "25"
  });
} catch (err) {
  console.error('验证失败:', err.errors);
}

对于DOM操作,始终对动态内容进行转义:

function safeHTML(str) {
  const div = document.createElement('div');
  div.textContent = str;
  return div.innerHTML;
}

document.getElementById('output').innerHTML = safeHTML(userInput);

安全通信与数据处理

使用HTTPS且避免在前端存储敏感信息。对于必须的API密钥,考虑使用HttpOnly Cookie:

// 不安全
localStorage.setItem('auth_token', 'Bearer xyz');

// 相对安全
fetch('/api/login', {
  method: 'POST',
  credentials: 'include',  // 配合后端HttpOnly Cookie
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ /* 数据 */ })
});

加密敏感数据时使用Web Crypto API而非自定义算法:

async function hashPassword(password) {
  const encoder = new TextEncoder();
  const data = encoder.encode(password + process.env.SALT);
  const hash = await crypto.subtle.digest('SHA-256', data);
  return Array.from(new Uint8Array(hash))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
}

防范XSS攻击

对于现代框架,React/Vue等已提供基础防护,但仍需注意危险场景:

// React中的危险操作示例
function UnsafeComponent({ userInput }) {
  // 错误做法
  return <div dangerouslySetInnerHTML={{ __html: userInput }} />;
  
  // 正确做法
  return <div>{userInput}</div>; // 自动转义
}

动态创建脚本时使用textContent而非innerHTML

const script = document.createElement('script');
script.textContent = 'console.log("安全执行")';
document.body.appendChild(script);

防范CSRF攻击

实现CSRF令牌机制,并与框架集成:

// 前端获取令牌
let csrfToken = document.querySelector('meta[name="csrf-token"]').content;

// 请求时携带
fetch('/api/transfer', {
  method: 'POST',
  headers: {
    'X-CSRF-Token': csrfToken,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ amount: 100 })
});

依赖管理安全

定期使用npm audit检查依赖,锁定版本号:

{
  "dependencies": {
    "lodash": "4.17.21",  // 固定版本
    "react": "^18.2.0"    // 允许补丁更新
  }
}

使用Content Security Policy (CSP)增强防护:

<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; script-src 'self' 'unsafe-inline' cdn.example.com;">

错误处理与日志

避免暴露敏感信息的错误消息:

try {
  await criticalOperation();
} catch (err) {
  // 不安全
  console.error(`操作失败: ${err.stack}`);
  
  // 安全做法
  console.error('操作失败: 系统错误');
  sendToMonitoring({
    errorCode: 'E500',
    timestamp: Date.now()
  });
}

性能与内存安全

避免内存泄漏的常见模式:

// 事件监听器泄漏
window.addEventListener('resize', heavyCalculation);

// 正确做法
const debouncedCalc = debounce(heavyCalculation, 200);
window.addEventListener('resize', debouncedCalc);

// 组件卸载时
window.removeEventListener('resize', debouncedCalc);

处理大文件时使用流式API:

async function processFile(file) {
  const stream = file.stream();
  const reader = stream.getReader();
  
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    // 分块处理数据
  }
}

现代API的安全实践

使用structuredClone替代JSON.parse(JSON.stringify())进行深拷贝:

const original = new Set([1, 2, new Map([[3, 4]])]);
const copy = structuredClone(original);  // 保持引用关系

Worker通信时验证消息来源:

// worker.js
self.onmessage = (event) => {
  if (event.origin !== window.location.origin) return;
  // 安全处理消息
};

类型安全增强

即使使用JavaScript也应考虑类型检查:

// 使用JSDoc增强类型安全
/**
 * @param {string} url
 * @param {{ method?: string, body?: object }} options
 * @returns {Promise<{ data: any, status: number }>}
 */
async function safeFetch(url, options = {}) {
  // 实现
}

浏览器存储规范

区分不同存储场景的使用:

// 会话级数据
sessionStorage.setItem('temp_data', JSON.stringify({ tabState: 'active' }));

// 长期偏好设置
localStorage.setItem('user_prefs', JSON.stringify({
  theme: 'dark',
  fontSize: 14
}));

// 敏感数据
const secureStore = {
  set(key, value) {
    crypto.subtle.encrypt(/* 加密参数 */)
      .then(ciphertext => {
        localStorage.setItem(key, ciphertext);
      });
  }
};

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:性能优化建议

下一篇:代码复用原则

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌