服务器被扫描端口怎么办?识别异常连接与加固网络服务

很多人第一次意识到"服务器在被扫描",是在看了一眼防火墙日志或者 ss 命令的输出之后:一堆陌生的 IP、密密麻麻的短连接、几十上百个半开状态。第一反应通常是慌,觉得"我是不是要被黑了"。其实先要稳住:只要服务器在公网、只要开放了端口,被扫描就是常态,几乎和你做得好不好无关,它更像是背景噪声。真正需要处理的,不是"怎么阻止全世界的扫描器",而是"怎么确认扫描有没有带来实际的异常,以及怎么把自己的暴露面和访问控制收紧到足够小"。

这篇文章从防御和运维的角度讲清楚三件事:怎么识别"服务器确实在被扫描以及是否有异常连接",怎么判断这些连接是噪声还是有风险,以及怎么加固网络服务和访问控制让对方无法得逞。全程不涉及任何扫描、探测、利用的技术细节——我们关心的只有自己这一侧的观测和防守。

所有命令都区分 RHEL/CentOS/Rocky 与 Debian/Ubuntu 两套,涉及防火墙、服务关闭的操作会给出风险提示和回滚方式。

一、先分清:被扫描 ≠ 被入侵

在动手之前,必须先建立一个正确的心态:公网服务器的日志里出现陌生 IP、出现失败连接、出现大量 SYN 包,这些绝大多数是自动化扫描的结果,本身不代表你已经被入侵。扫描是"挨家挨户敲门看有没有人应",而入侵是"敲开了门进去翻东西"。这两件事要分开对待,恐慌性地"关服务器、重装系统"往往反应过度。

同时也要清醒:扫描是入侵的前置动作。扫描器发现你开了某个端口、跑着某个版本的服务,后续可能针对性地尝试利用。所以被扫描本身虽不必惊慌,但它是提醒你"该复查暴露面了"的信号。正确的心态是:把它当成例行体检的触发点,而不是当成事故。

区分"扫描噪声"和"真实异常",看的是模式。扫描通常是:大量不同 IP、连接很快建立又断开、目标端口常常是你根本没跑服务的端口、失败尝试的用户名是 admin/test/root 这类通用词。而真正值得警惕的信号是:某个 IP 反复针对同一服务、某个账号被反复尝试、有成功登录的记录、有异常进程或端口突然被监听、有文件被改动。前者是噪声,后者才需要认真处理。

二、识别:从这几个地方看服务器状态

判断服务器状态,不需要复杂的工具,几个系统自带的命令就够了。关键是知道去哪里看、看什么。

# 1) 看当前所有 TCP 连接与监听,-n 不做 DNS 解析,-t TCP,-u UDP,-p 显示进程
sudo ss -antp | head -50

# 2) 统计各状态连接数:SYN-RECV 多说明有大量半开连接在尝试连接
sudo ss -ant | awk '{print $1}' | sort | uniq -c | sort -rn

# 3) 按远端 IP 统计连接数,找出连接数异常多的来源
sudo ss -ant | awk 'NR>1 {print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20

# 4) 查看监听端口(确认自己开了哪些门)
sudo ss -lntup

第一个命令看到的是实时连接快照。如果有一堆来自陌生 IP、状态是 SYN-RECV(半开)或 ESTAB(已建立)的连接指向某个服务端口,就说明有人正持续尝试连接。第二个命令的状态统计里,SYN-RECV 数量特别多是"有人在大量发起连接"的典型特征(正常业务里这个状态应该很少)。第三条按远端 IP 聚合,能一眼看出有没有某一个或几个 IP 连接数特别夸张。

再看安全日志。SSH 的认证失败是"被扫描"最直观的证据,因为 22 端口是全球扫描的首选目标。

# RHEL / CentOS / Rocky:认证日志在 /var/log/secure
sudo grep -i "Failed password" /var/log/secure | tail -20

# Debian / Ubuntu:认证日志在 /var/log/auth.log
sudo grep -i "Failed password" /var/log/auth.log | tail -20

# 通用:用 journalctl 看 sshd 相关日志(两个发行版都能用)
sudo journalctl -u sshd --since "1 hour ago" | tail -50
sudo journalctl -u ssh --since "1 hour ago" | tail -50   # Debian/Ubuntu 服务名可能是 ssh

# 统计失败登录的来源 IP Top 10(这一步最能说明问题)
sudo grep -i "Failed password" /var/log/secure 2>/dev/null | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -10
# Debian/Ubuntu 把 /var/log/secure 换成 /var/log/auth.log

最后那条统计命令的输出,通常能直接告诉你"谁在敲门"。如果 Top 10 里每个 IP 都只出现几次,说明是分布式的大量机器在泛扫;如果某个 IP 出现成百上千次,说明它盯上了你,这种情况值得封禁。

防火墙日志也是重要来源,前提是你开启了日志。firewalld 和 ufw 都可以配置记录被拒绝的连接。

# 查看内核级防火墙丢包日志(firewalld/nftables/iptables 都可能汇总到内核日志)
sudo journalctl -k | grep -iE "DROP|REJECT" | tail -30
# 或看系统日志
sudo grep -i "UFW BLOCK" /var/log/syslog 2>/dev/null | tail -20    # Debian/Ubuntu + ufw
sudo grep "DROP" /var/log/messages 2>/dev/null | tail -20          # RHEL 系

防火墙日志的价值在于它记录的是"已经被拦下"的连接。如果日志里大量出现目标是你没开放的端口的 DROP 记录,说明扫描器在探测你的全端口,而防火墙正把它们挡住——这正是纵深防御在起作用的样子。

有一类信号必须高度警惕,它意味着可能不只是扫描,而是已经出问题了:系统里出现了不是你启动的监听端口、有陌生进程持续占用 CPU、~/.ssh/authorized_keys 里多了不认识的公钥、cron 里多了奇怪的定时任务、登录记录里有来自陌生 IP 的成功登录。看到这些,要立刻按"疑似已被入侵"来处理:隔离、取证、改所有凭据、重装。这部分超出本文范围,但必须知道这些是"红线信号",不能当噪声忽略。

三、判断:这些连接有没有实际风险

看到了陌生连接和失败登录之后,下一步是判断它有没有真正的风险。判断的依据不是"连接数量多不多",而是"这些连接指向的服务是否暴露了不该暴露的东西"。

第一个判断维度是端口。如果扫描打在 80、443 这些本来就该开放的端口上,那没什么好担心的,这是业务必须的。但如果扫描打在了你本不该对外开放的 3306、6379、27017、9200 上,那就要立刻检查:这些服务是不是监听在 0.0.0.0?安全组是不是放行了?如果是,风险就很高,因为它们很多默认不带认证或认证很弱,被扫到就是很危险的信号。

第二个判断维度是服务版本。老版本的服务往往有已知问题,被扫描发现版本后更容易被针对。所以"隐藏版本信息"是有意义的加固动作——不是让对方找不到你,而是不给对方"一看到版本就知道怎么打"的便利。

第三个判断维度是认证强度。SSH 是否还开着密码登录?数据库是否有强口令?管理接口是否有认证?如果这些还在用默认或弱配置,那么被扫描就意味着随时可能被突破。

# 确认可疑服务是否真的在对外监听
sudo ss -lntp | grep -E ':(3306|6379|27017|9200|11211)\b'
# 若看到 0.0.0.0 或 :: 开头的监听,说明对全网卡开放,需要立即收窄

# 确认 SSH 的认证方式(是否还允许密码登录)
sudo sshd -T | grep -iE 'passwordauthentication|permitrootlogin|pubkeyauthentication'

第二条命令 sshd -T 会输出 sshd 实际生效的配置(比看文件更可靠,因为它会把片段配置合并后输出)。如果 passwordauthentication yes 且服务器在公网,那么被扫描就不仅仅是噪声,而是持续的攻击面。

网络服务加固检查清单

把判断落到具体动作上,下面这张清单可以逐项对照。

检查项 安全目标 查看命令 处理方式
监听端口 只开必要端口 ss -lntup 关停无用服务、收窄监听地址
数据库/缓存暴露 禁止公网访问 ss -lntp \| grep 3306 绑内网、安全组限来源
版本信息 不泄露具体版本 看 HTTP 头/欢迎横幅 关闭版本号显示
SSH 认证 只用密钥 sshd -T \| grep password 关闭密码登录
root 登录 禁止直接登录 sshd -T \| grep permitroot PermitRootLogin no
无用服务 减少暴露面 systemctl list-units --type=service 停用并禁用
防火墙默认策略 默认拒绝 firewall-cmd --list-all / ufw status 设默认拒绝入站

四、防护:把暴露面收到最小

识别和判断之后,真正的工作是防护。防护的逻辑是从外到内层层收紧:最外面是云安全组,往里是主机防火墙,再往里是服务自身的绑定地址和认证,最后是应用的访问控制。

第一层是安全组。把入站改成"默认拒绝 + 逐条放行 + 限定来源"。尤其是 SSH,来源应该是你的办公网段或跳板机,而不是 0.0.0.0/0。数据库、缓存等端口一律不放公网。

第二层是主机防火墙。确保它是开启的,并且默认策略是拒绝入站。

# RHEL / CentOS / Rocky:firewalld
sudo systemctl enable --now firewalld
sudo firewall-cmd --set-default-zone=public
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="198.51.100.0/24" service name="ssh" accept'
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

# Debian / Ubuntu:ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 443/tcp
sudo ufw allow from 198.51.100.0/24 to any port 22 proto tcp
sudo ufw status verbose
sudo ufw enable

风险提示:执行 ufw enable 或 firewalld 收紧规则之前,必须确认你已经放行了当前登录用的端口,并且你的来源 IP 在允许范围内,否则会立刻切断自己的 SSH,导致进不去。回滚方式:sudo ufw disable 临时关闭 ufw,或 sudo systemctl stop firewalld 临时关闭 firewalld(会让规则全部失效)。操作时保留云控制台入口作为兜底。

第三层是服务绑定和认证。数据库只监听 127.0.0.1 或内网 IP;Redis 设 requirepass 和 bind;MongoDB 设 bindIp 并开启认证。SSH 关掉密码登录、禁止 root 直接登录。

第四层是 Fail2ban 这类自动封禁,把持续尝试的 IP 自动挡在门外,并给你的日志减负。它更适合处理"认证失败的反复尝试",和前面几层是互补关系。

五、加固网络服务的具体动作

除了端口和访问控制,服务本身的加固也很关键。

关闭无用服务是性价比很高的一步。很多服务器上跑着装了就没用过的服务,占端口、占资源、增加暴露面。

# 列出所有正在运行的服务,逐个确认是否必要
systemctl list-units --type=service --state=running

# 查看某个端口是哪个服务在监听
sudo ss -lntp | grep <端口>

# 确认无用后,停用并禁止开机自启(示例)
sudo systemctl stop <服务名>
sudo systemctl disable <服务名>

隐藏版本信息能减少被针对的可能。Web 服务的响应头里经常带着服务器名和版本号,拿掉它们对正经用户没有影响。

# Nginx:关闭版本号显示
server_tokens off;          # 放在 http 或 server 块中

# 如果用 PHP-FPM,也建议关闭其版本信息的暴露
# fastcgi_param 相关头可按需精简
# 验证版本信息是否还被泄露
curl -I https://你的域名 | grep -i server
# 理想输出是只有 server: nginx,不带具体版本号

同一条思路也适用于其他服务:SSH 可以在配置里减少 banner 信息,数据库不要对外开放交互式命令行。原则是"只暴露提供服务所必需的那一小部分信息",其余一律收起来。

日志与审计也别落下。开启防火墙日志、保留 SSH 认证日志、定期看失败登录统计,这些动作能让你在被扫描升级为真实尝试时第一时间察觉。

# 给 ufw 开启日志(Debian/Ubuntu)
sudo ufw logging on
# firewalld 开启被拒连接的日志
sudo firewall-cmd --set-log-denied=all

风险提示:把日志级别调到 all 会让日志量显著增加,磁盘小或日志未轮转的服务器可能被日志写满。建议同时确认 logrotate 已配置,或把级别设为 unicast/broadcast 这类更克制的值。

六、一个务实的处置流程

当你在日志里发现"服务器在被扫描",按下面这个顺序处理,既不会反应过度,也不会漏掉真正的风险。

先冷静,把现象记录下来:什么端口、来自哪些 IP、什么时间、频率如何。记录本身就是判断的基础。再看这些端口是不是本来就该开放的,如果打在业务端口上,属于正常噪声;如果打在不该开放的端口上,就是暴露面问题,要立刻收窄。接着核对服务配置:监听地址、认证方式、版本信息,把这些基础项补牢。然后上自动化防护:Fail2ban 封禁持续尝试的来源,防火墙和 Fail2ban 日志开启。最后升级观测:把这些指标纳入日常巡检或告警,让下一次"被扫描"能被自动发现,而不是靠偶然翻日志。

需要反复强调的是:不要试图"阻止所有扫描"。这在公网环境下不现实,也没必要——攻击者的 IP 每天都在变,你封不完。能做好的是"让自己没有可被轻易利用的入口",这才是防御的正解。

常见问题

Q:被扫描要不要封掉对方 IP?
看情况。泛扫的 IP 封了也没意义,它明天就换一个。真正值得封的是那些持续反复、针对特定服务尝试的 IP,这类用 Fail2ban 自动封禁最省事。另外,防火墙默认拒绝策略本身就"封"了所有非必要流量,不需要再逐个加黑名单。

Q:日志里全是失败登录,是不是已经被黑了?
不一定。失败登录只是"有人在试",不代表试成功了。要结合成功登录记录、异常进程、新增公钥、异常定时任务一起看。只有出现这些红线信号,才按已被入侵处理。没有的话,就是常规暴露面问题。

Q:关掉密码登录后,是不是就完全不怕扫描了?
能大幅降低风险,但不是"完全不怕"。公钥认证也有其自身的注意事项(比如私钥保管),而且其他端口背后的服务仍可能有各自的问题。它是一个重要加固点,不是终点。配合端口最小化和访问控制才完整。

Q:怎么在不惊动业务的前提下停用一个服务?
先在非生产环境验证、或选业务低峰期操作;停用前用 ss -lntp 确认端口确实没业务在依赖;停用后观察一段时间应用日志和监控,确认无异常再禁止开机自启。记下 systemctl enable --now <服务名> 作为回滚命令。

Q:防火墙日志看不过来怎么办?
靠工具而不是靠人眼。用 Fail2ban 自动处理认证失败,用日志聚合或监控系统把失败登录、异常连接做成指标和告警。人工只需要看聚合后的 Top 榜和趋势,不需要逐行读原始日志。

总结

被扫描是公网服务器的常态,不等于被入侵。把心态放平,把动作放对,比惊慌失措有用得多。

识别的关键在几个地方:ss -antp 看连接与状态、按远端 IP 聚合找异常来源、/var/log/secure 或 auth.log 看失败登录、防火墙日志看被拦下的探测。几刀下去,是噪声还是有风险,基本就清楚了。

判断的核心是"暴露面":扫描打在本来就该开放的端口上是噪声,打在不该开放的后端服务上是风险。把监听地址、认证强度、版本信息这三项查一遍,就知道自己到底怕不怕扫。

防护的顺序是从外到内:安全组最小化、主机防火墙默认拒绝、服务绑内网并加强认证、Fail2ban 自动封禁。每一层都不复杂,叠起来就是纵深。

最后一条纪律:任何收紧防火墙或停服务的操作,先验证新通道、留好回滚命令、备好控制台入口。防守做得再严,也不能把自己关在门外。