在Nginx反向代理配置中,基于HTTP请求方法和请求头实现访问控制(ACL)是常见的需求。下面我将详细介绍如何配置这些规则。
location /api/ {
# 只允许GET和POST方法
if ($request_method !~ ^(GET|POST)$ ) {
return 405; # Method Not Allowed
}
proxy_pass http://backend;
}
location /admin/ {
# 拒绝TRACE和TRACK方法
if ($request_method ~ ^(TRACE|TRACK)$ ) {
return 403;
}
# PUT/DELETE方法需要额外验证
if ($request_method ~ ^(PUT|DELETE)$ ) {
# 这里可以添加额外的验证逻辑
# 例如检查特定请求头
set $allow_method N;
if ($http_x_api_key = "your-secret-key") {
set $allow_method Y;
}
if ($allow_method = N) {
return 403;
}
}
proxy_pass http://backend;
}
location /secure/ {
# 检查是否存在Authorization头
if ($http_authorization = "") {
return 401; # Unauthorized
}
# 检查特定的自定义头
if ($http_x_custom_header != "expected-value") {
return 403;
}
proxy_pass http://backend;
}
location / {
# 阻止已知的恶意User-Agent
if ($http_user_agent ~* (wget|curl|libwww-perl|nikto|sqlmap) ) {
return 403;
}
# 只允许特定浏览器的访问
if ($http_user_agent !~* (chrome|firefox|safari) ) {
return 403;
}
proxy_pass http://backend;
}
location /admin-api/ {
# 组合多个条件
set $deny_access N;
# 条件1: 方法不是POST
if ($request_method != POST) {
set $deny_access "${deny_access}1";
}
# 条件2: 缺少X-API-Key头
if ($http_x_api_key = "") {
set $deny_access "${deny_access}2";
}
# 条件3: Content-Type不是application/json
if ($http_content_type != "application/json") {
set $deny_access "${deny_access}3";
}
# 如果任一条件满足(字符串包含1,2或3)
if ($deny_access ~ [123]) {
return 403;
}
proxy_pass http://backend;
}
# 定义允许的User-Agent映射
map $http_user_agent $allowed_agent {
default 0;
"~*chrome" 1;
"~*firefox" 1;
"~*safari" 1;
}
# 定义允许的方法映射
map $request_method $allowed_method {
default 0;
"GET" 1;
"POST" 1;
"OPTIONS" 1;
}
server {
location / {
# 使用map变量进行判断
if ($allowed_agent = 0) {
return 403 "Forbidden User-Agent";
}
if ($allowed_method = 0) {
return 405 "Method Not Allowed";
}
proxy_pass http://backend;
}
}
避免过度使用if指令:Nginx中的if指令有性能开销,特别是在location块中
优先使用map指令:对于复杂的条件判断,map指令通常更高效
考虑使用auth_request:对于复杂的授权逻辑,可以使用auth_request
指令委托给专门的认证服务
合理使用return:根据场景返回适当的HTTP状态码(403 Forbidden, 401 Unauthorized, 405 Method Not Allowed等)
记录拒绝的请求:考虑添加访问日志记录被拒绝的请求,便于安全审计
log_format blocked '$remote_addr - $remote_user [$time_local] '
'"$request" $status "$http_user_agent"';
server {
location / {
if ($deny_access ~ [123]) {
access_log /var/log/nginx/blocked.log blocked;
return 403;
}
}
}
通过以上配置,您可以灵活地实现基于HTTP请求方法和请求头的访问控制,保护您的反向代理服务。