Nginx IP 白名单须置于 http/server 块顶层,避免 location 中失效;iptables SSH 限流需先 ACCEPT 再 DROP 并设回滚;@PreAuthorize 仅作业务层角色校验,非边界防护;网关鉴权禁用 X-Forwarded-For 判定角色,须依赖 JWT 或签名透传。
nginx 里用 allow/deny 做 IP 白名单,但别直接写在 location 块里
直接在 location 里写 allow 和 deny 很容易被绕过——比如用户访问 /api/v1/users 被拦了,但顺手试个 /static/xxx.js 就可能漏出敏感配置或内部路径。真正生效的位置是 server 或 http 块顶层,配合 if + return 403 更可控。
常见错误现象:403 Forbidden 出现在不该拦的地方,或者压根不生效。原因往往是作用域错、顺序反(deny all 写太前)、或没加 allow 127.0.0.1 导致本地调试也挂掉。
-
allow和deny按顺序匹配,遇到第一条就停,所以白名单必须写在deny all前面 - IPv6 要单独写
allow ::1,不能靠通配 - 如果用了 CDN 或反向代理,
$remote_addr是代理 IP,得用$http_x_forwarded_for并配合set_real_ip_from才可信
Spring Boot 用 @PreAuthorize 控制角色访问,但别只依赖它做边界防护
@PreAuthorize("hasRole('ADMIN')") 看起来干净,但它只在方法执行前校验,不拦请求头、不防 URL 猜测、也不管静态资源。真要隔离服务器访问,它只是最后一道关,不是第一道。
使用场景:适合保护 API 接口逻辑,比如 /servers/list 返回哪些机器,由后端查 DB 过滤后再返回,而不是前端靠权限隐藏按钮就完事。
- 角色名默认带
ROLE_前缀,写hasRole('ADMIN')实际检查的是ROLE_ADMIN,别漏前缀 -
@PreAuthorize不处理未登录用户,得配合HttpSecurity.authorizeHttpRequests()先设登录要求 - 如果服务器列表来自配置文件或环境变量,权限校验得同步读取对应字段,别硬编码 IP 列表到注解里
Linux iptables 限制 SSH 只允许特定 IP 连服务器,但别忘了保留当前会话
执行 iptables -A INPUT -p tcp --dport 22 -s 203.0.113.5 -j ACCEPT 后立刻 iptables -A INPUT -p tcp --dport 22 -j DROP,很容易把自己锁在外面——尤其是通过跳板机连的,源 IP 不是你本地的。
性能影响几乎为零,但规则顺序和测试方式决定成败。生产环境改之前,先用 at 或 screen 设个自动回滚。
- 务必先加
ACCEPT规则,再加DROP,顺序反了直接失联 - 用
iptables -I INPUT 1 ...插入最前,比-A更稳妥 - 临时放行自己 IP:
iptables -I INPUT 1 -s $(hostname -I | awk '{print $1}') -p tcp --dport 22 -j ACCEPT,再删老规则 - 保存规则用
iptables-save > /etc/iptables/rules.v4(Debian)或service iptables save(CentOS 6),别只内存生效
API 网关层统一鉴权时,X-Forwarded-For 头不可信,必须结合 JWT 或 session 校验角色
只靠请求头里的 X-Forwarded-For 判断用户角色,等于把门禁卡贴在玻璃上——前端能随便伪造。真实系统里,IP 只辅助限流或告警,角色必须来自可信凭证。
典型错误:网关解析 X-Forwarded-For 得到 IP,查内部权限表返回服务器列表,结果攻击者 curl -H "X-Forwarded-For: 192.168.10.100" 直接越权。
- JWT 必须校验
signature和exp,别只 parse 就信任role字段 - session ID 要存 Redis 并设置过期,别用内存 session,扩缩容就丢状态
- 如果后端服务也要二次校验,角色信息建议从网关透传
X-User-Role(签名后),而不是让下游再查一遍 DB
最常被忽略的一点:IP 和角色是两个维度,混在一起控制访问,要么漏(只控 IP 不控角色),要么僵(只控角色不看来源)。真要安全,得在接入层做 IP 粗筛,在业务层做角色细筛,中间用可信凭证串起来。

















