在Ubuntu服务器上,端口安全管控的第一道防线就是搞清楚哪些端口正在被哪些进程占用。很多管理员习惯性直接上防火墙,但如果你连当前监听的服务都没摸清,封端口就是瞎忙活。最直接的排查命令是ss,它比老旧的netstat更快更准。执行 ss -tlnp 可以列出所有TCP监听的端口及对应的进程名和PID。你会看到类似“127.0.0.1:3306”这样的条目,注意这个IP前缀,它意味着MySQL只监听了本地回环地址,外部根本无法连接,这是数据库默认最安全的状态。如果显示“0.0.0.0:22”,说明SSH服务对所有网卡开放,这就值得警惕了。

除了ss,lsof -i :端口号 可以反向查询某个端口被谁占用,这在处理端口冲突时非常实用。比如你改完Nginx配置发现起不来,直接 lsof -i :443 看是不是Apache还占着坑。再结合 netstat -tulnp 查看UDP端口,因为DNS、NTP这类服务走UDP,很容易被忽略。排查完端口现状,你心里就有了一张“端口地图”,接下来才能精准施策,而不是盲目封禁导致业务中断。

UFW防火墙策略:从默认拒绝到精细放行

Ubuntu自带的UFW(Uncomplicated Firewall)是iptables的友好前端,但很多人用错了它的默认策略。装完系统第一件事不是开UFW,而是先设默认规则:ufw default deny incoming 和 ufw default allow outgoing。这意味所有入站流量默认拒绝,出站流量默认放行。然后你再像白名单一样逐个开放必要端口。比如 sudo ufw allow 22/tcp 只放行SSH,sudo ufw allow 80,443/tcp 放行Web服务。注意,直接 ufw allow 80 会同时放行TCP和UDP,而Web服务只用TCP,多余开放就是风险。

更精细的做法是限制来源IP。如果你的SSH只允许公司固定IP访问,就用 sudo ufw allow from 203.0.113.5 to any port 22。对于多网卡服务器,还可以绑定网卡接口,比如 sudo ufw allow in on eth1 to any port 3306,这样即使MySQL监听了内网地址,也只允许内网网卡进来。启用UFW前务必先放行SSH端口,否则一旦启用 sudo ufw enable,你连自己都登不上去。可以用 ufw status numbered 查看规则编号,方便后续用 ufw delete 编号 来删改规则。

服务自身绑定监听地址:比防火墙更底层的隔离

防火墙是门卫,但服务自身配置才是房间的锁。很多服务默认监听所有接口,这意味着即使防火墙放行了,服务本身也暴露了不必要的攻击面。以MySQL为例,编辑 /etc/mysql/mysql.conf.d/mysqld.cnf,找到 bind-address = 127.0.0.1,这就是只允许本地连接。如果前后端分离,后端API和数据库在同一台机器,就让MySQL只监听本地,API通过Unix Socket或127.0.0.1连接,性能更好也更安全。Redis同理,在 /etc/redis/redis.conf 中设置 bind 127.0.0.1 ::1,并确保 protected-mode yes 开启。

Nginx或Apache这类Web服务通常需要对外,但如果有多个虚拟主机,可以按域名或IP区分监听。比如在Nginx的server块中写 listen 203.0.113.5:80; 而不是 listen 80;,这样服务就只绑定特定公网IP,其他IP上的请求根本到不了Nginx。对于微服务架构中那些仅内部调用的API服务,直接让它们监听内网地址如10.0.0.5:8080,从网络层面彻底杜绝外部访问。这种“服务自治”的安全思路,比单纯依赖防火墙更稳固。

SSH端口安全强化:不止是改端口号

SSH是服务器的命门,但改端口号22为其他值只是障眼法,端口扫描器几秒钟就能发现。真正有效的做法是组合拳。编辑 /etc/ssh/sshd_config,首先禁止root直接登录:PermitRootLogin no。然后禁止密码认证,只允许密钥登录:PasswordAuthentication no,ChallengeResponseAuthentication no。同时设置允许登录的用户白名单:AllowUsers youruser。这几个配置一上,暴力破解基本废了。

更进阶的是使用TCP Wrappers做二次访问控制。编辑 /etc/hosts.allow,添加 sshd: 203.0.113.5 只允许特定IP,再在 /etc/hosts.deny 中写 sshd: ALL 拒绝其他所有。虽然TCP Wrappers在较新Ubuntu版本中逐渐被弃用,但仍有大量生产环境在用。替代方案是使用iptables的recent模块做动态限速,或者直接上fail2ban。安装fail2ban后,默认的jail配置就会监控SSH登录失败,超过次数自动用iptables封禁来源IP一段时间。sudo apt install fail2ban 后,cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local,然后在 [sshd] 部分调整 maxretry 和 bantime 参数即可。

应用层访问权限控制:文件系统与进程用户分离

端口和服务安全最终要落到文件系统权限上。一个经典错误是Web应用以root运行,一旦应用有漏洞,攻击者直接拿到root shell。正确做法是为每个服务创建独立系统用户,比如 sudo useradd -r -s /bin/false nginx,让Nginx以nginx用户运行。在Nginx配置中指定 user nginx;,并确保 /var/www/html 目录的所有者和权限设置正确。通常网站文件归开发用户所有,Nginx只需要读取权限,所以设置 chmod 755 目录,chmod 644 文件,并且目录组可以设为 www-data,然后Nginx用户加入该组。

PHP-FPM的情况更复杂,因为PHP进程需要写权限来生成缓存或上传文件。这里要使用进程池隔离,每个网站一个独立的PHP-FPM池,各自以不同系统用户运行。在 /etc/php/8.1/fpm/pool.d/ 下创建配置文件,指定 user 和 group 为对应网站的用户,同时设置 listen.owner 和 listen.group 与Nginx用户匹配,这样Nginx才能通过Unix Socket与PHP通信。这种隔离下,A网站被黑不会影响B网站的文件,攻击者的横向移动被有效遏制。

内核参数调优:网络层面的深度防御

除了应用和防火墙,Linux内核本身提供了大量网络安全参数,通过 sysctl 调整可以抵御常见攻击。编辑 /etc/sysctl.conf 或 /etc/sysctl.d/99-security.conf,开启TCP SYN Cookie防护:net.ipv4.tcp_syncookies = 1,这能防御SYN Flood攻击。禁止IP源路由:net.ipv4.conf.all.accept_source_route = 0,防止攻击者指定数据包路由路径。禁止ICMP重定向:net.ipv4.conf.all.accept_redirects = 0,防止中间人篡改路由表。

对于端口扫描的防御,可以开启net.ipv4.tcp_syn_retries的适当降低,减少SYN重试次数,让扫描器更难判断端口状态。同时启用 net.ipv4.conf.all.rp_filter = 1 开启反向路径过滤,丢弃源地址伪造的数据包。还有一个常被忽略的参数 net.ipv4.icmp_echo_ignore_all = 1,直接禁止Ping响应,虽然不影响端口安全,但能减少被扫描发现的概率。修改后执行 sysctl -p 使其生效。这些内核参数与UFW、服务配置形成立体防护,从协议栈底层到应用层层层设卡。

审计与监控:端口安全的持续保障

安全配置不是一劳永逸,持续监控才能发现异常。首先用 auditd 审计关键文件变更,比如监控 /etc/ssh/sshd_config 和 /etc/ufw/ 目录的修改。执行 sudo auditctl -w /etc/ssh/sshd_config -p wa -k sshd_config_change,任何写入或属性变更都会被记录。对于端口监听的变化,可以编写简单的监控脚本,定期执行 ss -tlnp 并与基线比对,发现新增监听端口立即告警。

更专业的是使用网络入侵检测系统如AIDE做文件完整性校验,或者部署Osquery进行系统状态查询。Osquery可以像查数据库一样查询系统信息,比如 SELECT * FROM listening_ports; 就能获取所有监听端口,配合定时任务和日志聚合,在Grafana上可视化端口变化趋势。另外,定期用 nmap 从外部扫描自己的服务器,验证防火墙规则是否真的生效,因为配置错误时有发生。sudo nmap -sS -p- 你的服务器IP,从外网发起,看实际开放的端口是否与预期一致。这种“红队视角”的自检,往往能发现意想不到的暴露面。