您现在的位置是:网站首页 > 常见安全威胁文章详情

常见安全威胁

Node.js作为流行的JavaScript运行时环境,广泛应用于后端开发。然而,其生态系统的开放性也带来了多种安全威胁,开发者需警惕这些风险并采取防护措施。

注入攻击

注入攻击是Node.js应用中最常见的安全威胁之一。攻击者通过构造恶意输入,使应用执行非预期的操作。SQL注入和命令注入是两种主要形式。

SQL注入示例:

const query = `SELECT * FROM users WHERE username = '${req.body.username}'`;
db.query(query, (err, result) => {
  // 攻击者可输入 ' OR '1'='1 绕过验证
});

防护方案应使用参数化查询:

const query = 'SELECT * FROM users WHERE username = ?';
db.query(query, [req.body.username], (err, result) => {
  // 安全查询
});

命令注入通常发生在调用系统命令时:

const { exec } = require('child_process');
exec(`ls ${req.query.dir}`, (err, stdout) => {
  // 攻击者可输入 ; rm -rf / 执行危险命令
});

应使用白名单验证输入:

const validDirs = ['/tmp', '/var'];
if (!validDirs.includes(req.query.dir)) {
  return res.status(400).send('Invalid directory');
}

跨站脚本攻击(XSS)

XSS攻击允许攻击者在用户浏览器中执行恶意脚本。Node.js应用中常见于未正确转义的动态内容。

反射型XSS示例:

app.get('/search', (req, res) => {
  res.send(`<p>搜索结果: ${req.query.q}</p>`);
  // 攻击者可构造 ?q=<script>恶意代码</script>
});

防护措施包括内容安全策略(CSP)和转义输出:

const escapeHtml = require('escape-html');
app.get('/search', (req, res) => {
  res.send(`<p>搜索结果: ${escapeHtml(req.query.q)}</p>`);
});

存储型XSS更危险,恶意脚本被持久化到数据库:

// 用户评论存储
comments.push({
  text: req.body.text, // 可能包含<script>alert(1)</script>
  user: req.user.id
});

敏感数据泄露

配置不当可能导致敏感信息如API密钥、数据库凭证泄露。常见问题包括:

  1. 将.env文件提交到版本控制
  2. 在错误日志中记录敏感数据
  3. 响应中包含过多信息

错误示例:

// config.js
module.exports = {
  dbPassword: 'supersecret', // 硬编码密码
  apiKey: '12345'
};

正确做法应使用环境变量:

// config.js
module.exports = {
  dbPassword: process.env.DB_PASSWORD,
  apiKey: process.env.API_KEY
};

不安全的依赖

Node.js应用通常依赖大量第三方包,可能引入漏洞。

检查依赖漏洞的方法:

npm audit

应定期更新依赖:

npm outdated
npm update

对于关键应用,可锁定依赖版本:

{
  "dependencies": {
    "express": "4.17.1" // 精确版本而非^4.17.1
  }
}

身份验证缺陷

不正确的身份验证实现会导致未授权访问。

常见问题包括:

  1. 弱密码策略
  2. 会话固定
  3. JWT实现不当

不安全的路由保护示例:

app.get('/admin', (req, res) => {
  if (req.cookies.loggedIn === 'true') { // 容易伪造
    res.send('管理员面板');
  }
});

应使用成熟的认证库如Passport.js:

const passport = require('passport');

app.get('/admin', 
  passport.authenticate('jwt', { session: false }),
  (req, res) => {
    res.send('管理员面板');
  }
);

拒绝服务(DoS)攻击

Node.js单线程特性使其易受DoS攻击。

常见攻击向量:

  1. 正则表达式灾难性回溯
  2. 未限制的请求体大小
  3. 未超时的长时间操作

易受攻击的正则示例:

app.post('/validate', (req, res) => {
  const regex = /^([a-zA-Z0-9]+)*$/; // 灾难性回溯
  const isValid = regex.test(req.body.input);
  res.json({ valid: isValid });
});

防护措施包括:

  1. 限制请求体大小:
app.use(express.json({ limit: '10kb' }));
  1. 设置请求超时:
const timeout = require('connect-timeout');
app.use(timeout('5s'));

不安全的文件操作

文件系统操作不当可能导致目录遍历等攻击。

漏洞示例:

app.get('/download', (req, res) => {
  const file = path.join(__dirname, 'files', req.query.file);
  res.download(file); // 攻击者可请求 ../../etc/passwd
});

应验证文件路径:

const allowedPath = path.join(__dirname, 'files');
const requestedPath = path.join(__dirname, 'files', req.query.file);

if (!requestedPath.startsWith(allowedPath)) {
  return res.status(403).send('禁止访问');
}

HTTP头部安全配置

不当的HTTP头部可能导致安全风险。关键头部包括:

  1. X-XSS-Protection
  2. X-Content-Type-Options
  3. Strict-Transport-Security
  4. Content-Security-Policy

配置示例:

const helmet = require('helmet');
app.use(helmet());

// 或手动配置
app.use((req, res, next) => {
  res.setHeader('X-Frame-Options', 'DENY');
  res.setHeader('X-Content-Type-Options', 'nosniff');
  next();
});

不安全的反序列化

JSON解析可能被滥用执行代码。

危险示例:

const data = JSON.parse(req.body, (key, value) => {
  if (key === '__proto__') return {}; // 原型污染防护
  return value;
});

应避免使用复杂的reviver函数,并验证输入结构。

服务器端请求伪造(SSRF)

应用发起不可信的HTTP请求可能导致内部网络探测。

漏洞示例:

app.get('/fetch', async (req, res) => {
  const response = await axios.get(req.query.url); // 可能访问内部服务
  res.send(response.data);
});

防护措施:

  1. 限制目标URL协议和域名
  2. 使用DNS重绑定防护
  3. 设置请求超时
const { URL } = require('url');

app.get('/fetch', async (req, res) => {
  const parsedUrl = new URL(req.query.url);
  if (!parsedUrl.hostname.endsWith('.example.com')) {
    return res.status(400).send('Invalid URL');
  }
  // 安全请求
});

日志注入

未处理的日志内容可能破坏日志系统或注入恶意内容。

漏洞示例:

app.use((req, res, next) => {
  console.log(`Request from ${req.ip}`); // 可能包含换行符
  next();
});

应清理日志内容:

const clean = (str) => str.replace(/\n/g, '\\n').replace(/\r/g, '\\r');

app.use((req, res, next) => {
  console.log(`Request from ${clean(req.ip)}`);
  next();
});

不安全的随机数生成

Math.random()不适用于安全场景。

不安全示例:

function generateToken() {
  return Math.random().toString(36).substr(2); // 可预测
}

应使用加密安全的随机数:

const crypto = require('crypto');

function generateToken() {
  return crypto.randomBytes(32).toString('hex');
}

原型污染

通过修改__proto__可能改变对象行为。

漏洞示例:

function merge(target, source) {
  for (const key in source) {
    target[key] = source[key]; // 可能污染原型
  }
}

防护方案:

function safeMerge(target, source) {
  for (const key in source) {
    if (key !== '__proto__' && key !== 'constructor') {
      target[key] = source[key];
    }
  }
}

不安全的子进程创建

不当的子进程调用可能导致命令注入。

危险示例:

const { exec } = require('child_process');
exec(`git clone ${req.body.repo}`, (err) => {
  // 可能注入额外命令
});

应使用分离参数:

const { spawn } = require('child_process');
const child = spawn('git', ['clone', req.body.repo]);

未验证的重定向

开放重定向可能被用于钓鱼攻击。

漏洞示例:

app.get('/redirect', (req, res) => {
  res.redirect(req.query.url); // 可能指向恶意网站
});

应验证目标域名:

const allowedDomains = new Set(['example.com', 'trusted.org']);

app.get('/redirect', (req, res) => {
  const url = new URL(req.query.url);
  if (!allowedDomains.has(url.hostname)) {
    return res.status(400).send('Invalid redirect');
  }
  res.redirect(url.toString());
});

上一篇: 压测工具使用

下一篇: 输入验证

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

  • 建站时间:2013/03/16
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步