You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apache 2.4:如何用expr/ipmatch匹配非REMOTE_ADDR的IP头?

CDN后基于HTTP头的IP段封禁解决方案

问题背景

我的Web服务器部署在CloudFront CDN之后,客户端IP通过CloudFront-Viewer-Address HTTP头传递。目前已实现单IP封禁,规则如下:

RewriteCond %{HTTP:CloudFront-Viewer-Address} ^123\.45\.67\.89(.*)$
RewriteRule ^(.*)$ - [F,L]

注:规则里的(.*)$是为了匹配该头中可能包含的端口。访问日志里这个头带端口(比如127.0.0.1:1234),但重写日志里看不到端口。

CGI程序显示的头值示例包含IPv4和IPv6带端口的情况:

HTTP_CLOUDFRONT_VIEWER_ADDRESS --> 0000:0000:0000:0000:0000:0000:0000:0001:52325
HTTP_CLOUDFRONT_VIEWER_ADDRESS --> 127.0.0.1:45629

尝试用-ipmatch封禁IP段(替换变量为%{HTTP:CloudFront-Viewer-Address})失败,不确定是-ipmatch仅支持%{REMOTE_ADDR}还是端口导致匹配失败。

核心原因

-ipmatch要求匹配的是纯IP地址(不含端口),而CloudFront-Viewer-Address头包含端口号(IPv4为IP:端口格式,IPv6为完整IPv6地址:端口格式),直接用该头变量匹配会导致规则失效。

有效解决方案

通过两步Rewrite规则先剥离端口,提取纯IP后再用-ipmatch匹配网段:

通用规则(支持IPv4/IPv6)

# 提取CloudFront-Viewer-Address中的纯IP,存入环境变量VIEWER_IP
RewriteCond %{HTTP:CloudFront-Viewer-Address} ^([^\:]+)(:*.*)$
RewriteRule ^ - [E=VIEWER_IP:%1]

# 匹配目标IP段,返回403 Forbidden
RewriteCond expr "%{ENV:VIEWER_IP} -ipmatch '123.45.67.0/24'"
RewriteRule ^ - [F,L]

规则细节说明

  1. 端口剥离逻辑:
    正则^([^\:]+)(:*.*)$会捕获第一个冒号前的所有内容:
    • 对于IPv4地址(如127.0.0.1:45629),第一个冒号前就是完整的IPv4地址
    • 对于IPv6地址(如0000:0000:0000:0000:0000:0000:0000:0001:52325),最后一个冒号是端口分隔符,前面的部分是完整的IPv6地址,正则会正确捕获到IPv6地址部分
  2. 环境变量传递:用E=VIEWER_IP:%1把捕获的纯IP存入环境变量,后续规则直接调用%{ENV:VIEWER_IP}即可
  3. 网段匹配:-ipmatch支持标准的CIDR格式网段,包括IPv4和IPv6

验证与排查

  • 确保Apache版本为2.4及以上(-ipmatch是Apache 2.4新增的表达式功能)
  • 开启重写日志(在Apache配置中添加RewriteLogLevel 3),查看VIEWER_IP变量是否正确提取了纯IP,以及匹配过程是否正常

扩展:封禁IPv6网段

只需替换-ipmatch后的网段为IPv6 CIDR即可,例如:

RewriteCond expr "%{ENV:VIEWER_IP} -ipmatch '2001:db8::/32'"
RewriteRule ^ - [F,L]

内容的提问来源于stack exchange,提问作者Special Monkey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 00:40:08