生产服务器安全强化:综合清单
识别数据泄露的平均时间为 204 天。 生产服务器强化可减少攻击面,从而使泄露更难发起且检测速度更快。本指南涵盖了每个生产服务器应实施的具体安全措施,从 SSH 配置到 Web 应用程序防火墙。
要点
- 仅 SSH 密钥身份验证和非标准端口可阻止 99% 的自动暴力攻击
- 正确配置的防火墙将攻击面从数千个入口点减少到不到十个
- Web 应用程序防火墙在网络层阻止 SQL 注入、XSS 和其他 OWASP Top 10 攻击
- 自动修补可确保漏洞在披露后几小时内得到修复,而不是几周
SSH 强化
配置
# /etc/ssh/sshd_config
# Disable password authentication
PasswordAuthentication no
ChallengeResponseAuthentication no
# Disable root login
PermitRootLogin no
# Use SSH keys only
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
# Limit login attempts
MaxAuthTries 3
MaxSessions 5
# Set idle timeout (5 minutes)
ClientAliveInterval 300
ClientAliveCountMax 0
# Restrict SSH to specific users
AllowUsers deploy ubuntu
# Disable X11 forwarding
X11Forwarding no
# Use only strong algorithms
KexAlgorithms [email protected],diffie-hellman-group-exchange-sha256
Ciphers [email protected],[email protected],[email protected]
MACs [email protected],[email protected]
失败2Ban
# /etc/fail2ban/jail.local
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 5
bantime = 3600
防火墙配置
UFW(Ubuntu)
# Reset and set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH (consider changing port)
sudo ufw allow 22/tcp
# Allow HTTP/HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Allow specific IPs for management
sudo ufw allow from 203.0.113.10 to any port 9090 comment "Grafana"
sudo ufw allow from 203.0.113.10 to any port 9093 comment "Alertmanager"
# Deny everything else (implicit with default deny)
sudo ufw enable
sudo ufw status verbose
AWS 安全组
# Terraform security group
resource "aws_security_group" "app" {
name_prefix = "app-"
vpc_id = aws_vpc.main.id
# Allow HTTPS from anywhere
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "HTTPS from internet"
}
# Allow SSH from office IP only
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["203.0.113.0/24"]
description = "SSH from office"
}
# Allow all outbound
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# Database security group - no public access
resource "aws_security_group" "db" {
name_prefix = "db-"
vpc_id = aws_vpc.main.id
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.app.id]
description = "PostgreSQL from app servers only"
}
}
Nginx 安全标头
# Security headers for all responses
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https://api.example.com;" always;
# Hide server version
server_tokens off;
# Limit request size
client_max_body_size 10m;
# Rate limiting
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
server {
location / {
limit_req zone=general burst=20 nodelay;
}
location /api/ {
limit_req zone=api burst=50 nodelay;
}
location /auth/ {
limit_req zone=login burst=3 nodelay;
}
}
SSL/TLS 配置
# Modern TLS configuration
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;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
# Session configuration
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
# Certificate (Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
自动证书续订
# /etc/cron.d/certbot
0 0,12 * * * root certbot renew --quiet --post-hook "nginx -s reload"
容器安全
如果在生产环境中运行 Docker,请应用以下额外的强化措施:
Docker 守护进程安全
{
"userns-remap": "default",
"no-new-privileges": true,
"live-restore": true,
"userland-proxy": false,
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
容器运行时限制
# docker-compose.yml security settings
services:
api:
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
主要原则:
- 删除所有功能并仅添加所需的功能
- 只读文件系统防止攻击者修改容器内容
- 没有新权限可防止容器内的权限升级
- Dockerfile 中的 非 root 用户(请参阅我们的 Docker 部署指南)
图像安全
- 使用官方的最小基础镜像(Alpine 变体)
- 固定图像版本(切勿在生产中使用
:latest) - 使用 Trivy 或 Grype 扫描图像中的漏洞
- 使用 Docker Content Trust 签署图像
- 使用具有访问控制的私有注册表
数据库安全
PostgreSQL 强化
# postgresql.conf security settings
listen_addresses = 'localhost' # Only listen on localhost
ssl = on # Require SSL for connections
ssl_cert_file = '/path/to/server.crt'
ssl_key_file = '/path/to/server.key'
password_encryption = scram-sha-256 # Modern password hashing
log_connections = on # Log all connections
log_disconnections = on # Log disconnections
log_statement = 'ddl' # Log DDL statements
# pg_hba.conf - restrict connections
# TYPE DATABASE USER ADDRESS METHOD
local all all scram-sha-256
host all all 10.0.0.0/8 scram-sha-256
hostssl all all 0.0.0.0/0 scram-sha-256
- 切勿将 PostgreSQL 暴露于公共互联网
- 使用具有最低所需权限的专用数据库用户
- 启用连接加密 (SSL)
- 设置强密码策略
- 定期备份验证(请参阅我们的灾难恢复指南)
入侵检测
OSSEC 配置
<!-- /var/ossec/etc/ossec.conf -->
<ossec_config>
<syscheck>
<!-- Monitor critical files for changes -->
<directories check_all="yes">/etc,/usr/bin,/usr/sbin</directories>
<directories check_all="yes">/opt/app/dist</directories>
<!-- Ignore frequently changing files -->
<ignore>/etc/mtab</ignore>
<ignore>/etc/resolv.conf</ignore>
<!-- Run integrity check every 6 hours -->
<frequency>21600</frequency>
</syscheck>
<rootcheck>
<rootkit_files>/var/ossec/etc/shared/rootkit_files.txt</rootkit_files>
<rootkit_trojans>/var/ossec/etc/shared/rootkit_trojans.txt</rootkit_trojans>
</rootcheck>
</ossec_config>
AWS GuardDuty
resource "aws_guardduty_detector" "main" {
enable = true
datasources {
s3_logs {
enable = true
}
kubernetes {
audit_logs {
enable = true
}
}
}
}
自动安全补丁
# Ubuntu: Enable unattended security updates
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
# /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";
Unattended-Upgrade::Mail "[email protected]";
安全强化清单
服务器级别
- 仅 SSH 密钥身份验证,禁用 root 登录
- 配置了默认拒绝策略的防火墙
- Fail2Ban 在 SSH 和 Web 服务器上处于活动状态
- 启用自动安全更新
- 禁用非必要服务
- 文件完整性监控(OSSEC 或同等功能)
- 启用审核日志记录 (auditd)
应用级别
- 所有端点上的 TLS 1.2+,启用 HSTS
- 配置安全标头(CSP、X-Frame-Options 等)
- 对所有公共端点进行速率限制
- 输入验证和参数化查询(无
sql.raw()) - HttpOnly,用于身份验证的安全 cookie
- CORS 仅限于已知来源
- 错误响应不会泄漏堆栈跟踪
网络级别
- 数据库不可公开访问
- 私有子网上的内部服务
- AWS 服务的 VPC 终端节点(无公共互联网)
- 面向公众的端点上的 WAF
- DDoS 防护(Cloudflare、AWS Shield)
监控
- 已配置安全事件警报
- 日志保留至少 90 天
- 监控失败的身份验证尝试
- 检测到异常流量模式
常见问题
我们应该多久进行一次安全审核?
每季度自动扫描(漏洞扫描、依赖性审计)和年度手动渗透测试。高风险应用程序(支付处理、医疗数据)应每 6 个月进行一次外部渗透测试。每个生产部署都应包括 CI/CD 管道中的自动安全扫描 --- 请参阅我们的 CI/CD 最佳实践指南。
如果我们已经有速率限制,还需要 WAF 吗?
是的。速率限制可以防止滥用,但不会检查请求内容。 WAF 通过分析请求负载来阻止 SQL 注入、XSS 和其他应用程序层攻击。将速率限制视为防洪,将 WAF 视为内容检查——两者都需要。
我们如何保护 Odoo 生产服务器的安全?
除了上面的一般强化之外:在生产中禁用数据库管理器(list_db = False),设置强大的admin_passwd,使用dbfilter来限制数据库访问,在Nginx后面运行Odoo(永远不要直接暴露Odoo),并保持Odoo和所有模块更新。 ECOSIRE 提供 Odoo 安全强化 作为我们托管服务的一部分。
最有影响力的安全措施是什么?
在所有管理帐户上启用 MFA(多重身份验证)。这种单一控制可防止 99% 的基于凭据的攻击。在任何其他强化措施之前,在 SSH(通过 PAM)、AWS 控制台、数据库管理工具和应用程序管理面板上实施 MFA。
接下来会发生什么
安全强化是一项持续的实践。将其与监控和警报 相结合以进行检测,将其与灾难恢复 相结合以实现弹性,并与CI/CD 安全扫描 相结合以进行预防。
联系 ECOSIRE 获取安全强化咨询,或浏览我们的 DevOps 指南 获取完整的基础设施路线图。
由 ECOSIRE 发布——帮助企业保护生产基础设施。
作者
ECOSIRE Research and Development Team
在 ECOSIRE 构建企业级数字产品。分享关于 Odoo 集成、电商自动化和 AI 驱动商业解决方案的洞见。