跳到主要内容

注入攻击防护

介绍

注入攻击是一类常见的安全漏洞,攻击者通过将恶意代码插入到应用程序的输入中,从而欺骗应用程序执行非预期的操作。注入攻击能够导致未授权访问、数据泄露、数据篡改甚至完全控制服务器。最常见的注入攻击类型包括SQL注入、NoSQL注入、命令注入、跨站脚本(XSS)和跨站请求伪造(CSRF)等。

原理

注入攻击的共同原理

  • 用户输入未验证:应用程序未对用户输入进行充分验证和过滤
  • 输入被当作代码执行:用户输入被直接拼接到代码中执行
  • 上下文混淆:用户输入被错误地识别为代码而非数据
  • 信任用户输入:应用程序过度信任用户提供的输入
  • 缺乏参数化:未使用参数化查询或命令
  • 输出未编码:未对输出到客户端的内容进行适当编码

主要注入攻击类型原理

  • SQL注入:将恶意SQL代码插入到查询中,欺骗数据库执行非授权操作
  • NoSQL注入:针对NoSQL数据库的注入攻击,利用查询构造漏洞
  • 命令注入:将恶意命令插入到系统命令中执行
  • XSS注入:将恶意脚本注入到网页中,当用户访问时执行
  • CSRF:诱导用户在已认证的情况下执行非预期操作
  • XML注入:通过修改XML输入来欺骗应用程序
  • LDAP注入:针对LDAP查询的注入攻击

图示

SQL注入流程
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ 攻击者 │ │ 应用程序 │ │ 数据库 │
└─────────┬─────┘ └─────────┬─────┘ └─────────┬─────┘
│ │ │
1. 发送恶意输入 │ │ │
───────────► │ │
│ │ │
2. 拼接SQL查询 │ │ │
│ │ │
3. 执行恶意查询 │ │ │
└───────────────────────► │
│ │
4. 执行SQL命令 │ │ │
└───────────────────────►
│ │
5. 返回敏感数据 │ │ │
◄───────────────────────┘ │

│ │ │
6. 接收敏感数据 │ │ │
◄───────────────────────────────────────────────────────────┘

XSS攻击流程
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ 攻击者 │ │ 应用程序 │ │ 用户浏览器 │
└─────────┬─────┘ └─────────┬─────┘ └─────────┬─────┘
│ │ │
1. 注入恶意脚本 │ │ │
───────────► │ │
│ │ │
2. 存储恶意脚本 │ │ │
│ │ │
3. 请求页面 │ │ │
│ │ │
│ │ ◄───────────────────┘
│ │ │
4. 返回含恶意脚本的页面 │ │
│ │ │
│ ◄───────────────────┘ │
│ │ │
5. 执行恶意脚本 │ │ │
│ │ ┌───────────────────►
│ │ │
6. 窃取用户数据 │ │ │
│ │ │
└───────────────────────┬───────────────────────┘

┌─────────▼─────────┐
│ 攻击者接收数据 │
└───────────────────┘

实例

SQL注入示例与防护

// 易受SQL注入攻击的代码
const express = require('express');
const mysql = require('mysql');
const app = express();
app.use(express.json());

const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'mydb'
});

// 危险:直接拼接用户输入
app.get('/api/users', (req, res) => {
const username = req.query.username;
const query = `SELECT * FROM users WHERE username = '${username}'`;
console.log('执行查询:', query);

connection.query(query, (error, results) => {
if (error) throw error;
res.json(results);
});
});

// 安全:使用参数化查询
app.get('/api/users/safe', (req, res) => {
const username = req.query.username;
const query = 'SELECT * FROM users WHERE username = ?';
console.log('执行查询:', query, [username]);

connection.query(query, [username], (error, results) => {
if (error) throw error;
res.json(results);
});
});

const PORT = 3000;
app.listen(PORT, () => {
console.log(`服务器运行在端口 ${PORT}`);
});

命令注入示例与防护

import os
from flask import Flask, request

app = Flask(__name__)

# 易受命令注入攻击的代码
@app.route('/api/ping')
def ping():
target = request.args.get('target', 'localhost')
# 危险:直接拼接用户输入到系统命令
command = f'ping -c 4 {target}'
print(f'执行命令: {command}')
result = os.popen(command).read()
return f'<pre>{result}</pre>'

# 安全:使用subprocess并限制参数
@app.route('/api/ping/safe')
def ping_safe():
target = request.args.get('target', 'localhost')
# 安全:使用列表形式传递参数,避免命令注入
command = ['ping', '-c', '4', target]
print(f'执行命令: {command}')
result = subprocess.run(command, capture_output=True, text=True)
return f'<pre>{result.stdout}</pre>'

if __name__ == '__main__':
app.run(port=3000)

XSS攻击示例与防护

const express = require('express');
const app = express();
app.use(express.json());

// 存储用户评论的数组(实际应用中应使用数据库)
const comments = [];

// 易受XSS攻击的代码
app.post('/api/comments', (req, res) => {
const { comment } = req.body;
// 危险:直接存储未过滤的用户输入
comments.push(comment);
res.json({ success: true, message: '评论已添加' });
});

app.get('/api/comments', (req, res) => {
// 危险:直接输出未编码的用户输入
let html = '<ul>';
comments.forEach(comment => {
html += `<li>${comment}</li>`;
});
html += '</ul>';
res.send(html);
});

// 安全:使用转义函数过滤用户输入
function escapeHtml(text) {
return text
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/