1. 为什么需要控制HTTP方法?

HTTP协议定义了GET、POST、PUT、DELETE等十余种方法,但实际业务中往往只需开放部分方法。例如:

  • 静态资源服务器仅需GET
  • RESTful API需支持GET/POST/PUT/DELETE
  • 文件上传接口可能涉及PATCH

若放任所有方法自由通行,可能带来安全隐患。去年某电商平台就因未限制OPTIONS方法导致CORS漏洞被攻击。通过Nginx精准控制HTTP方法,既能提升安全性,又能规范接口行为。

(示例场景:某API网关需屏蔽TRACE方法)

location /api/ {
    if ($request_method !~ ^(GET|POST|PUT|DELETE)$ ) {
        return 405;
    }
    # 代理到后端服务
    proxy_pass http://backend;
}

注释说明:正则表达式匹配白名单方法,非白名单返回405状态码


2. 原生配置方案详解

2.1 基础方法过滤

通过内置变量$request_method实现基础控制:

# 技术栈:原生Nginx配置
server {
    listen 80;
    server_name api.example.com;
    
    # 全局禁用危险方法
    if ($request_method = TRACE) {
        return 403 "TRACE method not allowed";
    }

    location /v1/users {
        # 仅允许标准REST方法
        if ($request_method !~ ^(GET|POST|PUT|DELETE)$ ) {
            return 405;
        }
        proxy_pass http://user_service;
    }

    location /upload {
        # 文件上传特殊处理
        limit_except POST {
            deny all;
        }
        client_max_body_size 100M;
        proxy_pass http://storage_service;
    }
}

注释说明:limit_except指令专门用于方法限制,比正则更高效


2.2 高级条件判断

处理OPTIONS预检请求:

# 技术栈:原生Nginx配置
location /api/ {
    if ($request_method = OPTIONS) {
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type';
        return 204;
    }
    
    # 其他方法处理逻辑...
}

注释说明:CORS预检请求需特殊处理,返回204而非200


3. 扩展方案:Lua脚本增强

当需要动态逻辑时,OpenResty方案更灵活:

# 技术栈:OpenResty
location /dynamic-api {
    access_by_lua_block {
        local allowed_methods = {
            GET = true,
            POST = true,
            HEAD = true
        }
        
        if not allowed_methods[ngx.req.get_method()] then
            ngx.exit(ngx.HTTP_METHOD_NOT_ALLOWED)
        end
        
        -- 从Redis读取动态规则
        local redis = require "resty.redis"
        local red = redis:new()
        red:connect("127.0.0.1", 6379)
        local forbidden = red:get("method_lock:"..ngx.var.uri)
        if forbidden == ngx.req.get_method() then
            ngx.exit(ngx.HTTP_FORBIDDEN)
        end
    }
}

注释说明:Lua脚本实现动态规则加载和复杂逻辑判断


4. 技术方案对比

方案 优点 缺点 适用场景
原生配置 零依赖、高性能 仅支持简单逻辑 静态规则、简单过滤
Lua扩展 支持动态规则、复杂逻辑 需要维护OpenResty环境 需要动态更新的复杂场景

5. 避坑指南

  1. 正则陷阱if ($request_method ~* "get|post")会意外匹配到非标准方法如"getfile"
  2. 性能影响:频繁的Lua脚本执行可能增加5%~15%的延迟
  3. 状态码选择:405需配合Allow头才符合RFC规范:
add_header Allow "GET, HEAD" always;
  1. 日志优化:建议单独记录非法方法请求:
map $request_method $loggable {
    default 1;
    TRACE   0;
    OPTIONS 0;
}

access_log /var/log/nginx/access.log combined if=$loggable;

6. 实战配置案例

综合应用场景:物联网设备API网关

# 技术栈:Nginx + Lua
http {
    lua_shared_dict method_rules 10m;
    
    server {
        listen 8888;
        
        location /device {
            access_by_lua_block {
                local method = ngx.req.get_method()
                local uri = ngx.var.uri
                
                -- 从共享字典读取缓存规则
                local rules = ngx.shared.method_rules
                local cache_key = uri .. "_methods"
                local allowed = rules:get(cache_key)
                
                if not allowed then
                    -- 首次请求时从数据库加载
                    allowed = fetch_method_rules_from_db(uri)
                    rules:set(cache_key, allowed, 60) -- 缓存60秒
                end
                
                if not allowed:find(method) then
                    ngx.exit(ngx.HTTP_METHOD_NOT_ALLOWED)
                end
            }
            
            proxy_pass http://iot_backend;
        }
    }
}

注释说明:通过共享字典实现规则缓存,避免频繁查库


7. 总结与展望

现代Web服务对HTTP方法的精细化控制已成为安全防护的重要环节。Nginx在此场景中展现出:

  • 原生配置方案简单高效,适合规则稳定的场景
  • Lua扩展方案灵活强大,适合需要动态控制的场景
  • 组合使用可构建多层级防护体系

未来趋势预测:

  1. 自动生成方法白名单的AI模型
  2. 与WAF联动的动态规则引擎
  3. 基于QUIC协议的HTTP/3方法控制