Files
novalon-website/scripts/security-hardening.sh
T
张翔 3ce31d3178
ci/woodpecker/push/woodpecker Pipeline failed
feat: 优化CI/CD流程 - 自定义工具镜像、修复TLS问题、添加镜像清理脚本
- 创建轻量级工具镜像(novalon/tools:1.0.0)避免重复安装工具
- 修复Docker TLS handshake timeout问题
- 更新CI配置使用registry.f.novalon.cn/novalon/tools:1.0.0
- 添加自动清理脚本用于磁盘和镜像管理
2026-03-31 17:27:43 +08:00

524 lines
14 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# 生产环境安全加固自动化脚本
# 作者:张翔
# 日期:2026-03-31
echo "🚀 开始执行生产环境安全加固..."
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# 配置参数
PROD_DIR="/home/novalon/docker-app"
NGINX_DIR="$PROD_DIR/novalon-nginx"
APP_DIR="$PROD_DIR/novalon-website"
echo "📁 检查生产环境目录..."
if [ ! -d "$PROD_DIR" ]; then
echo "❌ 生产环境目录不存在:$PROD_DIR"
exit 1
fi
echo "✅ 生产环境目录存在"
# 1. 创建安全的Nginx配置
echo "⚙️ 创建安全的Nginx配置..."
mkdir -p "$NGINX_DIR"
cat > "$NGINX_DIR/nginx.conf" << 'NGINX_EOF'
# ============================================================
# 安全的Nginx配置 - Next.js生产环境
# 作者:张翔
# 日期:2026-03-31
# ============================================================
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
# ============================================================
# 基础配置
# ============================================================
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'rt=$request_time uct="$upstream_connect_time" '
'uht="$upstream_header_time" urt="$upstream_response_time"';
access_log /var/log/nginx/access.log main;
# 性能优化
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# ============================================================
# 安全配置
# ============================================================
# 隐藏Nginx版本号
server_tokens off;
# 安全响应头
add_header X-Frame-Options "SAMEORIGIN" 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' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:; frame-ancestors 'self'; base-uri 'self'; form-action 'self';" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
# 限制请求大小
client_max_body_size 10m;
client_body_timeout 10s;
client_header_timeout 10s;
send_timeout 10s;
# ============================================================
# 防止DDoS攻击
# ============================================================
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
limit_conn conn_limit 10;
# ============================================================
# Gzip压缩
# ============================================================
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1000;
gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss application/atom+xml image/svg+xml;
# ============================================================
# 上游服务器配置
# ============================================================
upstream nextjs_backend {
server 127.0.0.1:3000;
keepalive 64;
}
# ============================================================
# HTTP到HTTPS重定向
# ============================================================
server {
listen 80;
listen [::]:80;
server_name your-domain.com www.your-domain.com;
# 重定向到HTTPS
return 301 https://$server_name$request_uri;
}
# ============================================================
# HTTPS服务器
# ============================================================
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name your-domain.com www.your-domain.com;
# SSL证书配置
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
# SSL配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
# ========================================================
# 位置块配置
# ========================================================
# Next.js静态文件
location /_next/ {
proxy_pass http://nextjs_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
add_header X-Cache-Status $upstream_cache_status;
proxy_cache off;
}
# API路由
location /api/ {
limit_req zone=req_limit burst=20 nodelay;
proxy_pass http://nextjs_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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;
proxy_read_timeout 86400;
}
# 管理后台(可选IP限制)
location /admin {
limit_req zone=req_limit burst=10 nodelay;
# 如果需要IP白名单,取消下面的注释
# allow 192.168.1.0/24;
# allow 10.0.0.0/8;
# deny all;
proxy_pass http://nextjs_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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;
}
# 根路径
location / {
limit_req zone=req_limit burst=20 nodelay;
proxy_pass http://nextjs_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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;
}
# 健康检查
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# 错误页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
internal;
}
}
}
NGINX_EOF
echo "✅ 安全的Nginx配置已创建"
# 2. 创建Docker Compose配置
echo "🐳 创建Docker Compose配置..."
cat > "$NGINX_DIR/docker-compose.yml" << 'COMPOSE_EOF'
version: "3.8"
services:
nginx:
image: nginx:alpine
container_name: novalon-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
- ./logs:/var/log/nginx
networks:
- novalon-network
# 限制容器资源
deploy:
resources:
limits:
cpus: '1'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
networks:
novalon-network:
driver: bridge
external: true
COMPOSE_EOF
echo "✅ Docker Compose配置已创建"
# 3. 创建SSL目录
echo "🔒 创建SSL目录..."
mkdir -p "$NGINX_DIR/ssl"
echo "✅ SSL目录已创建"
# 4. 创建健康检查脚本
echo "🩺 创建健康检查脚本..."
mkdir -p "$PROD_DIR/scripts"
cat > "$PROD_DIR/scripts/health-check.sh" << 'HEALTH_EOF'
#!/bin/bash
# 健康检查脚本
echo "[$(date)] 开始健康检查..."
# 检查Nginx容器
if docker ps --filter "name=novalon-nginx" --format "{{.Names}}" | grep -q "novalon-nginx"; then
echo "✅ Nginx容器运行正常"
else
echo "❌ Nginx容器未运行"
exit 1
fi
# 检查应用容器
if docker ps --filter "name=novalon-website" --format "{{.Names}}" | grep -q "novalon-website"; then
echo "✅ 应用容器运行正常"
else
echo "❌ 应用容器未运行"
exit 1
fi
# 检查80端口
if curl -s -o /dev/null -w "%{http_code}" http://localhost:80 | grep -q "301"; then
echo "✅ 80端口HTTP重定向正常"
else
echo "❌ 80端口配置异常"
exit 1
fi
# 检查443端口
if curl -s -o /dev/null -w "%{http_code}" -k https://localhost:443 | grep -q "200"; then
echo "✅ 443端口HTTPS正常"
else
echo "⚠️ 443端口HTTPS可能异常(检查SSL证书)"
fi
# 检查健康检查端点
if curl -s http://localhost:80/health | grep -q "healthy"; then
echo "✅ 健康检查端点正常"
else
echo "❌ 健康检查端点异常"
exit 1
fi
echo "✅ 所有健康检查通过"
HEALTH_EOF
chmod +x "$PROD_DIR/scripts/health-check.sh"
echo "✅ 健康检查脚本已创建"
# 5. 创建安全加固说明文档
echo "📄 创建安全加固说明文档..."
cat > "$PROD_DIR/SECURITY_GUIDE.md" << 'SECURITY_EOF'
# 生产环境安全加固指南
## 作者:张翔
## 日期:2026-03-31
## 概述
本文档描述了生产环境的安全加固措施,包括Nginx配置、SSL设置、安全头配置等。
## 安全配置清单
### ✅ 已完成配置
1. **Nginx反向代理**
- 隐藏后端服务信息
- 隐藏Nginx版本号
- 配置安全响应头
2. **HTTPS配置**
- 启用HTTP/2
- 配置强加密套件
- 启用OCSP Stapling
3. **安全响应头**
- X-Frame-Options: SAMEORIGIN
- X-Content-Type-Options: nosniff
- X-XSS-Protection: 1; mode=block
- Content-Security-Policy: 严格策略
- Strict-Transport-Security: HSTS
4. **DDoS防护**
- 请求频率限制
- 连接数限制
- 请求体大小限制
5. **资源限制**
- 容器CPU限制
- 容器内存限制
### 🔧 待完成配置
1. **SSL证书**
- 获取SSL证书
- 配置证书路径
- 启用HTTPS
2. **IP白名单**
- 配置管理后台IP白名单
- 限制敏感接口访问
3. **WAF配置**
- 集成ModSecurity
- 配置规则集
4. **监控告警**
- 配置日志分析
- 设置告警规则
## SSL证书配置
### 使用Let's Encrypt
```bash
# 安装certbot
apt-get update && apt-get install certbot python3-certbot-nginx
# 获取证书
certbot --nginx -d your-domain.com -d www.your-domain.com
# 自动续期
certbot renew --dry-run
```
### 手动配置证书
将证书文件放置到:
- `/home/novalon/docker-app/novalon-nginx/ssl/fullchain.pem`
- `/home/novalon/docker-app/novalon-nginx/ssl/privkey.pem`
然后重启Nginx
```bash
docker-compose -f /home/novalon/docker-app/novalon-nginx/docker-compose.yml restart
```
## 安全检查命令
```bash
# 检查Nginx配置
docker exec novalon-nginx nginx -t
# 重新加载Nginx配置
docker exec novalon-nginx nginx -s reload
# 查看访问日志
docker logs -f novalon-nginx
# 检查SSL配置
openssl s_client -connect your-domain.com:443 -servername your-domain.com
# 测试安全头
curl -I https://your-domain.com
```
## 应急响应
### 如何应对DDoS攻击
1. **临时限制IP**
```bash
# 在nginx.conf中添加
deny 192.168.1.1;
```
2. **启用CDN**
- 使用Cloudflare等CDN服务
- 隐藏源站IP
3. **联系云服务商**
- 启用DDoS防护
- 增加带宽限制
### 如何应对SQL注入
1. **启用WAF规则**
2. **检查应用代码**
3. **更新依赖包**
4. **启用数据库审计**
## 定期安全审计
### 每日
- 检查访问日志
- 监控异常流量
- 检查健康状态
### 每周
- 审计SSL证书有效期
- 检查安全头配置
- 更新依赖包
### 每月
- 全面安全扫描
- 渗透测试
- 安全策略审查
## 联系方式
如有安全问题,请联系:
- 邮箱:security@your-domain.com
- 电话:400-xxx-xxxx
SECURITY_EOF
echo "✅ 安全加固说明文档已创建"
# 6. 显示加固结果
echo ""
echo "=========================================="
echo "🛡️ 安全加固完成!"
echo "=========================================="
echo ""
echo "✅ 已完成的配置:"
echo " 1. 安全的Nginx配置"
echo " 2. Docker Compose配置"
echo " 3. SSL目录创建"
echo " 4. 健康检查脚本"
echo " 5. 安全加固文档"
echo ""
echo "📋 下一步操作:"
echo " 1. 配置SSL证书"
echo " 2. 重启Nginx服务"
echo " 3. 验证安全配置"
echo " 4. 启用监控告警"
echo ""
echo "💡 建议操作:"
echo " cd $PROD_DIR/novalon-nginx"
echo " docker-compose up -d"
echo " curl -I http://localhost # 检查HTTP重定向"
echo " curl -k -I https://localhost # 检查HTTPS"
echo ""