注入攻击防护
介绍
注入攻击是一类常见的安全漏洞,攻击者通过将恶意代码插入到应用程序的输入中,从而欺骗应用程序执行非预期的操作。注入攻击能够导致未授权访问、数据泄露、数据篡改甚至完全控制服务器。最常见的注入攻击类型包括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, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/