openresty、nginx 拦截非法请求, referer模块 ngx_http_referer_module

referer模块 ngx_http_referer_module 默认编译进nginx

valid_referers 指令

官网可参考 http://nginx.org/en/docs/http/ngx_http_referer_module.html#valid_referers

| Syntax: | valid_referers none | blocked | server_names | string ...; |
|–|–|
|Default: | — |
|Context: | server, location|

参数说明

none 允许缺失referer头部请求访问

block 允许有referer头部请求访问

server_names 如果server_names与本机server_name某个域名匹配则允许访问

正则表达式  匹配上允许访问

域名前缀或后缀匹配上 也允许访问

invalid_referer 变量 允许访问时值是空 不允许访问时值是空	

referer_hash_bucket_size 缓存

referer_hash_max_size 缓存最大值

示例:

拦截1–指定拦截

server {
    server_name xxx.xxxx.com;

    error_log logs/myerror.log debug;
    root html;
    location /{
        valid_referers none blocked server_names
                       *.555.pub www.404.cn/nginx/
                       ~\.google\.;

        if ($invalid_referer) {
                return 403;
        }

        return 200 'valid\n';
    }

}
拦截来着百度搜索的请求

返回404
if ($http_referer ~ 'baidu.com')
{
    return 404;
}

或者

返回跳转页面
if ($http_referer ~ 'baidu.com')
{
    return 200 "<html><script>window.location.href='//$host$request_uri';</script></html>";
}

拦截2–空拦截

为空访问返回不存在

valid_referers server_names ~.;
if ($invalid_referer) {
    #return   403;
    root html;
}

综合示例

location /nacos/ {
 set $flag 0;
    if ($remote_addr !~ ^(10.0.37.155|10.0.37.154|10.0.37.156|10.0.37.162|10.0.37.163|10.0.37.164|10.0.37.165|10.0.37.157|10.0.37.158)) {set $flag 1;}
    if ($host ~ "^hn8.nw109.cc1*$") {set $flag 0;}
    if ($flag = 1) {return 403;}
    proxy_pass http://nacosserv;
  }
  error_page 403 /403page.html;
  location = /403page.html{
      root html;
  }
<think>嗯,用户现在的问题是关于如何从NginxReferer头中解析出特定的路径部分,比如他们给出的例子是http://ai-webapi.bpmhome.cn:8001/8001/gpustack/,想要提取出8001/gpustack/这部分。我需要先理解用户的具体需求,然后思考Nginx中可以实现的方法。 首先,用户已经知道如何获取Referer,现在的问题是如何解析其中的路径部分。在之前的回答中,我提到了使用Nginx的内置变量和正则表达式来提取信息。用户可能是在处理防盗链、流量分析或者动态内容调整时,需要根据Referer的路径来做不同的处理。比如,根据不同的路径段来路由请求或者记录日志。 接下来,我需要考虑Nginx的配置方法。Nginx的map指令和正则表达式是处理这类问题的常用工具。此外,可能需要使用if语句或者ngx_http_lua_module模块来更灵活地处理字符串。用户给出的例子中,Referer的URL结构明确,端口号后的路径部分是需要提取的,所以需要从URL中截取端口号后的路径。 首先,分析URL的结构:http://ai-webapi.bpmhome.cn:8001/8001/gpustack/。这里,主机部分是ai-webapi.bpmhome.cn:8001,路径是/8001/gpustack/。用户需要提取的是端口后的路径部分,即8001/gpustack/。但是注意到端口号是8001,而路径的第一个目录也是8001,这可能是一个重复或者特定的结构,用户可能希望动态提取端口后的路径,而不管端口号是什么。 可能的解决方法是使用正则表达式匹配Referer中的路径部分。例如,匹配http://或https://开头,接着是域名和端口,然后捕获端口后面的路径部分。正则表达式可以写成^https?://[^/]+:[0-9]+/(.*)$,这样捕获组1就是端口后的路径。但需要考虑是否有端口的情况,比如有些URL可能没有显式端口(如默认的80或443)。所以可能需要更灵活的正则表达式,例如^https?://[^/]+(:[0-9]+)?/(.*)$,这样无论有没有端口都能匹配,并且捕获路径部分。 然后,在Nginx中如何实现这个正则匹配。Nginx的map指令可以用于将变量映射到另一个变量,结合正则表达式来提取路径。另外,也可以使用if语句结合capture groups,但需要注意if的局限性,比如作用域问题。或者使用Lua模块来更灵活地处理字符串,但用户可能没有安装该模块,所以可能需要给出两种方案:一种是纯Nginx配置,另一种需要Lua支持。 比如,使用map指令: map $http_referer $referer_path { default ""; ~*^https?://[^/]+(:[0-9]+)?/(?<path>.*)$ $path; } 这样,$referer_path变量就会被赋值为路径部分。但需要注意Nginx的正则语法是否支持命名捕获组,实际上Nginx的map指令使用的是PCRE正则,支持命名捕获组,但可能需要使用变量名来引用,比如使用$1而不是命名组。可能需要调整正则表达式,使其正确捕获路径部分。 例如,正则表达式可以调整为~*^https?://[^/]+(:[0-9]+)?/(.*)$,然后捕获组$1即为路径部分。然后在map指令中将$1赋值给$referer_path变量。 但map指令中的正则匹配如果成功,默认会将第一个捕获组的值赋给变量。所以可以这样写: map $http_referer $referer_path { ~^https?://[^/]+(:[0-9]+)?/(.*)$ $2; default ''; } 这里,正则表达式中的第二个捕获组(.*)对应$2,因为第一个捕获组是(:[0-9]+)?部分,可能为空。所以用户需要的是端口后面的路径,不管端口是否存在,所以需要正确捕获路径部分。例如,http://example.com:8001/path/to/resource,那么$1是:8001,$2是path/to/resource。而如果是http://example.com/path/to/resource,则$1不存在,$2是path/to/resource。但这样,当URL中没有端口时,第二个捕获组是否会正确捕获?可能需要调整正则表达式,使得端口部分是可选的,并且路径部分正确捕获。 可能更好的正则表达式是^https?://[^:/]+(:\d+)?/(.*)$,这样,主机名部分不能包含端口分隔符,然后端口是可选的,后面跟着路径。这样,捕获组1是端口部分,捕获组2是路径。因此,在map中,我们需要获取$2作为路径。但用户案例中的路径是8001/gpustack/,而端口是8001,这可能造成混淆,但用户的需求是获取端口后的路径,不管端口是什么,所以这个方法是可行的。 但是,在用户给出的例子中,路径的第一个目录和端口号相同,这是否是普遍情况?用户可能希望无论端口是什么,都获取端口后的路径部分,而不管端口号是否存在。因此,正则表达式应该能够处理有端口和无端口的情况,正确捕获路径部分。 另一种方法是使用Lua脚本,通过ngx.var.http_referer获取Referer,然后用字符串处理函数分割出路径部分。这需要Nginx安装了ngx_http_lua_module模块。例如: location / { access_by_lua_block { local referer = ngx.var.http_referer if referer then local _, _, path = string.find(referer, "^https?://[^/]+(:%d+)?/(.*)") ngx.var.referer_path = path or "" end } } 这样,path变量就是端口后的路径部分。这种方法更灵活,但需要Lua支持。 总结下来,用户的问题需要从Referer中提取端口后的路径部分,可以有两种方法:使用Nginx的map指令和正则表达式,或者使用Lua模块。需要根据用户的实际环境和需求选择合适的方法。此外,还需要考虑Referer可能不存在的情况,或者格式不正确的情况,设置默认值。 最后,在回答中需要给出具体的配置示例,并解释每一步的作用,确保用户能够理解并正确应用。同时,提醒用户注意正则表达式的编写和测试,确保匹配正确,避免因为正则错误导致提取失败。</think>--- ### 一、核心解决思路 要从Referer中提取路径部分(如 `http://ai-webapi.bpmhome.cn:8001/8001/gpustack/` → 获取 `8001/gpustack/`),需通过 **正则表达式匹配** 或 **字符串截取** 实现。以下是两种Nginx原生方法: --- ### 二、方法1:纯Nginx配置(正则匹配) #### 1. 使用 `map` 指令提取路径 ```nginx # 在http块中定义映射规则 map $http_referer $referer_path { default ""; # 默认值为空 # 正则匹配:捕获端口后的路径部分 ~^https?://[^/]+(:[0-9]+)?/(?<captured_path>.*)$ $captured_path; } # 在server块中使用变量 server { location / { # 将提取的路径存入变量$referer_path add_header X-Referer-Path "$referer_path"; # 可在日志中记录路径 access_log /var/log/nginx/access.log combined ref_path=$referer_path; } } ``` #### 2. 正则解析说明 - **正则表达式分解**: $$ \text{正则:} \quad \verb|^https?://[^/]+(:[0-9]+)?/(.*)$| $$ - `^https?://` → 匹配`http://`或`https://` - `[^/]+` → 匹配域名部分(不含斜杠) - `(:[0-9]+)?` → 可选端口号(如`:8001`) - `/(.*)$` → 捕获端口后的路径(如`/8001/gpustack/`) --- ### 三、方法2:Lua模块高级提取(需安装OpenResty) #### 1. 安装依赖 ```bash # 安装OpenResty(含ngx_http_lua_module) apt-get install openresty ``` #### 2. Nginx配置 ```nginx location / { access_by_lua_block { -- 获取Referer local referer = ngx.var.http_referer if referer then -- 提取路径(忽略协议、域名、端口) local path = string.match(referer, "^https?://[^/]+(:%d+)?/(.*)") -- 存储到变量 ngx.var.referer_path = path or "" end } # 使用变量 add_header X-Referer-Path "$referer_path"; } ``` --- ### 四、验证与调试 #### 1. 测试请求 ```bash # 模拟带Referer请求 curl -H "Referer: http://ai-webapi.bpmhome.cn:8001/8001/gpustack/" http://yourdomain.com ``` #### 2. 查看结果 - **响应头中观察**:检查 `X-Referer-Path` 是否包含 `8001/gpustack/` - **日志验证**:检查日志字段 `ref_path` 的值 --- ### 五、边界情况处理 | 场景 | 解决方案 | |------|----------| | **无Referer** | 通过 `if ($http_referer) { ... }` 过滤空值 | | **非标准URL格式** | 使用更宽松的正则(如 `~*^.*?://[^/]+/(.*)$`) | | **含查询参数** | 在正则中排除 `?`:`/([^?]*)` | --- ### 六、性能优化建议 - **减少正则复杂度**:避免多层嵌套捕获组 - **缓存结果**:对频繁使用的路径值通过 `map` 定义缓存 - **限制匹配范围**:仅在需要的位置(如特定 `location`)启用解析 --- 通过上述方法,可精准提取Referer中的路径部分,适用于 **访问来源追踪**、**动态路由控制** 等场景。建议优先使用Nginx原生方案,若需复杂逻辑再考虑Lua扩展。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值