Apache2反向代理:配置每次请求触发脚本进行请求校验
解决Apache反向代理前置CGI检查的问题
1. 先修复CGI脚本不执行的问题
你当前配置直接Rewrite到本地文件路径/usr/local/bin/throttle.cgi,Apache会把它当作静态文件返回内容,而非执行脚本。需要利用ScriptAlias映射的路径触发CGI执行:
修改Rewrite规则
将原RewriteRule改为指向/cgi-bin/throttle.cgi,同时保留原始请求的路径和查询参数:
RewriteEngine On RewriteRule ^(.*)$ /cgi-bin/throttle.cgi?$1 [QSA,L]
QSA:保留原始请求的查询字符串,传递给CGI脚本L:停止后续Rewrite规则处理
确保脚本满足执行条件
- 脚本开头添加正确的shebang,示例:
#!/usr/bin/env python3 - 给脚本添加可执行权限:
chmod +x /usr/local/bin/throttle.cgi - 确保Apache已启用
mod_cgi或mod_cgid模块(容器内执行a2enmod cgi后重启httpd)
2. 调整代理逻辑,让CGI脚本控制转发
脚本需要完成两个核心动作:检查请求合法性,通过则转发到后端,否则返回拒绝响应。以下是Python脚本示例:
#!/usr/bin/env python3 import os import sys import requests # 获取原始请求信息 request_method = os.environ.get('REQUEST_METHOD') request_path = os.environ.get('PATH_INFO', '') query_string = os.environ.get('QUERY_STRING', '') full_backend_url = f"https://www.example.com{request_path}" if query_string: full_backend_url += f"?{query_string}" # 提取请求头(Apache将请求头转为HTTP_*格式的环境变量) request_headers = {} for key, value in os.environ.items(): if key.startswith('HTTP_'): header_name = key[5:].replace('_', '-').title() request_headers[header_name] = value # 读取请求体(仅POST/PUT等方法需要) request_body = sys.stdin.read() if request_method in ['POST', 'PUT'] else None # 自定义检查逻辑,根据需求修改 def validate_request(): # 示例:检查特定请求头是否存在 if 'X-Auth-Token' not in request_headers: return False # 可添加查询参数、请求体内容等检查逻辑 return True # 执行检查 if not validate_request(): print("Status: 403 Forbidden") print("Content-Type: text/plain") print() print("Request rejected by validation check") sys.exit() # 检查通过,转发请求到后端 try: backend_response = requests.request( method=request_method, url=full_backend_url, headers=request_headers, data=request_body, allow_redirects=False ) # 将后端响应返回给客户端 print(f"Status: {backend_response.status_code} {backend_response.reason}") for key, value in backend_response.headers.items(): print(f"{key}: {value}") print() sys.stdout.write(backend_response.content) except Exception as e: print("Status: 500 Internal Server Error") print("Content-Type: text/plain") print() print(f"Failed to forward request: {str(e)}")
注意事项
- 容器内需要安装
requests库:pip install requests(可在Dockerfile中添加该安装步骤)
3. 最终Apache配置
<VirtualHost *:80> ErrorLog "/var/log/apache2/proxy-error.log" CustomLog "/var/log/apache2/proxy-access.log" common ScriptAlias /cgi-bin/ /usr/local/bin/ ProxyRequests Off SSLProxyEngine On SSLProxyCheckPeerCN on SSLProxyCheckPeerExpire on # 注释原直接代理规则,由CGI脚本负责转发 # ProxyPass "/" "https://www.example.com/" # ProxyPassReverse "/" "https://www.example.com/" RewriteEngine On RewriteRule ^(.*)$ /cgi-bin/throttle.cgi?$1 [QSA,L] <Location "/cgi-bin/"> AllowOverride None Options +ExecCGI Require all granted </Location> </VirtualHost>
内容的提问来源于stack exchange,提问作者mhaken
相关产品推荐
相关产品推荐

