57 KiB
57 KiB
安全文档
版本历史
| 版本 | 日期 | 作者 | 变更说明 |
|---|---|---|---|
| 1.0 | 2024-01-20 | 安全团队 | 初始版本 |
1. 安全概述
1.1 安全目标
确保畜牧养殖管理平台的数据安全、系统安全和业务安全,保护用户隐私和企业资产。
1.2 安全原则
- 最小权限原则:用户和系统只获得完成任务所需的最小权限
- 深度防御:多层安全防护,避免单点故障
- 零信任架构:不信任任何用户或设备,持续验证
- 数据保护:全生命周期数据保护
- 持续监控:实时安全监控和威胁检测
1.3 安全合规
- 等保2.0:符合网络安全等级保护2.0要求
- GDPR:遵循欧盟通用数据保护条例
- 个人信息保护法:符合中国个人信息保护法要求
- 行业标准:遵循畜牧业相关安全标准
2. 安全架构
2.1 安全架构图
graph TB
subgraph "边界安全"
WAF[Web应用防火墙]
FW[网络防火墙]
IPS[入侵防护系统]
DDoS[DDoS防护]
end
subgraph "应用安全"
AUTH[身份认证]
AUTHZ[权限控制]
ENCRYPT[数据加密]
AUDIT[审计日志]
end
subgraph "数据安全"
BACKUP[数据备份]
MASK[数据脱敏]
DLP[数据防泄漏]
CRYPTO[加密存储]
end
subgraph "基础设施安全"
HOST[主机安全]
CONTAINER[容器安全]
NETWORK[网络安全]
MONITOR[安全监控]
end
Internet --> WAF
WAF --> FW
FW --> IPS
IPS --> AUTH
AUTH --> AUTHZ
AUTHZ --> ENCRYPT
ENCRYPT --> AUDIT
2.2 安全域划分
| 安全域 | 描述 | 安全等级 | 访问控制 |
|---|---|---|---|
| 互联网区 | 面向公网的服务 | 高 | WAF + 防火墙 |
| DMZ区 | 前端应用和负载均衡 | 高 | 严格访问控制 |
| 应用区 | 后端API服务 | 中 | 内网访问 |
| 数据区 | 数据库和存储 | 极高 | 最小权限访问 |
| 管理区 | 运维和管理系统 | 极高 | VPN + 双因子认证 |
3. 身份认证与授权
3.1 用户身份认证
3.1.1 多因子认证(MFA)
// 双因子认证实现
class TwoFactorAuth {
constructor() {
this.totpWindow = 30; // 30秒时间窗口
this.backupCodes = [];
}
// 生成TOTP密钥
generateSecret(userId) {
const secret = speakeasy.generateSecret({
name: `畜牧管理平台 (${userId})`,
issuer: '畜牧管理平台'
});
return {
secret: secret.base32,
qrCode: qrcode.toDataURL(secret.otpauth_url)
};
}
// 验证TOTP令牌
verifyToken(secret, token) {
return speakeasy.totp.verify({
secret: secret,
encoding: 'base32',
token: token,
window: this.totpWindow
});
}
// 生成备用码
generateBackupCodes() {
const codes = [];
for (let i = 0; i < 10; i++) {
codes.push(crypto.randomBytes(4).toString('hex').toUpperCase());
}
return codes;
}
// 验证备用码
verifyBackupCode(userId, code) {
// 从数据库获取用户备用码
const userBackupCodes = this.getUserBackupCodes(userId);
const index = userBackupCodes.indexOf(code);
if (index !== -1) {
// 使用后删除备用码
userBackupCodes.splice(index, 1);
this.updateUserBackupCodes(userId, userBackupCodes);
return true;
}
return false;
}
}
3.1.2 JWT令牌安全
// JWT安全配置
const jwtConfig = {
// 使用RS256算法
algorithm: 'RS256',
// 短期访问令牌
accessTokenExpiry: '15m',
// 长期刷新令牌
refreshTokenExpiry: '7d',
// 令牌发行者
issuer: 'xlxumu-platform',
// 令牌受众
audience: 'xlxumu-users'
};
class JWTManager {
constructor() {
this.privateKey = fs.readFileSync('private.pem');
this.publicKey = fs.readFileSync('public.pem');
this.blacklist = new Set(); // 令牌黑名单
}
// 生成访问令牌
generateAccessToken(payload) {
return jwt.sign(payload, this.privateKey, {
algorithm: jwtConfig.algorithm,
expiresIn: jwtConfig.accessTokenExpiry,
issuer: jwtConfig.issuer,
audience: jwtConfig.audience,
jwtid: uuidv4() // 唯一标识符
});
}
// 生成刷新令牌
generateRefreshToken(userId) {
const payload = {
userId: userId,
type: 'refresh',
tokenFamily: uuidv4() // 令牌族标识
};
return jwt.sign(payload, this.privateKey, {
algorithm: jwtConfig.algorithm,
expiresIn: jwtConfig.refreshTokenExpiry,
issuer: jwtConfig.issuer,
audience: jwtConfig.audience,
jwtid: uuidv4()
});
}
// 验证令牌
verifyToken(token) {
try {
// 检查黑名单
if (this.blacklist.has(token)) {
throw new Error('Token is blacklisted');
}
const decoded = jwt.verify(token, this.publicKey, {
algorithms: [jwtConfig.algorithm],
issuer: jwtConfig.issuer,
audience: jwtConfig.audience
});
return decoded;
} catch (error) {
throw new Error('Invalid token');
}
}
// 撤销令牌
revokeToken(token) {
this.blacklist.add(token);
// 可以设置定时清理过期的黑名单令牌
}
}
3.2 权限控制系统
3.2.1 RBAC权限模型
// 基于角色的访问控制
class RBACManager {
constructor() {
this.roles = new Map();
this.permissions = new Map();
this.userRoles = new Map();
}
// 定义权限
definePermission(name, resource, action) {
this.permissions.set(name, {
resource: resource,
action: action,
description: `${action} on ${resource}`
});
}
// 定义角色
defineRole(name, permissions) {
this.roles.set(name, {
name: name,
permissions: permissions,
inherits: []
});
}
// 角色继承
addRoleInheritance(childRole, parentRole) {
if (this.roles.has(childRole) && this.roles.has(parentRole)) {
this.roles.get(childRole).inherits.push(parentRole);
}
}
// 分配角色给用户
assignRole(userId, roleName) {
if (!this.userRoles.has(userId)) {
this.userRoles.set(userId, []);
}
this.userRoles.get(userId).push(roleName);
}
// 检查用户权限
hasPermission(userId, permission) {
const userRoles = this.userRoles.get(userId) || [];
for (const roleName of userRoles) {
if (this.roleHasPermission(roleName, permission)) {
return true;
}
}
return false;
}
// 检查角色权限
roleHasPermission(roleName, permission) {
const role = this.roles.get(roleName);
if (!role) return false;
// 检查直接权限
if (role.permissions.includes(permission)) {
return true;
}
// 检查继承权限
for (const parentRole of role.inherits) {
if (this.roleHasPermission(parentRole, permission)) {
return true;
}
}
return false;
}
}
// 权限中间件
const permissionMiddleware = (permission) => {
return async (req, res, next) => {
try {
const token = req.headers.authorization?.replace('Bearer ', '');
const decoded = jwtManager.verifyToken(token);
if (!rbacManager.hasPermission(decoded.userId, permission)) {
return res.status(403).json({
error: 'Insufficient permissions',
required: permission
});
}
req.user = decoded;
next();
} catch (error) {
res.status(401).json({ error: 'Unauthorized' });
}
};
};
3.2.2 权限配置
# 权限配置文件
permissions:
# 用户管理权限
user.create: "创建用户"
user.read: "查看用户"
user.update: "更新用户"
user.delete: "删除用户"
# 农场管理权限
farm.create: "创建农场"
farm.read: "查看农场"
farm.update: "更新农场"
farm.delete: "删除农场"
# 动物管理权限
animal.create: "添加动物"
animal.read: "查看动物"
animal.update: "更新动物信息"
animal.delete: "删除动物"
# 系统管理权限
system.config: "系统配置"
system.monitor: "系统监控"
system.backup: "数据备份"
roles:
# 超级管理员
super_admin:
permissions:
- "*" # 所有权限
# 系统管理员
admin:
permissions:
- "user.*"
- "farm.*"
- "animal.*"
- "system.config"
- "system.monitor"
# 农场主
farm_owner:
permissions:
- "farm.read"
- "farm.update"
- "animal.*"
# 普通用户
user:
permissions:
- "farm.read"
- "animal.read"
4. 数据安全
4.1 数据加密
4.1.1 传输加密
# Nginx SSL配置
server {
listen 443 ssl http2;
server_name www.xlxumu.com;
# SSL证书配置
ssl_certificate /etc/letsencrypt/live/www.xlxumu.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.xlxumu.com/privkey.pem;
# SSL安全配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# HSTS配置
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# 其他安全头
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none';" always;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# 强制HTTPS重定向
server {
listen 80;
server_name www.xlxumu.com;
return 301 https://$server_name$request_uri;
}
4.1.2 存储加密
// 数据库字段加密
const crypto = require('crypto');
class FieldEncryption {
constructor() {
this.algorithm = 'aes-256-gcm';
this.keyLength = 32;
this.ivLength = 16;
this.tagLength = 16;
this.masterKey = process.env.ENCRYPTION_MASTER_KEY;
}
// 生成数据加密密钥
generateDataKey() {
return crypto.randomBytes(this.keyLength);
}
// 加密数据
encrypt(plaintext, dataKey) {
const iv = crypto.randomBytes(this.ivLength);
const cipher = crypto.createCipher(this.algorithm, dataKey, iv);
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
encrypted += cipher.final('hex');
const tag = cipher.getAuthTag();
return {
encrypted: encrypted,
iv: iv.toString('hex'),
tag: tag.toString('hex')
};
}
// 解密数据
decrypt(encryptedData, dataKey) {
const decipher = crypto.createDecipher(
this.algorithm,
dataKey,
Buffer.from(encryptedData.iv, 'hex')
);
decipher.setAuthTag(Buffer.from(encryptedData.tag, 'hex'));
let decrypted = decipher.update(encryptedData.encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
// 加密敏感字段
encryptSensitiveFields(data, fields) {
const dataKey = this.generateDataKey();
const encryptedData = { ...data };
fields.forEach(field => {
if (data[field]) {
encryptedData[field] = this.encrypt(data[field], dataKey);
}
});
// 加密数据密钥
encryptedData._dataKey = this.encryptDataKey(dataKey);
return encryptedData;
}
// 解密敏感字段
decryptSensitiveFields(encryptedData, fields) {
const dataKey = this.decryptDataKey(encryptedData._dataKey);
const data = { ...encryptedData };
fields.forEach(field => {
if (encryptedData[field]) {
data[field] = this.decrypt(encryptedData[field], dataKey);
}
});
delete data._dataKey;
return data;
}
// 使用主密钥加密数据密钥
encryptDataKey(dataKey) {
const iv = crypto.randomBytes(this.ivLength);
const cipher = crypto.createCipher(this.algorithm, this.masterKey, iv);
let encrypted = cipher.update(dataKey, null, 'hex');
encrypted += cipher.final('hex');
const tag = cipher.getAuthTag();
return {
encrypted: encrypted,
iv: iv.toString('hex'),
tag: tag.toString('hex')
};
}
// 使用主密钥解密数据密钥
decryptDataKey(encryptedDataKey) {
const decipher = crypto.createDecipher(
this.algorithm,
this.masterKey,
Buffer.from(encryptedDataKey.iv, 'hex')
);
decipher.setAuthTag(Buffer.from(encryptedDataKey.tag, 'hex'));
let decrypted = decipher.update(encryptedDataKey.encrypted, 'hex');
decrypted += decipher.final();
return decrypted;
}
}
4.2 数据脱敏
// 数据脱敏工具
class DataMasking {
// 手机号脱敏
maskPhone(phone) {
if (!phone || phone.length < 11) return phone;
return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
}
// 身份证号脱敏
maskIdCard(idCard) {
if (!idCard || idCard.length < 15) return idCard;
return idCard.replace(/(\d{6})\d{8}(\d{4})/, '$1********$2');
}
// 邮箱脱敏
maskEmail(email) {
if (!email || !email.includes('@')) return email;
const [username, domain] = email.split('@');
const maskedUsername = username.length > 2
? username.substring(0, 2) + '*'.repeat(username.length - 2)
: username;
return `${maskedUsername}@${domain}`;
}
// 银行卡号脱敏
maskBankCard(cardNumber) {
if (!cardNumber || cardNumber.length < 16) return cardNumber;
return cardNumber.replace(/(\d{4})\d{8}(\d{4})/, '$1********$2');
}
// 姓名脱敏
maskName(name) {
if (!name || name.length < 2) return name;
return name.charAt(0) + '*'.repeat(name.length - 1);
}
// 地址脱敏
maskAddress(address) {
if (!address || address.length < 10) return address;
return address.substring(0, 6) + '*'.repeat(address.length - 6);
}
// 批量脱敏
maskObject(obj, maskRules) {
const masked = { ...obj };
Object.keys(maskRules).forEach(field => {
if (masked[field]) {
const maskType = maskRules[field];
switch (maskType) {
case 'phone':
masked[field] = this.maskPhone(masked[field]);
break;
case 'email':
masked[field] = this.maskEmail(masked[field]);
break;
case 'idCard':
masked[field] = this.maskIdCard(masked[field]);
break;
case 'bankCard':
masked[field] = this.maskBankCard(masked[field]);
break;
case 'name':
masked[field] = this.maskName(masked[field]);
break;
case 'address':
masked[field] = this.maskAddress(masked[field]);
break;
}
}
});
return masked;
}
}
// 使用示例
const dataMasking = new DataMasking();
// API响应数据脱敏中间件
const maskingMiddleware = (maskRules) => {
return (req, res, next) => {
const originalSend = res.send;
res.send = function(data) {
if (typeof data === 'object' && data !== null) {
if (Array.isArray(data)) {
data = data.map(item => dataMasking.maskObject(item, maskRules));
} else {
data = dataMasking.maskObject(data, maskRules);
}
}
originalSend.call(this, data);
};
next();
};
};
4.3 数据备份与恢复
#!/bin/bash
# secure-backup.sh - 安全备份脚本
BACKUP_DIR="/secure-backup"
ENCRYPTION_KEY_FILE="/etc/backup-encryption.key"
DATE=$(date +%Y%m%d_%H%M%S)
# 创建加密密钥(首次运行)
create_encryption_key() {
if [ ! -f "$ENCRYPTION_KEY_FILE" ]; then
openssl rand -base64 32 > "$ENCRYPTION_KEY_FILE"
chmod 600 "$ENCRYPTION_KEY_FILE"
chown root:root "$ENCRYPTION_KEY_FILE"
fi
}
# 加密备份文件
encrypt_backup() {
local source_file=$1
local encrypted_file="${source_file}.enc"
openssl enc -aes-256-cbc -salt -in "$source_file" -out "$encrypted_file" -pass file:"$ENCRYPTION_KEY_FILE"
if [ $? -eq 0 ]; then
rm "$source_file" # 删除明文备份
echo "✅ 备份文件已加密: $encrypted_file"
else
echo "❌ 备份文件加密失败"
return 1
fi
}
# 解密备份文件
decrypt_backup() {
local encrypted_file=$1
local decrypted_file="${encrypted_file%.enc}"
openssl enc -aes-256-cbc -d -in "$encrypted_file" -out "$decrypted_file" -pass file:"$ENCRYPTION_KEY_FILE"
if [ $? -eq 0 ]; then
echo "✅ 备份文件已解密: $decrypted_file"
else
echo "❌ 备份文件解密失败"
return 1
fi
}
# 安全备份主函数
secure_backup() {
echo "开始安全备份: $DATE"
# 创建备份目录
mkdir -p "$BACKUP_DIR"
# 创建加密密钥
create_encryption_key
# 备份数据库
echo "备份数据库..."
docker exec mysql-master mysqldump -u root -p${MYSQL_ROOT_PASSWORD} \
--single-transaction \
--routines \
--triggers \
--all-databases > "$BACKUP_DIR/mysql_backup_$DATE.sql"
# 加密数据库备份
encrypt_backup "$BACKUP_DIR/mysql_backup_$DATE.sql"
# 备份配置文件
echo "备份配置文件..."
tar -czf "$BACKUP_DIR/config_backup_$DATE.tar.gz" ./config ./nginx .env.production
encrypt_backup "$BACKUP_DIR/config_backup_$DATE.tar.gz"
# 生成备份校验和
echo "生成备份校验和..."
find "$BACKUP_DIR" -name "*_$DATE.*.enc" -exec sha256sum {} \; > "$BACKUP_DIR/checksums_$DATE.txt"
echo "安全备份完成"
}
# 验证备份完整性
verify_backup() {
local checksum_file=$1
if [ ! -f "$checksum_file" ]; then
echo "校验和文件不存在: $checksum_file"
return 1
fi
echo "验证备份完整性..."
sha256sum -c "$checksum_file"
if [ $? -eq 0 ]; then
echo "✅ 备份完整性验证通过"
else
echo "❌ 备份完整性验证失败"
return 1
fi
}
# 主函数
case $1 in
"backup")
secure_backup
;;
"decrypt")
decrypt_backup $2
;;
"verify")
verify_backup $2
;;
*)
echo "使用方法: $0 {backup|decrypt <file>|verify <checksum_file>}"
;;
esac
5. 网络安全
5.1 防火墙配置
#!/bin/bash
# firewall-config.sh - 防火墙配置脚本
# 清空现有规则
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
# 设置默认策略
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# 允许本地回环
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# 允许已建立的连接
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 允许SSH(修改为非标准端口)
iptables -A INPUT -p tcp --dport 2222 -j ACCEPT
# 允许HTTP和HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# 允许内网访问数据库端口
iptables -A INPUT -p tcp -s 10.0.0.0/8 --dport 3306 -j ACCEPT
iptables -A INPUT -p tcp -s 172.16.0.0/12 --dport 3306 -j ACCEPT
iptables -A INPUT -p tcp -s 192.168.0.0/16 --dport 3306 -j ACCEPT
# 允许Redis访问
iptables -A INPUT -p tcp -s 10.0.0.0/8 --dport 6379 -j ACCEPT
iptables -A INPUT -p tcp -s 172.16.0.0/12 --dport 6379 -j ACCEPT
iptables -A INPUT -p tcp -s 192.168.0.0/16 --dport 6379 -j ACCEPT
# 防止DDoS攻击
iptables -A INPUT -p tcp --dport 80 -m limit --limit 25/minute --limit-burst 100 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -m limit --limit 25/minute --limit-burst 100 -j ACCEPT
# 防止端口扫描
iptables -A INPUT -m recent --name portscan --rcheck --seconds 86400 -j DROP
iptables -A INPUT -m recent --name portscan --remove
iptables -A INPUT -p tcp -m tcp --dport 139 -m recent --name portscan --set -j LOG --log-prefix "portscan:"
iptables -A INPUT -p tcp -m tcp --dport 139 -j DROP
# 记录被丢弃的包
iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
# 保存规则
iptables-save > /etc/iptables/rules.v4
echo "防火墙配置完成"
5.2 入侵检测系统
# fail2ban配置
# /etc/fail2ban/jail.local
[DEFAULT]
# 禁用时间(秒)
bantime = 3600
# 查找时间窗口(秒)
findtime = 600
# 最大重试次数
maxretry = 3
# 忽略的IP地址
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 3600
[nginx-limit-req]
enabled = true
filter = nginx-limit-req
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 3600
[nginx-botsearch]
enabled = true
filter = nginx-botsearch
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 7200
# 自定义过滤器
# /etc/fail2ban/filter.d/nginx-botsearch.conf
[Definition]
failregex = ^<HOST> -.*"(GET|POST).*HTTP.*" (404|444) .*$
ignoreregex =
#!/bin/bash
# intrusion-detection.sh - 入侵检测脚本
LOG_FILE="/var/log/intrusion-detection.log"
ALERT_EMAIL="security@xlxumu.com"
# 检查异常登录
check_suspicious_logins() {
echo "检查异常登录..." | tee -a $LOG_FILE
# 检查失败登录次数
failed_logins=$(grep "Failed password" /var/log/auth.log | grep "$(date +%b\ %d)" | wc -l)
if [ $failed_logins -gt 10 ]; then
echo "警告: 今日失败登录次数过多 ($failed_logins)" | tee -a $LOG_FILE
send_alert "异常登录检测" "今日失败登录次数: $failed_logins"
fi
# 检查异常IP
suspicious_ips=$(grep "Failed password" /var/log/auth.log | grep "$(date +%b\ %d)" | awk '{print $11}' | sort | uniq -c | sort -nr | head -5)
if [ ! -z "$suspicious_ips" ]; then
echo "可疑IP地址:" | tee -a $LOG_FILE
echo "$suspicious_ips" | tee -a $LOG_FILE
fi
}
# 检查异常网络连接
check_network_connections() {
echo "检查异常网络连接..." | tee -a $LOG_FILE
# 检查大量连接的IP
high_conn_ips=$(netstat -an | grep :80 | grep ESTABLISHED | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | head -10)
echo "高连接数IP:" | tee -a $LOG_FILE
echo "$high_conn_ips" | tee -a $LOG_FILE
# 检查异常端口连接
unusual_ports=$(netstat -tuln | grep -v -E "(22|80|443|3306|6379|27017)" | grep LISTEN)
if [ ! -z "$unusual_ports" ]; then
echo "异常监听端口:" | tee -a $LOG_FILE
echo "$unusual_ports" | tee -a $LOG_FILE
send_alert "异常端口检测" "发现异常监听端口: $unusual_ports"
fi
}
# 检查文件完整性
check_file_integrity() {
echo "检查文件完整性..." | tee -a $LOG_FILE
# 检查关键系统文件
critical_files=("/etc/passwd" "/etc/shadow" "/etc/ssh/sshd_config" "/etc/sudoers")
for file in "${critical_files[@]}"; do
if [ -f "$file" ]; then
current_hash=$(sha256sum "$file" | awk '{print $1}')
stored_hash_file="/var/lib/integrity/${file//\//_}.hash"
if [ -f "$stored_hash_file" ]; then
stored_hash=$(cat "$stored_hash_file")
if [ "$current_hash" != "$stored_hash" ]; then
echo "警告: 文件 $file 已被修改" | tee -a $LOG_FILE
send_alert "文件完整性检测" "关键文件 $file 已被修改"
fi
else
# 首次运行,存储哈希值
mkdir -p "/var/lib/integrity"
echo "$current_hash" > "$stored_hash_file"
fi
fi
done
}
# 检查恶意进程
check_malicious_processes() {
echo "检查恶意进程..." | tee -a $LOG_FILE
# 检查高CPU使用率进程
high_cpu_processes=$(ps aux --sort=-%cpu | head -10 | awk '$3 > 80 {print $2, $11}')
if [ ! -z "$high_cpu_processes" ]; then
echo "高CPU使用率进程:" | tee -a $LOG_FILE
echo "$high_cpu_processes" | tee -a $LOG_FILE
fi
# 检查可疑进程名
suspicious_processes=$(ps aux | grep -E "(nc|netcat|ncat|socat|wget|curl)" | grep -v grep)
if [ ! -z "$suspicious_processes" ]; then
echo "可疑进程:" | tee -a $LOG_FILE
echo "$suspicious_processes" | tee -a $LOG_FILE
send_alert "可疑进程检测" "发现可疑进程: $suspicious_processes"
fi
}
# 发送告警
send_alert() {
local subject=$1
local message=$2
# 发送邮件告警
echo "$message" | mail -s "$subject" "$ALERT_EMAIL"
# 发送钉钉告警
curl -X POST "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN" \
-H 'Content-Type: application/json' \
-d "{\"msgtype\": \"text\",\"text\": {\"content\": \"🚨 安全告警: $subject\\n$message\"}}"
}
# 主函数
main() {
echo "=== 入侵检测开始 $(date) ===" | tee -a $LOG_FILE
check_suspicious_logins
check_network_connections
check_file_integrity
check_malicious_processes
echo "=== 入侵检测完成 ===" | tee -a $LOG_FILE
}
main
6. 应用安全
6.1 输入验证与过滤
// 输入验证中间件
const validator = require('validator');
const xss = require('xss');
class InputValidator {
// 通用验证规则
static rules = {
username: {
required: true,
minLength: 3,
maxLength: 20,
pattern: /^[a-zA-Z0-9_]+$/,
message: '用户名只能包含字母、数字和下划线,长度3-20位'
},
email: {
required: true,
validator: validator.isEmail,
message: '请输入有效的邮箱地址'
},
phone: {
required: true,
pattern: /^1[3-9]\d{9}$/,
message: '请输入有效的手机号码'
},
password: {
required: true,
minLength: 8,
maxLength: 128,
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/,
message: '密码必须包含大小写字母、数字和特殊字符,长度8-128位'
}
};
// 验证单个字段
static validateField(value, rule) {
const errors = [];
// 必填验证
if (rule.required && (!value || value.toString().trim() === '')) {
errors.push('该字段为必填项');
return errors;
}
if (!value) return errors;
const stringValue = value.toString();
// 长度验证
if (rule.minLength && stringValue.length < rule.minLength) {
errors.push(`最小长度为 ${rule.minLength}`);
}
if (rule.maxLength && stringValue.length > rule.maxLength) {
errors.push(`最大长度为 ${rule.maxLength}`);
}
// 正则验证
if (rule.pattern && !rule.pattern.test(stringValue)) {
errors.push(rule.message || '格式不正确');
}
// 自定义验证器
if (rule.validator && !rule.validator(stringValue)) {
errors.push(rule.message || '验证失败');
}
return errors;
}
// 验证对象
static validate(data, rules) {
const errors = {};
Object.keys(rules).forEach(field => {
const fieldErrors = this.validateField(data[field], rules[field]);
if (fieldErrors.length > 0) {
errors[field] = fieldErrors;
}
});
return {
isValid: Object.keys(errors).length === 0,
errors: errors
};
}
// XSS过滤
static sanitizeInput(input) {
if (typeof input === 'string') {
return xss(input, {
whiteList: {}, // 不允许任何HTML标签
stripIgnoreTag: true,
stripIgnoreTagBody: ['script']
});
}
if (typeof input === 'object' && input !== null) {
const sanitized = {};
Object.keys(input).forEach(key => {
sanitized[key] = this.sanitizeInput(input[key]);
});
return sanitized;
}
return input;
}
// SQL注入防护
static escapeSql(input) {
if (typeof input === 'string') {
return input.replace(/[\0\x08\x09\x1a\n\r"'\\\%]/g, function (char) {
switch (char) {
case "\0":
return "\\0";
case "\x08":
return "\\b";
case "\x09":
return "\\t";
case "\x1a":
return "\\z";
case "\n":
return "\\n";
case "\r":
return "\\r";
case "\"":
case "'":
case "\\":
case "%":
return "\\" + char;
default:
return char;
}
});
}
return input;
}
}
// 验证中间件
const validationMiddleware = (rules) => {
return (req, res, next) => {
// XSS过滤
req.body = InputValidator.sanitizeInput(req.body);
req.query = InputValidator.sanitizeInput(req.query);
req.params = InputValidator.sanitizeInput(req.params);
// 输入验证
const validation = InputValidator.validate(req.body, rules);
if (!validation.isValid) {
return res.status(400).json({
error: 'Validation failed',
details: validation.errors
});
}
next();
};
};
6.2 API安全
// API安全中间件
const rateLimit = require('express-rate-limit');
const helmet = require('helmet');
const cors = require('cors');
// 速率限制
const createRateLimit = (windowMs, max, message) => {
return rateLimit({
windowMs: windowMs,
max: max,
message: {
error: 'Too many requests',
message: message,
retryAfter: Math.ceil(windowMs / 1000)
},
standardHeaders: true,
legacyHeaders: false,
// 自定义键生成器(基于IP和用户ID)
keyGenerator: (req) => {
return req.user ? `${req.ip}-${req.user.id}` : req.ip;
},
// 跳过成功的请求
skipSuccessfulRequests: true
});
};
// 不同类型的速率限制
const rateLimits = {
// 通用API限制
general: createRateLimit(15 * 60 * 1000, 100, '请求过于频繁,请稍后再试'),
// 登录限制
auth: createRateLimit(15 * 60 * 1000, 5, '登录尝试过于频繁,请15分钟后再试'),
// 注册限制
register: createRateLimit(60 * 60 * 1000, 3, '注册请求过于频繁,请1小时后再试'),
// 密码重置限制
passwordReset: createRateLimit(60 * 60 * 1000, 3, '密码重置请求过于频繁,请1小时后再试'),
// 文件上传限制
upload: createRateLimit(60 * 60 * 1000, 10, '文件上传过于频繁,请1小时后再试')
};
// CORS配置
const corsOptions = {
origin: function (origin, callback) {
const allowedOrigins = [
'https://www.xlxumu.com',
'https://admin.xlxumu.com',
'https://api.xlxumu.com'
];
// 允许移动应用和开发环境
if (!origin || allowedOrigins.includes(origin) ||
(process.env.NODE_ENV === 'development' && origin.includes('localhost'))) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true,
optionsSuccessStatus: 200,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With']
};
// 安全头配置
const helmetOptions = {
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'"],
fontSrc: ["'self'"],
objectSrc: ["'none'"],
mediaSrc: ["'self'"],
frameSrc: ["'none'"]
}
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
};
// API安全中间件组合
const apiSecurity = (app) => {
// 基础安全头
app.use(helmet(helmetOptions));
// CORS配置
app.use(cors(corsOptions));
// 通用速率限制
app.use('/api/', rateLimits.general);
// 特定路由的速率限制
app.use('/api/auth/login', rateLimits.auth);
app.use('/api/auth/register', rateLimits.register);
app.use('/api/auth/reset-password', rateLimits.passwordReset);
app.use('/api/upload', rateLimits.upload);
// 请求大小限制
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
// 隐藏技术栈信息
app.disable('x-powered-by');
// API版本控制
app.use('/api/v1', require('./routes/v1'));
// 404处理
app.use('/api/*', (req, res) => {
res.status(404).json({
error: 'API endpoint not found',
path: req.path,
method: req.method
});
});
// 错误处理
app.use((error, req, res, next) => {
// 记录错误日志
console.error('API Error:', {
error: error.message,
stack: error.stack,
url: req.url,
method: req.method,
ip: req.ip,
userAgent: req.get('User-Agent')
});
// 不暴露内部错误信息
if (process.env.NODE_ENV === 'production') {
res.status(500).json({
error: 'Internal server error',
message: 'Something went wrong'
});
} else {
res.status(500).json({
error: error.message,
stack: error.stack
});
}
});
};
6.3 文件上传安全
// 文件上传安全配置
const multer = require('multer');
const path = require('path');
const crypto = require('crypto');
const sharp = require('sharp');
class SecureFileUpload {
constructor() {
this.allowedMimeTypes = {
image: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
document: ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
excel: ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
};
this.maxFileSizes = {
image: 5 * 1024 * 1024, // 5MB
document: 10 * 1024 * 1024, // 10MB
excel: 20 * 1024 * 1024 // 20MB
};
this.uploadDir = './uploads';
this.quarantineDir = './quarantine';
}
// 文件类型检测
detectFileType(buffer) {
// 检查文件头魔数
const signatures = {
'image/jpeg': [0xFF, 0xD8, 0xFF],
'image/png': [0x89, 0x50, 0x4E, 0x47],
'image/gif': [0x47, 0x49, 0x46],
'application/pdf': [0x25, 0x50, 0x44, 0x46]
};
for (const [mimeType, signature] of Object.entries(signatures)) {
if (this.checkSignature(buffer, signature)) {
return mimeType;
}
}
return null;
}
// 检查文件签名
checkSignature(buffer, signature) {
if (buffer.length < signature.length) return false;
for (let i = 0; i < signature.length; i++) {
if (buffer[i] !== signature[i]) return false;
}
return true;
}
// 文件名安全化
sanitizeFilename(filename) {
// 移除危险字符
const sanitized = filename.replace(/[^a-zA-Z0-9.-]/g, '_');
// 生成唯一文件名
const ext = path.extname(sanitized);
const name = path.basename(sanitized, ext);
const hash = crypto.randomBytes(8).toString('hex');
return `${name}_${hash}${ext}`;
}
// 病毒扫描(集成ClamAV)
async scanForVirus(filePath) {
return new Promise((resolve, reject) => {
const { exec } = require('child_process');
exec(`clamscan --no-summary ${filePath}`, (error, stdout, stderr) => {
if (error) {
if (error.code === 1) {
// 发现病毒
resolve({ infected: true, virus: stdout.trim() });
} else {
// 扫描错误
reject(new Error('Virus scan failed'));
}
} else {
// 文件安全
resolve({ infected: false });
}
});
});
}
// 图片安全处理
async processImage(inputPath, outputPath) {
try {
// 使用sharp重新处理图片,移除EXIF数据
await sharp(inputPath)
.jpeg({ quality: 90, progressive: true })
.png({ compressionLevel: 9 })
.removeAlpha()
.toFile(outputPath);
return true;
} catch (error) {
console.error('Image processing failed:', error);
return false;
}
}
// 创建安全的multer配置
createMulterConfig(fileType) {
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, this.uploadDir);
},
filename: (req, file, cb) => {
const safeFilename = this.sanitizeFilename(file.originalname);
cb(null, safeFilename);
}
});
const fileFilter = (req, file, cb) => {
// 检查MIME类型
if (!this.allowedMimeTypes[fileType].includes(file.mimetype)) {
return cb(new Error(`不支持的文件类型: ${file.mimetype}`));
}
cb(null, true);
};
return multer({
storage: storage,
limits: {
fileSize: this.maxFileSizes[fileType],
files: 5 // 最多5个文件
},
fileFilter: fileFilter
});
}
// 文件上传后处理
async postProcessFile(file) {
const filePath = file.path;
try {
// 1. 检查文件头
const buffer = require('fs').readFileSync(filePath);
const detectedType = this.detectFileType(buffer);
if (!detectedType || detectedType !== file.mimetype) {
throw new Error('文件类型不匹配');
}
// 2. 病毒扫描
const scanResult = await this.scanForVirus(filePath);
if (scanResult.infected) {
// 移动到隔离区
const quarantinePath = path.join(this.quarantineDir, file.filename);
require('fs').renameSync(filePath, quarantinePath);
throw new Error(`检测到病毒: ${scanResult.virus}`);
}
// 3. 图片特殊处理
if (file.mimetype.startsWith('image/')) {
const processedPath = filePath + '.processed';
const success = await this.processImage(filePath, processedPath);
if (success) {
require('fs').renameSync(processedPath, filePath);
} else {
throw new Error('图片处理失败');
}
}
return {
success: true,
file: {
filename: file.filename,
originalname: file.originalname,
mimetype: file.mimetype,
size: file.size,
path: filePath
}
};
} catch (error) {
// 删除有问题的文件
if (require('fs').existsSync(filePath)) {
require('fs').unlinkSync(filePath);
}
throw error;
}
}
}
// 使用示例
const secureUpload = new SecureFileUpload();
// 图片上传路由
app.post('/api/upload/image',
secureUpload.createMulterConfig('image').single('image'),
async (req, res) => {
try {
if (!req.file) {
return res.status(400).json({ error: '没有上传文件' });
}
const result = await secureUpload.postProcessFile(req.file);
res.json(result);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
);
7. 安全监控与审计
7.1 安全日志记录
// 安全审计日志
class SecurityAuditLogger {
constructor() {
this.winston = require('winston');
this.logger = this.winston.createLogger({
level: 'info',
format: this.winston.format.combine(
this.winston.format.timestamp(),
this.winston.format.json()
),
transports: [
new this.winston.transports.File({
filename: '/var/log/security/security-audit.log',
maxsize: 100 * 1024 * 1024, // 100MB
maxFiles: 10
}),
new this.winston.transports.Console({
format: this.winston.format.simple()
})
]
});
}
// 记录认证事件
logAuthEvent(event, userId, ip, userAgent, success, details = {}) {
this.logger.info('AUTH_EVENT', {
event: event,
userId: userId,
ip: ip,
userAgent: userAgent,
success: success,
timestamp: new Date().toISOString(),
details: details
});
}
// 记录权限事件
logPermissionEvent(userId, resource, action, granted, ip) {
this.logger.info('PERMISSION_EVENT', {
userId: userId,
resource: resource,
action: action,
granted: granted,
ip: ip,
timestamp: new Date().toISOString()
});
}
// 记录数据访问事件
logDataAccess(userId, dataType, recordId, action, ip) {
this.logger.info('DATA_ACCESS', {
userId: userId,
dataType: dataType,
recordId: recordId,
action: action,
ip: ip,
timestamp: new Date().toISOString()
});
}
// 记录安全事件
logSecurityEvent(eventType, severity, description, ip, details = {}) {
this.logger.warn('SECURITY_EVENT', {
eventType: eventType,
severity: severity,
description: description,
ip: ip,
timestamp: new Date().toISOString(),
details: details
});
}
// 记录系统事件
logSystemEvent(eventType, description, details = {}) {
this.logger.info('SYSTEM_EVENT', {
eventType: eventType,
description: description,
timestamp: new Date().toISOString(),
details: details
});
}
}
// 审计中间件
const auditMiddleware = (auditLogger) => {
return (req, res, next) => {
const startTime = Date.now();
// 记录请求开始
const requestId = require('crypto').randomUUID();
req.requestId = requestId;
// 重写res.json以记录响应
const originalJson = res.json;
res.json = function(data) {
const endTime = Date.now();
const duration = endTime - startTime;
// 记录API访问
auditLogger.logger.info('API_ACCESS', {
requestId: requestId,
method: req.method,
url: req.url,
ip: req.ip,
userAgent: req.get('User-Agent'),
userId: req.user?.id,
statusCode: res.statusCode,
duration: duration,
timestamp: new Date().toISOString()
});
// 记录敏感操作
if (['POST', 'PUT', 'DELETE'].includes(req.method)) {
auditLogger.logDataAccess(
req.user?.id,
req.url.split('/')[2], // 提取资源类型
req.params.id,
req.method,
req.ip
);
}
return originalJson.call(this, data);
};
next();
};
};
7.2 实时安全监控
// 实时安全监控系统
class SecurityMonitor {
constructor() {
this.redis = require('redis').createClient();
this.alerts = [];
this.thresholds = {
failedLogins: { count: 5, window: 300 }, // 5分钟内5次失败
apiCalls: { count: 1000, window: 60 }, // 1分钟内1000次调用
dataAccess: { count: 100, window: 300 } // 5分钟内100次数据访问
};
}
// 检查失败登录
async checkFailedLogins(ip) {
const key = `failed_logins:${ip}`;
const count = await this.redis.incr(key);
if (count === 1) {
await this.redis.expire(key, this.thresholds.failedLogins.window);
}
if (count >= this.thresholds.failedLogins.count) {
this.triggerAlert('FAILED_LOGIN_THRESHOLD', {
ip: ip,
count: count,
threshold: this.thresholds.failedLogins.count
});
}
}
// 检查API调用频率
async checkApiCalls(userId, endpoint) {
const key = `api_calls:${userId}:${endpoint}`;
const count = await this.redis.incr(key);
if (count === 1) {
await this.redis.expire(key, this.thresholds.apiCalls.window);
}
if (count >= this.thresholds.apiCalls.count) {
this.triggerAlert('API_RATE_LIMIT', {
userId: userId,
endpoint: endpoint,
count: count,
threshold: this.thresholds.apiCalls.count
});
}
}
// 触发安全告警
triggerAlert(alertType, data) {
const alert = {
id: require('crypto').randomUUID(),
type: alertType,
timestamp: new Date().toISOString(),
data: data,
severity: this.getAlertSeverity(alertType)
};
this.alerts.push(alert);
this.sendAlert(alert);
}
// 获取告警严重程度
getAlertSeverity(alertType) {
const severityMap = {
'FAILED_LOGIN_THRESHOLD': 'HIGH',
'API_RATE_LIMIT': 'MEDIUM',
'SUSPICIOUS_ACTIVITY': 'HIGH',
'DATA_BREACH_ATTEMPT': 'CRITICAL'
};
return severityMap[alertType] || 'LOW';
}
// 发送告警
async sendAlert(alert) {
// 发送到监控系统
console.log('🚨 安全告警:', alert);
// 发送邮件通知
if (alert.severity === 'CRITICAL' || alert.severity === 'HIGH') {
await this.sendEmailAlert(alert);
}
// 发送钉钉通知
await this.sendDingTalkAlert(alert);
// 记录到数据库
await this.saveAlertToDatabase(alert);
}
}
7.3 安全事件响应
#!/bin/bash
# security-incident-response.sh - 安全事件响应脚本
INCIDENT_LOG="/var/log/security/incidents.log"
BACKUP_DIR="/secure-backup/incident-$(date +%Y%m%d_%H%M%S)"
# 事件响应等级
declare -A RESPONSE_LEVELS=(
["LOW"]="记录日志"
["MEDIUM"]="通知管理员"
["HIGH"]="立即响应"
["CRITICAL"]="紧急响应"
)
# 记录安全事件
log_incident() {
local severity=$1
local event_type=$2
local description=$3
local affected_systems=$4
echo "$(date '+%Y-%m-%d %H:%M:%S') [$severity] $event_type: $description (影响系统: $affected_systems)" >> $INCIDENT_LOG
}
# 隔离受影响系统
isolate_system() {
local system_ip=$1
echo "隔离系统: $system_ip"
# 阻止该IP的所有连接
iptables -I INPUT -s $system_ip -j DROP
iptables -I OUTPUT -d $system_ip -j DROP
# 记录隔离操作
log_incident "HIGH" "SYSTEM_ISOLATION" "系统已被隔离" "$system_ip"
}
# 紧急备份
emergency_backup() {
echo "执行紧急备份..."
mkdir -p $BACKUP_DIR
# 备份关键数据
docker exec mysql-master mysqldump -u root -p${MYSQL_ROOT_PASSWORD} --all-databases > $BACKUP_DIR/emergency_db_backup.sql
# 备份配置文件
cp -r ./config $BACKUP_DIR/
cp -r ./nginx $BACKUP_DIR/
# 备份日志文件
cp -r /var/log $BACKUP_DIR/
echo "紧急备份完成: $BACKUP_DIR"
}
# 收集取证信息
collect_forensics() {
local incident_id=$1
local forensics_dir="/var/log/security/forensics/$incident_id"
mkdir -p $forensics_dir
echo "收集取证信息..."
# 系统信息
uname -a > $forensics_dir/system_info.txt
ps aux > $forensics_dir/processes.txt
netstat -tuln > $forensics_dir/network_connections.txt
# 用户信息
who > $forensics_dir/logged_users.txt
last -n 50 > $forensics_dir/login_history.txt
# 文件系统信息
find /tmp -type f -mtime -1 > $forensics_dir/recent_tmp_files.txt
find /var/log -name "*.log" -mtime -1 -exec ls -la {} \; > $forensics_dir/recent_logs.txt
# 网络流量
tcpdump -i any -w $forensics_dir/network_traffic.pcap -c 1000 &
echo "取证信息收集完成: $forensics_dir"
}
# 事件响应主函数
incident_response() {
local severity=$1
local event_type=$2
local description=$3
local affected_systems=$4
local incident_id="INC-$(date +%Y%m%d%H%M%S)"
echo "=== 安全事件响应开始 ==="
echo "事件ID: $incident_id"
echo "严重程度: $severity"
echo "事件类型: $event_type"
echo "描述: $description"
echo "影响系统: $affected_systems"
# 记录事件
log_incident $severity $event_type "$description" "$affected_systems"
# 根据严重程度执行响应
case $severity in
"CRITICAL")
echo "执行紧急响应..."
emergency_backup
collect_forensics $incident_id
isolate_system $affected_systems
send_critical_alert "$incident_id" "$description"
;;
"HIGH")
echo "执行高级响应..."
collect_forensics $incident_id
send_high_alert "$incident_id" "$description"
;;
"MEDIUM")
echo "执行中级响应..."
send_medium_alert "$incident_id" "$description"
;;
"LOW")
echo "记录低级事件..."
;;
esac
echo "=== 安全事件响应完成 ==="
}
# 发送告警通知
send_critical_alert() {
local incident_id=$1
local description=$2
# 发送邮件
echo "🚨 紧急安全事件 - $incident_id: $description" | mail -s "紧急安全告警" security@xlxumu.com
# 发送短信(集成短信服务)
curl -X POST "https://sms-api.example.com/send" \
-H "Authorization: Bearer $SMS_TOKEN" \
-d "phone=13800138000&message=紧急安全事件: $incident_id"
# 发送钉钉通知
curl -X POST "https://oapi.dingtalk.com/robot/send?access_token=$DINGTALK_TOKEN" \
-H 'Content-Type: application/json' \
-d "{\"msgtype\": \"text\",\"text\": {\"content\": \"🚨 紧急安全事件\\n事件ID: $incident_id\\n描述: $description\\n请立即处理!\"}}"
}
# 使用示例
case $1 in
"test")
incident_response "HIGH" "INTRUSION_ATTEMPT" "检测到入侵尝试" "192.168.1.100"
;;
"isolate")
isolate_system $2
;;
"backup")
emergency_backup
;;
"forensics")
collect_forensics $2
;;
*)
echo "使用方法: $0 {test|isolate <ip>|backup|forensics <incident_id>}"
;;
esac
8. 安全培训与意识
8.1 安全培训计划
| 培训对象 | 培训内容 | 频率 | 时长 |
|---|---|---|---|
| 开发人员 | 安全编码、OWASP Top 10、代码审计 | 季度 | 4小时 |
| 运维人员 | 系统安全、网络安全、应急响应 | 季度 | 6小时 |
| 管理人员 | 安全管理、合规要求、风险评估 | 半年 | 2小时 |
| 全体员工 | 安全意识、钓鱼邮件识别、密码安全 | 月度 | 1小时 |
8.2 安全检查清单
8.2.1 日常安全检查
- 检查系统补丁更新状态
- 审查用户权限分配
- 检查防火墙规则
- 监控异常登录活动
- 验证备份完整性
- 检查SSL证书有效期
- 审查安全日志
- 测试入侵检测系统
8.2.2 月度安全评估
- 漏洞扫描
- 渗透测试
- 代码安全审计
- 权限审计
- 安全配置检查
- 应急预案演练
- 安全培训效果评估
- 合规性检查
9. 应急预案
9.1 数据泄露应急预案
flowchart TD
A[发现数据泄露] --> B[立即隔离]
B --> C[评估影响范围]
C --> D[通知相关人员]
D --> E[收集证据]
E --> F[修复漏洞]
F --> G[恢复服务]
G --> H[事后分析]
H --> I[改进措施]
9.2 系统入侵应急预案
-
发现阶段
- 监控系统告警
- 异常行为检测
- 用户举报
-
响应阶段
- 立即隔离受影响系统
- 保护现场证据
- 通知安全团队
-
恢复阶段
- 清除恶意代码
- 修复安全漏洞
- 恢复正常服务
-
总结阶段
- 事件分析报告
- 改进安全措施
- 更新应急预案
10. 总结
10.1 安全管理要点
- 全面防护:从网络、系统、应用、数据多个层面构建安全防护体系
- 持续监控:建立7×24小时安全监控和告警机制
- 快速响应:制定完善的安全事件响应流程和应急预案
- 定期评估:定期进行安全评估和渗透测试
- 人员培训:提高全员安全意识和技能水平
10.2 安全发展规划
-
短期目标(1-3个月)
- 完善基础安全防护
- 建立安全监控体系
- 制定安全管理制度
-
中期目标(3-6个月)
- 实施零信任架构
- 建立安全运营中心
- 完善应急响应能力
-
长期目标(6-12个月)
- 通过等保2.0认证
- 建立安全文化
- 实现自动化安全运营
10.3 联系方式
- 安全团队邮箱:security@xlxumu.com
- 应急响应热线:400-XXX-XXXX
- 安全事件报告:incident@xlxumu.com
本文档将根据安全威胁变化和业务发展需要持续更新