在当前的互联网环境中,服务器几乎每时每刻都在面临各种安全威胁。你是否遇到过这样的场景:凌晨突然收到告警,提示服务器在几分钟内遭受了上千次SSH登录尝试;或是发现Web应用被入侵,攻击者利用漏洞获取了root权限并植入了挖矿程序?这类安全事件不仅会中断业务,更可能导致严重的数据泄露和经济损失。
安全加固绝非一劳永逸,而是一项需要持续进行的工作。许多运维工程师在服务器上线时,往往只做了修改SSH端口、设置几条基础防火墙规则这样简单的配置,就认为安全工作已经到位。实际上,这还远远不够。攻击手段在不断演进,从简单的密码爆破到利用零日漏洞,我们必须构建更稳固的防御体系。
本文将从实战角度出发,详细讲解Linux服务器安全加固的三大核心:SSH安全配置、防火墙规则管理以及用户权限控制。这些措施经过大量生产环境验证,能够有效抵御绝大多数常见攻击,并且不会对正常的业务运维造成负担。
一、概述
1.1 背景介绍
安全加固是一个持续对抗的过程。攻击者的手段从简单的密码爆破,到利用0day漏洞,再到社会工程学,可谓防不胜防。
1.2 技术特点
- 纵深防御策略:不依赖单一防护手段,而是构建多层防御体系。即使SSH层面被突破,防火墙和严格的用户权限仍能提供保护,三者配合形成完整的安全防护网。
- 实用性与安全性平衡:本文介绍的方法都经过实践验证。例如,使用密钥认证替代密码登录,既大幅提升了安全性,也为日常运维带来了便利。
- 可审计可追溯:所有的安全配置都会产生详细的日志,便于事后审计和问题排查。通过分析各类日志,可以快速发现异常行为,这对于满足合规要求和应急响应都至关重要。
1.3 适用场景
- 场景一:电商平台Web服务器防护:这类服务器存储着大量用户数据,是攻击重点。加固重点包括:禁用SSH密码登录、配置防火墙仅开放必要端口、使用fail2ban自动封禁IP、避免使用root运行Web服务。
- 场景二:API服务器访问控制:API服务器需要对外提供服务,但又不能完全开放。加固重点在于:使用防火墙白名单限制SSH来源、在应用层(如Nginx)限制调用频率、配置详细的访问日志。
- 场景三:数据库服务器隔离防护:存储核心数据的数据库服务器安全要求最高。通常需完全禁止外网直接访问,SSH只允许跳板机连接,并对数据库用户权限进行严格控制。
1.4 环境要求
| 组件 |
版本要求 |
说明 |
| 操作系统 |
CentOS 7+/Ubuntu 18.04+/Debian 10+ |
需要支持systemd和现代防火墙工具 |
| OpenSSH |
7.4+ |
较新版本提供了更多安全特性 |
| 防火墙 |
iptables/firewalld/ufw |
根据发行版选择合适的工具 |
| fail2ban |
0.10+ |
用于自动封禁暴力破解IP |
| 权限要求 |
root或sudo权限 |
安全配置需要管理员权限 |
二、详细步骤
2.1 SSH安全加固
2.1.1 生成和配置SSH密钥
密钥认证比密码认证安全得多,因为其密钥长度通常为2048位或4096位,暴力破解几乎不可能。
在本地生成SSH密钥:
# 生成RSA密钥对(推荐4096位)
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
# 或者生成更安全的ED25519密钥
ssh-keygen -t ed25519 -C "your_email@example.com"
# 按提示操作:
# 1. 指定密钥保存位置(默认~/.ssh/id_rsa)
# 2. 设置密钥密码(可选,但建议设置)
将公钥上传到服务器:
# 方法一:使用ssh-copy-id(推荐)
ssh-copy-id -i ~/.ssh/id_rsa.pub user@server_ip
# 方法二:手动复制
cat ~/.ssh/id_rsa.pub | ssh user@server_ip "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
# 方法三:直接在服务器上操作
# 登录服务器后执行:
mkdir -p ~/.ssh
chmod 700 ~/.ssh
vim ~/.ssh/authorized_keys # 粘贴公钥内容
chmod 600 ~/.ssh/authorized_keys
验证密钥登录:
# 测试密钥登录
ssh -i ~/.ssh/id_rsa user@server_ip
# 如果能成功登录,说明密钥配置正确
2.1.2 修改SSH配置文件
接下来,我们需要修改SSH服务器的配置,禁用不安全的选项。
# 备份原配置文件
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
# 编辑配置文件
sudo vim /etc/ssh/sshd_config
关键配置项:
# 修改SSH端口(避免自动化扫描)
Port 22022
# 禁止root直接登录
PermitRootLogin no
# 禁用密码认证,只允许密钥登录
PasswordAuthentication no
PubkeyAuthentication yes
# 禁用空密码登录
PermitEmptyPasswords no
# 禁用基于主机的认证
HostbasedAuthentication no
# 限制登录用户(可选)
AllowUsers deploy admin
# 设置登录超时时间
LoginGraceTime 60
# 限制最大认证尝试次数
MaxAuthTries 3
# 禁用X11转发(如果不需要)
X11Forwarding no
# 启用严格模式(检查文件权限)
StrictModes yes
# 设置日志级别
LogLevel VERBOSE
重启SSH服务:
# 先测试配置文件语法
sudo sshd -t
# 如果没有错误,重启SSH服务
sudo systemctl restart sshd
# 重要:重启前保持当前SSH连接,新开一个终端测试
# 确保能正常登录后再关闭旧连接
实战经验:修改SSH端口后,防火墙规则也要相应调整。务必先在防火墙中开放新端口,测试成功后再关闭默认的22端口,以免将自己锁在服务器外。
2.1.3 配置fail2ban防暴力破解
fail2ban能够自动监控系统日志,当发现暴力破解行为时,自动将攻击者的IP加入防火墙黑名单。
安装fail2ban:
# Ubuntu/Debian
sudo apt update
sudo apt install -y fail2ban
# CentOS/RHEL
sudo yum install -y epel-release
sudo yum install -y fail2ban
# 启动服务
sudo systemctl start fail2ban
sudo systemctl enable fail2ban
配置fail2ban:
# 创建本地配置文件
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo vim /etc/fail2ban/jail.local
关键配置:
[DEFAULT]
# 封禁时间(秒),默认10分钟
bantime = 3600
# 查找时间窗口(秒)
findtime = 600
# 在findtime内失败maxretry次就封禁
maxretry = 3
# 忽略的IP(白名单)
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24
[sshd]
enabled = true
port = 22022
logpath = /var/log/auth.log
maxretry = 3
bantime = 7200
验证fail2ban运行状态:
# 查看fail2ban状态
sudo systemctl status fail2ban
# 查看SSH监控状态
sudo fail2ban-client status sshd
# 查看被封禁的IP
sudo fail2ban-client get sshd banned
2.2 防火墙配置
2.2.1 使用iptables配置防火墙
iptables是Linux上功能强大且灵活的防火墙工具。
基础防火墙规则:
# 清空现有规则(谨慎操作)
sudo iptables -F
sudo iptables -X
# 设置默认策略(默认拒绝所有)
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT
# 允许本地回环
sudo iptables -A INPUT -i lo -j ACCEPT
# 允许已建立的连接
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 允许SSH(注意端口号)
sudo iptables -A INPUT -p tcp --dport 22022 -j ACCEPT
# 允许HTTP和HTTPS
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# 允许ping(可选)
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
# 保存规则
sudo iptables-save > /etc/iptables/rules.v4
限制SSH访问来源:
# 只允许特定IP访问SSH
sudo iptables -A INPUT -p tcp -s 192.168.1.100 --dport 22022 -j ACCEPT
sudo iptables -A INPUT -p tcp -s 10.0.0.0/8 --dport 22022 -j ACCEPT
# 拒绝其他IP的SSH访问
sudo iptables -A INPUT -p tcp --dport 22022 -j DROP
防止SYN flood攻击:
# 限制SYN包速率
sudo iptables -A INPUT -p tcp --syn -m limit --limit 1/s --limit-burst 3 -j ACCEPT
sudo iptables -A INPUT -p tcp --syn -j DROP
2.2.2 使用firewalld配置防火墙(CentOS/RHEL)
firewalld是CentOS 7及之后版本的默认防火墙工具,相比iptables,其配置更易管理。
# 启动firewalld
sudo systemctl start firewalld
sudo systemctl enable firewalld
# 查看当前状态
sudo firewall-cmd --state
# 查看默认区域
sudo firewall-cmd --get-default-zone
# 查看活动区域
sudo firewall-cmd --get-active-zones
配置防火墙规则:
# 添加服务
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
# 添加自定义端口
sudo firewall-cmd --permanent --add-port=22022/tcp
# 删除默认SSH端口
sudo firewall-cmd --permanent --remove-service=ssh
# 限制SSH访问来源
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port port="22022" protocol="tcp" accept'
# 重载配置
sudo firewall-cmd --reload
# 查看所有规则
sudo firewall-cmd --list-all
2.3 用户权限管理
2.3.1 创建普通用户并配置sudo权限
避免直接使用root账户,通过sudo机制授予普通用户必要的管理权限。
创建用户:
# 创建新用户
sudo useradd -m -s /bin/bash deploy
# 设置密码
sudo passwd deploy
# 或者创建用户时指定更多信息
sudo useradd -m -s /bin/bash -c "Deploy User" -G wheel deploy
配置sudo权限:
# 编辑sudoers文件(推荐使用visudo)
sudo visudo
# 或者创建独立的配置文件
sudo vim /etc/sudoers.d/deploy
sudo配置示例:
# 允许用户执行所有命令(需要密码)
deploy ALL=(ALL:ALL) ALL
# 允许用户执行所有命令(无需密码,不推荐)
deploy ALL=(ALL:ALL) NOPASSWD: ALL
# 只允许特定命令
deploy ALL=(ALL) /usr/bin/systemctl restart nginx, /usr/bin/systemctl status nginx
# 允许用户组
%admin ALL=(ALL:ALL) ALL
验证sudo权限:
# 切换到新用户
su - deploy
# 测试sudo权限
sudo whoami # 应该输出root
2.3.2 配置密码策略
对于仍需使用密码的服务或场景,强制使用强密码并定期更换是基本要求。
安装密码质量检查工具:
# Ubuntu/Debian
sudo apt install -y libpam-pwquality
# CentOS/RHEL
sudo yum install -y libpwquality
配置密码策略:
# 编辑PAM配置
sudo vim /etc/security/pwquality.conf
密码策略配置:
# 最小密码长度
minlen = 12
# 至少包含一个小写字母
lcredit = -1
# 至少包含一个大写字母
ucredit = -1
# 至少包含一个数字
dcredit = -1
# 至少包含一个特殊字符
ocredit = -1
# 新密码中至少有3个字符与旧密码不同
difok = 3
# 密码不能包含用户名
usercheck = 1
配置密码过期策略:
# 编辑登录配置
sudo vim /etc/login.defs
# 密码最长使用天数
PASS_MAX_DAYS 90
# 密码最短使用天数
PASS_MIN_DAYS 7
# 密码过期前警告天数
PASS_WARN_AGE 14
三、示例代码和配置
3.1 安全加固一键脚本
以下脚本整合了上述部分关键步骤,可用于快速进行基础安全加固,但生产环境请务必谨慎测试。
#!/bin/bash
# 文件名:security_hardening.sh
# 功能:Linux服务器安全加固自动化脚本
set -e
echo "========================================="
echo "Linux服务器安全加固脚本"
echo "时间:$(date '+%Y-%m-%d %H:%M:%S')"
echo "========================================="
# 1. 备份重要配置文件
echo "[1/6] 备份配置文件..."
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d)
sudo cp /etc/sudoers /etc/sudoers.bak.$(date +%Y%m%d)
# 2. 配置SSH安全
echo "[2/6] 配置SSH安全..."
sudo sed -i 's/^#*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#*Port.*/Port 22022/' /etc/ssh/sshd_config
# 3. 安装fail2ban
echo "[3/6] 安装fail2ban..."
if command -v apt &> /dev/null; then
sudo apt update && sudo apt install -y fail2ban
elif command -v yum &> /dev/null; then
sudo yum install -y epel-release && sudo yum install -y fail2ban
fi
# 4. 配置防火墙
echo "[4/6] 配置防火墙..."
if command -v firewall-cmd &> /dev/null; then
sudo firewall-cmd --permanent --add-port=22022/tcp
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
else
sudo iptables -A INPUT -p tcp --dport 22022 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
fi
# 5. 配置密码策略
echo "[5/6] 配置密码策略..."
sudo sed -i 's/^PASS_MAX_DAYS.*/PASS_MAX_DAYS 90/' /etc/login.defs
sudo sed -i 's/^PASS_MIN_DAYS.*/PASS_MIN_DAYS 7/' /etc/login.defs
# 6. 重启服务
echo "[6/6] 重启相关服务..."
sudo systemctl restart sshd
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
echo "========================================="
echo "安全加固完成!"
echo "注意:SSH端口已改为22022"
echo "请确保防火墙已开放该端口"
echo "========================================="
3.2 实际应用案例
案例一:电商平台SSH暴力破解防护
场景描述:某电商平台Web服务器的auth.log中出现大量来自全球各地IP的失败SSH登录尝试,每分钟数千次,属于典型的暴力破解攻击。
诊断过程:
# 查看失败的登录尝试
sudo grep "Failed password" /var/log/auth.log | tail -20
# 统计攻击来源IP
sudo grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -10
# 输出示例:
# 1523 185.220.101.45
# 892 103.99.0.122
# 654 198.98.51.189
解决方案:
# 1. 立即配置fail2ban
sudo apt install -y fail2ban
sudo systemctl start fail2ban
sudo systemctl enable fail2ban
# 2. 配置更严格的封禁策略
sudo vim /etc/fail2ban/jail.local
# [sshd]
# enabled = true
# maxretry = 3
# bantime = 86400 # 封禁24小时
# findtime = 600
# 3. 禁用密码登录
sudo vim /etc/ssh/sshd_config
# PasswordAuthentication no
# 4. 重启SSH服务
sudo systemctl restart sshd
# 5. 验证效果
sudo fail2ban-client status sshd
优化效果:
- 暴力破解尝试从每分钟数千次降至几乎为零。
- 24小时内自动封禁了超过200个恶意IP。
- 切换到密钥认证后,从根本上杜绝了密码被破解的可能性。
四、最佳实践和注意事项
4.1 最佳实践
4.1.1 SSH安全最佳实践
使用密钥认证:
- 密钥长度至少2048位,推荐4096位。
- 为私钥设置密码短语,增加一层保护。
- 定期轮换密钥(建议每年一次)。
- 私钥妥善保管,避免在多台机器间复制。
限制访问来源:
# 在sshd_config中限制允许登录的用户
AllowUsers deploy@192.168.1.* admin@10.0.0.*
# 或者使用防火墙限制
sudo iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 22022 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22022 -j DROP
4.1.2 防火墙最佳实践
默认拒绝策略:
- 采用白名单机制,默认拒绝所有入站流量。
- 只开放业务绝对必需的端口和服务。
- 定期审计并清理不再需要的防火墙规则。
分层防护:
# 网络层:限制IP访问
sudo iptables -A INPUT -s 10.0.0.0/8 -j ACCEPT
# 传输层:限制端口访问
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# 应用层:使用nginx限流
# limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
4.2 注意事项
4.2.1 配置变更注意事项
修改SSH配置前的准备:
- 务必保持至少一个当前的SSH连接不要断开,作为“救命稻草”。
- 在新开的终端窗口中测试新配置是否能成功登录。
- 确认防火墙规则已更新,放行了新的SSH端口。
- 准备好带外管理方式(如服务器控制台、IPMI),以防万一。
防火墙配置注意事项:
- 修改规则前,先使用
iptables-save 或相应命令备份当前规则。
- 规则变更后必须保存(如
iptables-save > /etc/iptables/rules.v4),否则重启后会丢失。
- 测试fail2ban等自动封禁规则时,先设置较短的
bantime(如60秒)。
4.2.2 常见错误
| 错误现象 |
原因分析 |
解决方案 |
| SSH无法连接 |
修改端口后防火墙未开放新端口 |
通过服务器控制台登录,在防火墙中开放新端口 |
| 密钥登录失败 |
~/.ssh/authorized_keys 文件权限不正确 |
chmod 600 ~/.ssh/authorized_keys |
| fail2ban不工作 |
日志路径(logpath)配置错误 |
检查 /etc/fail2ban/jail.local 中对应 jail 的 logpath 配置 |
| sudo无法使用 |
/etc/sudoers 文件存在语法错误 |
使用 pkexec visudo 命令进行修复 |
| 防火墙规则不生效 |
规则顺序有误,DROP规则在ACCEPT之前 |
检查规则顺序,确保ACCEPT规则在对应的DROP规则之前 |
五、故障排查和监控
5.1 安全日志分析
SSH登录日志:
# 查看成功的登录
sudo grep "Accepted" /var/log/auth.log
# 查看失败的登录
sudo grep "Failed" /var/log/auth.log
# 统计登录尝试最多的IP
sudo grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -10
sudo操作日志:
# 查看sudo操作记录
sudo grep "sudo" /var/log/auth.log
# 查看特定用户的sudo操作
sudo grep "sudo.*deploy" /var/log/auth.log
5.2 安全监控指标
建议对以下关键安全指标进行监控,以便及时发现异常。
| 指标类别 |
指标名称 |
正常范围 |
告警阈值 |
说明 |
| SSH |
失败登录次数 |
<10次/小时 |
>100次/小时 |
可能遭受暴力破解 |
| SSH |
异常时间登录 |
0 |
>0 |
凌晨2-6点的登录需要关注 |
| 防火墙 |
被拒绝连接数 |
<1000次/小时 |
>10000次/小时 |
可能遭受扫描或攻击 |
| 用户 |
新增用户 |
0 |
>0 |
未授权的用户创建 |
| 权限 |
sudo失败次数 |
<5次/天 |
>20次/天 |
可能有权限提升尝试 |
六、总结
6.1 技术要点回顾
- SSH安全核心:禁用密码登录,强制使用密钥认证;修改默认端口以避开自动化扫描;配置fail2ban实现自动封禁;严格限制登录用户和来源IP。
- 防火墙配置核心:坚守默认拒绝策略;仅开放业务必需的端口;使用白名单机制精细控制访问来源;确保所有动作都有日志可查。
- 权限管理核心:禁止root账户直接远程登录;通过sudo机制按需授权;配置强密码策略并定期更换;遵循最小权限原则。
6.2 进阶学习方向
- 入侵检测与审计:
- 学习使用AIDE进行文件完整性检查。
- 部署OSSEC或Wazuh等HIDS进行主机层实时监控。
- 搭建ELK Stack实现日志集中管理与分析。
- 安全加固自动化:
- 使用Ansible、Puppet等工具进行批量服务器的安全基线配置。
- 编写自动化安全巡检脚本。
- 将安全检查点集成到CI/CD流程中。
- 高级防护技术:
- 深入理解并配置SELinux或AppArmor实现强制访问控制。
- 学习容器(Docker/Kubernetes)环境下的安全最佳实践。
- 探索零信任网络架构在内部网络中的应用。
服务器安全是一个涉及运维、安全和网络的综合性领域。本文介绍的SSH、防火墙和权限管理是构建安全基石的三大支柱。希望这份实战指南能帮助你有效加固服务器。如果你在实践过程中遇到其他问题,或想分享自己的加固经验,欢迎来到云栈社区与更多开发者交流探讨。
附录:常用安全命令速查
# 查看当前登录用户
w
who
# 查看登录历史
last
lastb # 查看失败的登录记录
# 查看系统用户
cat /etc/passwd
# 查看当前用户的sudo权限
sudo -l
# 查看网络监听端口
sudo netstat -tulnp
sudo ss -tulnp
# 查看iptables防火墙规则
sudo iptables -L -n -v
# 查看firewalld防火墙规则
sudo firewall-cmd --list-all
# 查看fail2ban状态
sudo fail2ban-client status