在服务器安全里,黑名单和白名单是最容易被混为一谈的一对概念。很多人会说"我把这个 IP 拉黑了""我加了白名单",但问到两者的本质区别、安全强度谁更高、什么时候该用哪个,答案往往就模糊了。而这恰恰是访问控制里最基础也最要命的一环:用错了方向,要么漏掉大量风险,要么把自己的正常用户和管理员都挡在门外。
这篇文章要把这对概念彻底讲清楚:黑名单和白名单的本质区别是什么、为什么白名单的安全强度一定更高、它们各自怎么在主流工具里实现、两者同时存在时谁先谁后、以及在真实场景里该怎么组合使用。文章会给出 firewalld、nftables、ipset、云安全组、Nginx、Fail2ban 这几套常见实现的具体配置,命令区分 RHEL/CentOS/Rocky 与 Debian/Ubuntu 两套。
所有内容都是防御与运维视角:教你如何缩小自己的可访问范围、限制谁能连进来,不涉及任何探测或绕过他人访问控制的做法。
一、本质区别:默认允许与默认拒绝
黑名单和白名单的区别,一句话就能说清,但要真正理解它,得从"默认策略"这个角度切入。
黑名单(deny list / blacklist)是"默认允许,显式拒绝":除了你明确列出来的坏家伙,其他所有来源都放行。它的思维是"我先假设大家都没问题,发现了问题再加进去"。
白名单(allow list / whitelist)是"默认拒绝,显式允许":除了你明确列出来的可信来源,其他所有来源一律拒绝。它的思维是"我先假设所有人都有问题,只有证明可信的才放进来"。
这两个默认值的方向相反,带来的是根本性的安全差异。黑名单有个天然缺陷:你只能封住"已知的坏",而"未知的坏"永远在你允许的范围里。攻击者的 IP 每天都在变,你今天封了 100 个,明天他换 100 个新 IP 就绕过了。所以黑名单本质上是"事后补救",你总是在追着威胁跑。
白名单则相反:它把"未知"归入了拒绝一侧。任何没被你明确信任的东西,无论它是好是坏,都进不来。所以白名单是"事前预防",你不需要知道威胁长什么样,只要它不在可信清单里,就自动被挡住。这就是为什么安全上普遍说"白名单比黑名单强"——不是因为它更复杂,而是因为它的默认值更保守。
用一张表把这个对比摆清楚。
| 维度 | 黑名单 | 白名单 |
|---|---|---|
| 默认策略 | 允许(放行未列出的) | 拒绝(拦截未列出的) |
| 思维模式 | 已知威胁才拦 | 未知一律拦 |
| 安全强度 | 较低(依赖情报/事后) | 较高(默认保守) |
| 维护成本 | 需要持续更新威胁列表 | 只需维护可信列表 |
| 误伤风险 | 低(放行面大) | 高(可能挡住合法用户) |
| 典型用途 | 封禁已知恶意来源 | 保护管理入口、敏感接口 |
| 能否挡住未知攻击 | 不能 | 能 |
从这张表能看出一个重要的权衡:白名单安全性高,但误伤风险也高。如果你的白名单漏掉了一个本该允许的 IP,那个用户就直接被拒之门外。所以白名单更适合"可信来源明确且数量有限"的场景,比如管理后台、数据库、SSH,而不适合"面向大众开放"的业务端口——你不可能把全世界的用户 IP 都列进白名单。
二、黑名单怎么实现
黑名单的典型用法是"封禁已知的恶意 IP"。它在各个层面的实现都很直接。
在 firewalld 里,可以用 rich rule 的 drop 或 reject 来封禁单个 IP 或网段。
# RHEL / CentOS / Rocky:用 firewalld 封禁某个 IP
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.99" drop'
sudo firewall-cmd --reload
# 封禁整个网段
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.0/24" drop'
sudo firewall-cmd --reload
# 查看已配置的 rich rule
sudo firewall-cmd --list-rich-rules
# 解除封禁
sudo firewall-cmd --permanent --remove-rich-rule='rule family="ipv4" source address="203.0.113.99" drop'
sudo firewall-cmd --reload
drop 和 reject 的区别值得留意:drop 是静默丢弃,对方感觉像是丢包,不给你任何反馈;reject 则会回一个拒绝报文,对方立刻知道被拒了。安全场景通常用 drop,因为它不暴露"这里有个防火墙在挡你"。
在更底层的 nftables 里,可以建一个专门的"黑名单集合",把要封的 IP 放进去,规则一次性引用集合,效率更高。
# nftables:创建黑名单集合并封禁
sudo nft add table inet filter
sudo nft add set inet filter blacklist { type ipv4_addr\; }
sudo nft add rule inet filter input ip saddr @blacklist drop
# 往集合里加 IP
sudo nft add element inet filter blacklist { 203.0.113.99, 203.0.113.100 }
# 查看集合内容
sudo nft list set inet filter blacklist
在 Debian/Ubuntu 上用 ufw 封禁也很简单:
# Debian / Ubuntu:用 ufw 封禁
sudo ufw deny from 203.0.113.99
sudo ufw deny from 203.0.113.0/24
# 查看状态
sudo ufw status numbered
# 删除规则(按编号)
sudo ufw delete <编号>
在应用层,Nginx 可以用 deny 指令封禁来源:
# Nginx:拒绝某 IP/网段
server {
deny 203.0.113.99;
deny 203.0.113.0/24;
# 批量黑名单可以写进单独文件,用 include 引入
# include /etc/nginx/blacklist.conf;
}
而 Fail2ban 则是黑名单的"自动化版本":它不用你手工维护列表,而是根据日志自动把反复失败尝试的 IP 加进封禁。这是黑名单最实用的一种落地方式。
# 查看 Fail2ban 当前封禁了谁(本质是自动维护的黑名单)
sudo fail2ban-client status sshd
黑名单的维护难点在于"更新"。手工维护必然滞后,所以实践中黑名单往往和自动化(Fail2ban)、情报源(威胁情报 IP 库)结合使用。但无论怎么更新,它的根本局限不变:永远落后于变化的威胁。
三、白名单怎么实现
白名单的配置方向和黑名单相反,重点在"默认拒绝 + 显式允许"。
在 firewalld 里,可以用 rich rule 的 accept 只放行可信来源,配合区域(zone)的默认策略。firewalld 的 trusted 区域概念本身就是一种白名单思路:只有指定来源被信任。
# RHEL / CentOS / Rocky:只允许某个网段访问 SSH,其余拒绝
# 先确保默认区域不直接放行 ssh 服务,再用 rich rule 精确放行可信来源
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
# 把可信来源加进 trusted 区域(该区域默认全部放行)
sudo firewall-cmd --permanent --zone=trusted --add-source=198.51.100.0/24
sudo firewall-cmd --reload
在 ufw 里,白名单通过"默认拒绝 + 允许指定来源"实现:
# Debian / Ubuntu:默认拒绝所有入站,只放行可信来源
sudo ufw default deny incoming
sudo ufw default allow outgoing
# 只允许某网段访问 SSH
sudo ufw allow from 198.51.100.0/24 to any port 22 proto tcp
# 只允许某 IP 访问数据库端口
sudo ufw allow from 192.0.2.15 to any port 3306 proto tcp
sudo ufw enable
sudo ufw status verbose
用 ipset 或 nftables 的集合做白名单,适合"可信来源很多、需要高效匹配"的场景:
# 用 ipset 建白名单集合(需 ipset 包)
# RHEL 系:sudo dnf install ipset;Debian/Ubuntu:sudo apt install ipset
sudo ipset create whitelist hash:net
sudo ipset add whitelist 198.51.100.0/24
sudo ipset add whitelist 192.0.2.15
# 只放行白名单来源访问 22 端口,其余丢弃
sudo iptables -A INPUT -p tcp --dport 22 -m set --match-set whitelist src -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j DROP
应用层的白名单在 Nginx 里用 allow 加 deny all 组合实现:
# Nginx:只允许指定来源访问管理接口
location /admin/ {
allow 198.51.100.0/24;
allow 192.0.2.15;
deny all; # 注意:deny all 必须在最后
}
Nginx 的 allow/deny 是按顺序匹配的,遇到第一条匹配就生效,所以 deny all 必须放在最后作为兜底。把白名单写成"放行可信、拒绝其余"的顺序,才符合白名单的默认拒绝语义。这里如果顺序写反,把 deny all 放在前面,那所有请求都会被拒。
四、白名单适配的场景:管理入口与敏感服务
白名单安全强度高,但它有个前提:可信来源必须明确。这就决定了它最适合以下几类场景。
第一,服务器管理入口。SSH、Web 控制台、数据库管理界面这些入口,理论上只有你自己和团队会用。把来源限制在办公网段、跳板机 IP、VPN 出口,就能把这些入口从"对全网开放"变成"只对你开放"。这是白名单价值最大的地方——它能挡住 99% 以上的自动化扫描和爆破,因为这些尝试无一来自你的白名单。往往只需这一条,管理入口的安全性就有质的提升。
第二,数据库和内部服务。数据库、缓存、消息队列这些后端服务,本来就应该只允许应用服务器访问。把来源锁定为应用服务器的内网 IP,就是最标准的白名单用法。
第三,接口调用的对端限制。有些对外接口只服务于固定的合作方,这时候用白名单限定对方的出口 IP 是很自然的做法。
第四,敏感操作的二次限制。比如后台的某些高危操作页面,除了登录认证,再加一层 IP 白名单,形成"谁知道密码也未必进得来"的双保险。
# 典型组合:数据库只允许应用服务器内网 IP 访问
# 服务器侧绑定内网地址 + 防火墙只放行应用服务器
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.1.20" port port="3306" protocol="tcp" accept'
# 同时确保没有对其他来源放行 3306
sudo firewall-cmd --list-rich-rules
需要注意的是:白名单的维护成本比黑名单高。人员变动、办公 IP 变化、新增服务器,都要记得更新白名单,否则就会出现"我把自己锁在门外"或者"新同事连不上"的问题。所以白名单要配合清晰的文档和变更流程,别让它变成只有某个人知道怎么改的"黑盒"。
五、优先级与组合:两个同时存在时听谁的
现实中,黑名单和白名单常常同时存在。这时一个必须搞清楚的问题是:它们的优先级是什么?
通用的原则是:白名单优先于黑名单。也就是说,如果一个来源既匹配白名单又匹配黑名单,通常以白名单为准(放行)。理由是:白名单代表"明确信任",是经过确认的可信来源;如果一个 IP 同时上了两个列表,说明存在配置冲突,这时候让可信列表优先,避免误伤可信来源。不过,这个规则并非所有工具都精确遵循,具体行为要看实现。比如 Nginx 的 allow/deny 完全靠书写顺序决定,谁在前谁先匹配,所以顺序就是一切。
更稳妥的做法是避免让同一个 IP 同时出现在两个列表里,也就是让"信任"和"封禁"两个集合互斥。维护时如果一个 IP 要上白名单,先从黑名单里移除;反之亦然。这样就不用纠结优先级了。
常见的组合模式有两种。第一种是"管理入口用白名单、公网业务用黑名单"。这是最经典也最平衡的搭配:SSH、数据库、控制台这些入口用白名单严格限制,对外网站这种面向大众的服务则用黑名单+限流来过滤已知的恶意来源。这样既保证了核心入口的安全,又不影响正常用户的访问。
第二种是"全局默认拒绝 + 分层放行"。安全组和主机防火墙都设默认拒绝,然后按"业务需要"逐条放行。放行规则里,面向公众的端口以来源不限+应用层防护为主,管理类端口以来源白名单为主。这一套其实就是把白名单思想用在了整台服务器上。
# 一个组合示例(思路演示)
# 1) 默认拒绝所有入站(白名单思维)
sudo firewall-cmd --set-default-zone=drop
# 2) 放行公网业务端口(面向大众,用黑名单/限流在应用层处理)
sudo firewall-cmd --permanent --add-port=443/tcp
# 3) SSH 只放行可信来源(白名单)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="198.51.100.0/24" service name="ssh" accept'
# 4) 对已知恶意来源额外 drop(黑名单,可选)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.0/24" drop'
sudo firewall-cmd --reload
风险提示:执行 firewall-cmd --set-default-zone=drop 或类似的"默认拒绝"操作前,必须先确认所有必要的端口(尤其是你当前登录用的 SSH)都已放行、你的来源 IP 在白名单里,否则会立刻切断自己的连接。回滚方式:sudo firewall-cmd --set-default-zone=public 恢复默认区域,或 sudo systemctl stop firewalld 临时关闭。操作时保留云控制台入口。
六、最佳实践与常见误区
先说几条最佳实践。
第一,管理入口一律用白名单。这是投入产出比最高的一条。SSH、数据库、控制台限制来源后,绝大多数自动化攻击会自动消失,日志也会清爽很多。
第二,公网业务用默认拒绝 + 精确放行 + 应用层防护。面向大众的 80/443 用黑名单和限流处理,不要把白名单用在面向公众的入口上——那会挡住正常用户。
第三,优先用"默认拒绝"这个总开关。与其维护一个越来越长的黑名单,不如把默认策略设成拒绝,然后只放行必要的。默认拒绝本身就是白名单思想的体现,而且不需要你枚举坏人。
第四,黑名单要自动化,别手工维护。手工黑名单必然滞后且容易出错。用 Fail2ban 这类工具根据日志自动封禁,或定期同步威胁情报,比人工逐个添加有效得多。
第五,两个列表保持互斥,变更留记录。谁在什么时候因为什么加了哪条规则,都要可追溯。这既方便排查,也避免规则腐化成一堆没人敢删的历史遗留。
再说几个常见误区。
误区一:以为封了几个 IP 就安全了。黑名单只能封已知的坏,攻击者换 IP 就绕过。它的定位是"降低噪声",不是"安全屏障"。
误区二:把白名单当成万能方案。白名单安全性高,但维护成本和误伤风险也高。它适合可信来源明确的场景,硬套到面向公众的业务上只会带来麻烦。
误区三:忽略了规则顺序。在 Nginx、iptables 这类按顺序匹配的工具里,规则顺序决定结果。把 deny all 写在 allow 前面,等于白名单全部失效。写完一定要按真实来源测试。
误区四:只配了一层。安全组、主机防火墙、应用层是三层独立的东西。只配其中一层就以为万无一失,是常见的疏漏。三层都配置且思路一致,才是完整的纵深防御。
误区五:忘了给自己留退路。加白名单、设默认拒绝这类操作,风险在于可能把管理员自己挡住。永远保留云控制台入口和回滚命令,改配置时留着已有连接,验证新连接通过后再切断。
常见问题
Q:白名单和黑名单能同时给一个 IP 配吗?
技术上可以,但行为取决于工具。多数工具让白名单优先(放行),但 Nginx 这类按顺序匹配的完全看书写顺序。最稳妥的做法是让两个列表互斥,一个 IP 只出现在其中一个里,这样就不用猜优先级。
Q:服务器面向公众的 80/443 能不能用白名单?
一般不能。你不知道访问网站的用户 IP,无法枚举成白名单。这种情况下应该用"默认拒绝其他端口 + 放行 80/443 + 应用层黑名单/限流"的组合,而不是对 80/443 做接来源白名单。
Q:办公 IP 不固定,白名单怎么配?
两个办法。一是白名单整个运营商网段(不够精确,谨慎使用);二是用 VPN,给管理人员分配固定出口,把 VPN 出口地址加进白名单。后者的安全性和可控性都更好,是推荐做法。
Q:黑名单封了 IP,对方换 IP 怎么办?
这正是黑名单的固有局限。应对方式是让黑名单自动化(Fail2ban 自动封新的尝试来源)、并把重点放在"默认拒绝 + 白名单"上,从"追着封"转为"默认不让进"。
Q:云安全组和主机防火墙,白名单配哪个?
两个都配,且保持一致。云安全组在外层,即使服务器系统未启动也在生效;主机防火墙在内层,能做更精细的控制。两层叠加是纵深防御,不是冗余。
总结
黑名单是"默认允许、显式拒绝",白名单是"默认拒绝、显式允许"。默认值的差异,决定了白名单的安全强度天然高于黑名单——它能挡住未知威胁,而黑名单只能挡住已知的。
实现层面,firewalld 的 rich rule、nftables/ipset 的集合、云安全组、Nginx 的 allow/deny、Fail2ban 的自动封禁,都是这套思路的具体落地。工具不同,但"默认策略 + 例外列表"的骨架一致。
选型的核心原则是看场景:管理入口、数据库、内部服务这些"可信来源明确"的场景用白名单,安全收益最大;面向公众的业务端口用默认拒绝配合应用层黑名单与限流,才不至于挡住正常用户。
两者同时存在时,多数工具让白名单优先,但 Nginx 这类按顺序匹配的工具完全靠书写顺序,所以要么保证列表互斥,要么把规则顺序写对并测试。
最后一条纪律:任何"默认拒绝"或"白名单"的改动,都可能把你自己挡在门外。先放行、再验证、留退路、备回滚,是访问控制里永远不变的操作准则。
企业QQ咨询




