Linux服务器安全加固实战:账号、登录、口令与端口四重防护
1. 项目概述:为什么说“账号、登录、口令、端口”是Linux安全的四道门?
如果你刚接手一台Linux服务器,或者准备把自己的VPS打造成一个更坚固的堡垒,从哪里开始加固最有效?我的经验是,抛开那些复杂的安全框架和昂贵的商业软件,先把最基础、最容易被忽视的四个点——账号、登录、口令、端口——给扎扎实实地管好。这就像给房子装防盗门,你可能会装智能锁、监控,但如果门本身是纸糊的,或者钥匙就藏在门口的地垫下,其他一切都是白搭。
在真实的攻防对抗或安全审计中,攻击者第一步往往就是“敲门”。他们会尝试默认账号、弱口令、未关闭的远程端口,或者利用有缺陷的登录机制。我见过太多因为一个弱口令的测试账号,或者一个默认开启的22端口被暴力破解,导致整个服务器沦陷的案例。因此,这个“核心实战”项目,就是要带你把这四道门逐一加固,把那些低级的、却足以致命的风险点给堵上。无论你是运维工程师、开发者,还是个人站长,这套组合拳都是你Linux安全入门的必修课,也是构建纵深防御体系的第一块基石。
2. 账号安全:从清理“僵尸”到精细化权限管控
账号是系统访问的起点。一个混乱的账号体系,意味着攻击者有更多可乘之机。我们的目标不仅是删除无用账号,更要建立清晰的账号管理和权限划分原则。
2.1 账号清单审计与无用账号清理
第一步,你得知道自己系统里到底有多少“住户”。直接查看/etc/passwd文件是最基本的方法,但信息比较杂乱。我习惯用几个组合命令来快速审计:
# 查看所有系统用户(UID < 1000)和普通用户 awk -F: '$3 < 1000 {print $1" (系统用户)"} $3 >= 1000 {print $1" (普通用户)"}' /etc/passwd # 查看最近登录过的用户 lastlog # 查看当前登录的用户及其来源 who -a重点排查以下几类“高危”账号:
- 默认测试或示例账号:如
test、guest、demo等。这些账号口令往往简单或为空。 - 长期未登录的账号:使用
lastlog命令,找出那些“上次登录时间”显示为**从未登录过**或时间非常久远的账号。这些可能是被遗忘的“僵尸账号”。 - UID为0的非root账号:任何UID为0的用户都拥有root权限。除了root本身,不应该有其他UID为0的账号。检查命令:
awk -F: '($3 == 0) {print $1}' /etc/passwd。
对于确认无用的账号,坚决删除。但删除前,务必确认该账号没有关联任何正在运行的服务或定时任务。一个鲁莽的userdel -r username可能会导致服务崩溃。我的操作流程是:
ps -u username查看该用户是否有进程在运行。crontab -u username -l查看该用户的定时任务。- 确认无误后,再使用
userdel -r username删除账号及其家目录。
实操心得:对于一时无法确定是否可删的账号(比如某个老旧应用的服务账号),一个更稳妥的做法是先禁用,后观察。使用
usermod -L username或passwd -l username锁定账号,使其无法登录。观察一段时间(如一两周),确认系统所有功能正常后,再行删除。
2.2 超级用户权限的受控分配
永远不要直接分享root密码。这是铁律。正确的做法是使用sudo机制进行细粒度的权限委派。
首先,精简wheel组(或sudo组,取决于发行版)的成员。只有确需管理员权限的用户才应加入该组。检查命令:grep '^wheel' /etc/group或grep '^sudo' /etc/group。
其次,也是更关键的一步,是为特定用户或组配置精细化的sudo规则,而不是简单地赋予所有sudo权限。直接编辑/etc/sudoers文件风险较高,推荐使用visudo命令,它会在保存前检查语法,避免配置错误导致所有sudo功能失效。
一个精细化配置的例子:
# 用户 alice 只能以root身份重启nginx服务,且无需输入密码 alice ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx # 组 developers 可以运行所有软件包管理命令 %developers ALL=(ALL) /usr/bin/apt, /usr/bin/apt-get, /usr/bin/dpkg # 用户 bob 可以管理用户,但不能修改root密码 bob ALL=(ALL) /usr/sbin/useradd, /usr/sbin/userdel, /usr/sbin/usermod, /usr/bin/passwd, !/usr/bin/passwd root最后一行配置中的!表示“禁止”,这是一个非常实用的技巧,可以实现“允许大部分,禁止小部分”的权限控制。
注意事项:
NOPASSWD选项要慎用。虽然方便了自动化脚本,但也降低了安全门槛。仅在对安全性要求不高、且需要频繁执行的内网自动化任务中考虑使用。
2.3 服务账号的“降权”运行原则
很多应用程序(如Web服务器、数据库)需要以非root身份运行。我们应遵循“最小权限原则”,为这些服务创建专用的、权限受限的系统账号。
例如,为Nginx创建服务账号:
sudo useradd -r -s /sbin/nologin nginx参数解释:
-r:创建系统账号(UID较小,通常不创建家目录)。-s /sbin/nologin:设置其登录shell为/sbin/nologin,禁止该账号通过SSH等方式交互式登录,这从根本上杜绝了通过该账号获得shell的风险。
然后,在Nginx的配置文件(如nginx.conf)中,将user指令设置为nginx。这样,即使Nginx服务存在漏洞被攻破,攻击者获得的也只是一个权限极低的nginx账号身份,难以进行横向移动或提权。
3. 登录安全:筑起身份验证的坚固防线
控制了谁能进(账号),接下来就要管好“怎么进”(登录)。SSH是Linux远程管理的命脉,也是攻击者最常攻击的入口。
3.1 SSH服务配置深度优化
默认的SSH配置过于“友好”,我们需要让它变得“挑剔”且“坚固”。配置文件位于/etc/ssh/sshd_config,修改后需重启服务:sudo systemctl restart sshd。
关键配置项解析与加固:
修改默认端口(Port):
Port 2222 # 将22改为一个非知名端口,如2222、3522等- 为什么?这是最直接、最有效的“噪音过滤”手段。互联网上绝大多数针对22端口的自动化扫描脚本会因此失效。这并不能防止定向攻击,但能减少99%的随机扫描和暴力破解尝试。
- 注意:修改后,连接命令需指定端口:
ssh -p 2222 user@host。务必在修改前,确保新端口在防火墙中是放行的,并且保留一个当前活跃的SSH会话作为“逃生通道”,以防配置错误导致无法连接。
禁止root用户直接登录(PermitRootLogin):
PermitRootLogin no- 为什么?即使root口令很强,直接暴露最高权限账户也是极危险的。强制攻击者先攻破一个普通用户,再尝试提权,增加了攻击难度和我们的预警时间。
禁用密码认证,启用密钥对认证(PasswordAuthentication & PubkeyAuthentication):
PasswordAuthentication no PubkeyAuthentication yes- 为什么?这是防御暴力破解的终极方案。密钥认证基于非对称加密,私钥本地保存,不通过网络传输,理论上无法被暴力破解。彻底关闭密码认证后,SSH暴力破解工具将完全失效。
- 如何操作:
- 本地生成密钥对:
ssh-keygen -t ed25519 -C "your_email@example.com"(推荐ed25519算法,更快更安全)。 - 将公钥(
~/.ssh/id_ed25519.pub)内容上传到服务器的对应用户家目录下的~/.ssh/authorized_keys文件中。 - 务必确保
~/.ssh目录权限为700,authorized_keys文件权限为600,否则SSH会出于安全考虑拒绝使用密钥。
- 本地生成密钥对:
使用更强的基础加密算法(KexAlgorithms, Ciphers, MACs): 禁用已知不安全的旧算法,强制使用现代强算法。这是一个进阶配置,能抵御针对弱加密算法的攻击。
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256 Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
3.2 双因子认证(2FA)增强
对于安全要求极高的场景(如生产环境跳板机),仅靠密钥认证可能还不够。可以引入基于时间的一次性密码(TOTP)作为第二因素。即使私钥泄露,没有动态口令也无法登录。
常用工具是google-authenticator。安装后,运行google-authenticator命令,按照提示用手机App(如Google Authenticator、Microsoft Authenticator)扫描二维码,然后在SSH配置中启用挑战应答认证:
ChallengeResponseAuthentication yes AuthenticationMethods publickey,keyboard-interactive:pam这样,登录时就需要先通过密钥认证,再输入手机App上显示的6位动态码。
踩坑记录:配置2FA后,一定要为自己保留至少两个有效的验证方式(如两台手机都绑定),并保存好紧急救援码。我曾因手机丢失又没备份,差点把自己锁在服务器外面。
3.3 登录监控与入侵检测
加固之后,还需要有“眼睛”。/var/log/auth.log(Debian/Ubuntu)或/var/log/secure(RHEL/CentOS)记录了所有认证日志。
- 实时监控失败登录:
sudo tail -f /var/log/auth.log | grep -i "failed password" - 统计攻击源IP:
sudo grep "Failed password" /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -nr | head -20
对于频繁攻击的IP,可以手动加入防火墙黑名单,或者使用fail2ban这类工具自动封禁。fail2ban会监控日志,当某个IP在短时间内达到预设的失败次数阈值时,自动调用防火墙规则(如iptables)将其封禁一段时间。
4. 口令安全:告别“弱口令”的全面策略
口令是最后一道本地防线。即使SSH用了密钥,本地登录、数据库、Web应用后台等依然依赖口令。
4.1 系统级口令强度策略实施
通过PAM(可插拔认证模块)强制所有用户使用强口令。编辑/etc/security/pwquality.conf(或/etc/pam.d/common-password)文件。
一个严格的策略配置示例:
minlen = 12 minclass = 3 dcredit = -1 ucredit = -1 ocredit = -1 lcredit = -1 maxrepeat = 2 reject_username = yes enforce_for_root = yesminlen=12:最小长度12位。minclass=3:密码中至少包含3种字符类别(小写、大写、数字、符号)。dcredit=-1:要求至少1位数字。ucredit、ocredit、lcredit同理,分别对应大写、符号、小写。maxrepeat=2:同一字符最多连续出现2次。reject_username=yes:密码中不能包含用户名。enforce_for_root=yes:此策略对root用户同样生效。
设置后,用户使用passwd修改密码时就必须符合此策略。
4.2 定期口令更换与过期策略
对于有合规要求的场景,需要强制用户定期更换密码。通过/etc/login.defs和chage命令管理。
在/etc/login.defs中设置默认策略:
PASS_MAX_DAYS 90 PASS_MIN_DAYS 7 PASS_WARN_AGE 14PASS_MAX_DAYS 90:密码最长使用90天。PASS_MIN_DAYS 7:密码修改后,7天内不能再次修改。PASS_WARN_AGE 14:密码过期前14天开始警告。
查看特定用户密码策略:chage -l username。 手动设置用户策略:sudo chage -M 90 -m 7 -W 14 username。
4.3 口令存储与哈希算法升级
系统用户口令并非明文存储,而是经过哈希处理后的字符串,存放在/etc/shadow文件中。哈希算法的强度至关重要。
检查当前系统默认的密码哈希算法:
sudo authselect current | grep password-hashing现代Linux发行版默认应使用sha512。如果你的系统还在使用陈旧的md5或des,必须升级。
升级所有现有用户的密码哈希到sha512是一个敏感操作。可以鼓励用户在下次登录时自行修改密码(系统会自动用新算法存储)。对于服务账号,可以用openssl passwd -6(-6代表sha512)生成哈希值,然后手动更新/etc/shadow文件,但需格外小心。
重要警告:直接编辑
/etc/shadow文件风险极高,极易导致用户无法登录。非必要不手动操作。优先通过passwd命令或鼓励用户登录修改来触发哈希升级。
5. 端口防护:从暴露到隐匿的网络边界控制
端口是网络服务的门户。开放不必要的端口,就等于在城墙多开了一道无人看守的侧门。
5.1 端口发现与服务识别
在加固之前,先搞清楚自己“家”里到底开了哪些“门”。不要只相信你自己的记忆或配置,要从外部和内部两个视角进行扫描。
外部视角(模拟攻击者):使用
nmap从另一台机器扫描你的服务器公网IP。nmap -sS -p- -T4 <你的服务器IP>。-sS是SYN半开放扫描,-p-扫描所有65535个端口,-T4是速度级别。这个结果会告诉你,在互联网上到底能访问到哪些服务。内部视角(自查):在服务器本机上,使用
ss(推荐,比netstat更高效)或netstat命令。sudo ss -tulnp-t:TCP端口。-u:UDP端口。-l:仅显示监听状态的端口。-n:以数字形式显示地址和端口。-p:显示占用端口的进程名和PID。
仔细核对每一个监听端口,问自己三个问题:1. 这个服务是我需要的吗?2. 它需要被公网访问吗?3. 它是最新、安全的版本吗?
5.2 防火墙策略的精细化配置
防火墙是你的网络守门人。我强烈推荐使用iptables的后继者nftables,或者更易用的前端工具ufw(Uncomplicated Firewall)。这里以ufw为例,因为它语法简单,适合快速上手。
基础策略:默认拒绝所有入站,允许所有出站。
sudo ufw default deny incoming sudo ufw default allow outgoing按需放行端口:
- 放行SSH(假设你已改为2222端口):
sudo ufw allow 2222/tcp comment 'SSH Access' - 放行HTTP/HTTPS:
sudo ufw allow 80,443/tcp comment 'Web Services' - 放行特定IP访问特定端口(如只允许办公室IP访问数据库):
sudo ufw allow from 192.168.1.100 to any port 3306 proto tcp comment 'MySQL for Admin PC'
启用并检查规则:
sudo ufw enable sudo ufw status numbered verbose # 查看带编号和注释的详细规则一个关键技巧:速率限制。对于必须开放的服务(如SSH),可以启用速率限制来减缓暴力破解。
sudo ufw limit 2222/tcp comment 'SSH rate limit'这条规则会自动限制同一IP在短时间内新建连接的频率。
5.3 服务绑定与访问控制列表(ACL)
有时,你希望一个服务(如数据库、Redis)只被本机或内部网络的其他服务器访问,而不是整个互联网。仅靠防火墙可能不够精细,需要在服务本身配置绑定地址。
- MySQL/MariaDB:在配置文件(
/etc/mysql/mysql.conf.d/mysqld.cnf或/etc/my.cnf)中,找到bind-address项,将其设置为127.0.0.1(仅本地)或内部网络IP(如192.168.1.10),而不是0.0.0.0。 - Redis:默认绑定
127.0.0.1是安全的,但如果需要网络访问,务必在redis.conf中设置bind 192.168.1.10(指定IP),并必须配置requirepass设置一个强密码。
更进一步,可以在服务层面配置ACL。例如,Nginx可以配置allow和deny指令,只允许特定IP段访问管理后台location。
5.4 端口隐匿与敲门(Port Knocking)技术
对于极度敏感的服务,可以将其“隐藏”起来。端口敲门是一种有趣的技术:服务端口默认关闭,只有按照特定顺序“敲击”(连接)一系列预设的封闭端口后,防火墙规则才会临时打开目标端口。
例如,使用knockd工具。配置一个敲门序列1000,2000,3000(TCP)。客户端需要依次快速连接这三个端口后,服务器的防火墙才会临时开放SSH端口(如2222)给该客户端IP,持续30秒。
这极大地增加了攻击者发现和攻击目标端口的难度。但请注意,这不是银弹,它增加了管理复杂性,且不适合高频率访问的场景。它更像是一个为特定管理通道增加的“秘密机关”。
6. 实战整合:构建一个最小化暴露的服务器配置示例
让我们把以上所有点串联起来,为一个全新的Ubuntu 22.04服务器制定一份初始安全加固清单。假设这是一台用于部署Web应用(Nginx + Python)的服务器。
第1步:初始登录与账号设置
- 使用云平台控制台或本地终端,用提供的初始密钥或密码登录。
- 立即修改root密码(如果允许):
sudo passwd root,设置一个超强密码并妥善保存(即使后续禁用root登录,也应设置)。 - 创建个人管理账号,并加入sudo组:
sudo adduser yourusername sudo usermod -aG sudo yourusername - 切勿退出当前root或初始会话。新开一个终端,用新创建的
yourusername账号和密钥/密码尝试登录并执行sudo -i,确认sudo权限正常。
第2步:SSH深度加固
- 在新账号的会话中,编辑SSH配置:
sudo vim /etc/ssh/sshd_config。 - 应用以下关键修改:
Port 3522 PermitRootLogin no PasswordAuthentication no PubkeyAuthentication yes AllowUsers yourusername # 只允许特定用户登录,多个用户用空格隔开 - 将本地公钥(
~/.ssh/id_ed25519.pub)内容,追加到服务器上yourusername用户的家目录下:~/.ssh/authorized_keys。 - 设置正确的权限:
sudo chmod 700 ~/.ssh sudo chmod 600 ~/.ssh/authorized_keys - 在重启SSH前,至关重要的一步:在另一个终端窗口,保持一个当前活跃的SSH连接不关闭,作为“救援会话”。然后在新会话中测试新端口连接:
ssh -p 3522 -i ~/.ssh/your_private_key yourusername@服务器IP。确认能成功登录后,再回到“救援会话”重启SSH服务:sudo systemctl restart sshd。 - 用新端口和新账号成功登录后,方可关闭旧的“救援会话”。
第3步:配置防火墙(UFW)
- 设置默认策略并放行必要端口:
sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow 3522/tcp comment 'SSH on non-standard port' sudo ufw allow 80,443/tcp comment 'HTTP/HTTPS' # 如果数据库只需内网访问,这里不放行3306等端口 - 启用UFW:
sudo ufw enable。系统可能会提示影响当前的SSH连接,因为默认策略是deny incoming。由于我们已经明确放行了3522端口,所以输入y确认即可。
第4步:服务配置与口令策略
- 为Nginx和你的Python应用(如Gunicorn)创建专属系统账号。
sudo useradd -r -s /sbin/nologin nginx sudo useradd -r -s /sbin/nologin myapp - 在Nginx和Gunicorn配置文件中,指定以对应用户运行。
- 配置全局密码策略,编辑
/etc/security/pwquality.conf,设置如前面所述的强密码规则。 - 使用
chage命令为你的yourusername账号设置密码过期策略。
第5步:部署监控与日志
- 安装并配置
fail2ban:sudo apt install fail2ban sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local - 编辑
/etc/fail2ban/jail.local,针对SSH端口进行监控(注意端口号):[sshd] enabled = true port = 3522 filter = sshd logpath = /var/log/auth.log maxretry = 5 bantime = 3600 - 启动并设置开机自启:
sudo systemctl enable --now fail2ban。 - 定期查看日志:
sudo tail -f /var/log/fail2ban.log和sudo tail -f /var/log/auth.log。
完成以上步骤,你的服务器就从“裸奔”状态变成了一个拥有坚固四道防线的堡垒。这只是一个起点,安全是一个持续的过程,需要结合漏洞扫描、定期更新、备份恢复等共同构成完整的防御体系。但毫无疑问,把这四件事做好,你已经挡住了绝大多数自动化攻击和初级攻击者,为你的数据和业务赢得了至关重要的安全基础。