Nginx编译安装more_set_headers模块自定义head头信息

本文介绍如何通过编译添加Nginx的第三方模块more_set_headers来清除或自定义服务器响应头中的敏感信息,提高服务器安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:http://blog.hackroad.com/operations-engineer/linux_server/3264.html

 

通过服务器的head头可以得到服务器的很多信息,这给服务器安全带来很大隐患,如:

HTTP/1.1 200 OK
Server: icson
Date: Thu, 26 Sep 2013 06:43:52 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
X-UA-Compatible: IE=Edge,chrome=1
X-XSS-Protection: 1; mode=block

 

Nginx可以编译添加第三方模块more_set_headers来自定义或清除相关head信息。

cd /usr/local/src/
wget http://nginx.org/download/nginx-1.0.15.tar.gz
tar zxvf nginx-1.0.15.tar.gz
cd nginx-1.0.15
wget -O header.zip --no-check-certificate https://github.com/agentzh/headers-more-nginx-module/zipball/v0.17rc1
unzip header.zip
./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-\
http_ssl_module --with-http_gzip_static_module --add-module=./agentzh-headers-more-nginx-module-3580526/
make && make install

应用示例,清除服务器及php信息,在配置文件http段添加以下:

more_clear_headers "X-Powered-By:";
more_clear_headers "Server:";

重新加载配置文件:

/etc/init.d/nginx reload

查看当前head头信息:

现在nginx及php信息都没了,当然也可自定义为其它信息。

之前我配置了libinjection.so到防火墙上,现在修改我发给你的代码,将modsecurity配置到防火墙上 app.py: from flask import Flask, request, jsonify import ctypes import numpy as np from tensorflow.keras.models import load_model from tensorflow.keras.preprocessing.sequence import pad_sequences import pickle import json from urllib.parse import unquote import html import sys import base64 import re from utils.makelog import log_detection import os import logging from logging.handlers import RotatingFileHandler os.environ['TF_KERAS'] = '1' os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' # 1=警告,2=错误,3=静默 os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0' # 关闭 oneDNN 提示 app = Flask(__name__) log_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'utils') os.makedirs(log_dir, exist_ok=True) # 配置文件日志处理器(10MB轮换,保留10个备份) file_handler = RotatingFileHandler( os.path.join(log_dir, 'app.log'), maxBytes=10*1024*1024, backupCount=10 ) file_handler.setFormatter(logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s' )) # 设置日志级别(DEBUG/INFO/WARNING/ERROR/CRITICAL) app.logger.setLevel(logging.INFO) file_handler.setLevel(logging.INFO) app.logger.addHandler(file_handler) # --- 加载 libinjection --- try: libinjection = ctypes.CDLL('/usr/local/lib/libinjection.so', mode=ctypes.RTLD_GLOBAL) libinjection.libinjection_sqli.argtypes = [ ctypes.c_char_p, ctypes.c_size_t, ctypes.c_char_p, ctypes.c_size_t ] libinjection.libinjection_sqli.restype = ctypes.c_int app.logger.info("Libinjection 加载成功") print("Libinjection 加载成功(控制台输出)") except Exception as e: app.logger.error(f"Libinjection 加载失败: {str(e)}", exc_info=True) exit(1) # --- 解码辅助函数 --- def try_base64_decode(s): try: if len(s) % 4 != 0: return s decoded = base64.b64decode(s).decode('utf-8', errors='ignore') if all(32 <= ord(c) <= 126 or c in '\t\r\n' for c in decoded): return decoded return s except Exception: return s def deep_url_decode(s, max_depth=3): decoded = s for _ in range(max_depth): new_decoded = unquote(decoded) if new_decoded == decoded: break decoded = new_decoded return decoded # --- 提取 HTTP 请求中的潜在 SQL 内容 --- def extract_sql_candidates(data): candidates = [] def extract_strings(obj): EXCLUDED_KEYS = {'uri', 'path', 'security', 'PHPSESSID', 'session_id','Login', 'login', 'submit', 'Submit'} STATIC_RESOURCES = {'.css', '.js', '.png', '.jpg', '.jpeg', '.gif', '.ico', '.woff', '.woff2'} if isinstance(obj, dict): for key, value in obj.items(): if key in EXCLUDED_KEYS: continue # 检查值是否为静态资源(无需检测) if isinstance(value, str) and any(ext in value.lower() for ext in STATIC_RESOURCES): continue extract_strings(value) # 递归调用,仅传递值 elif isinstance(obj, list): for item in obj: extract_strings(item) elif isinstance(obj, str): text = obj # 多层 URL 解码 text = deep_url_decode(text) # HTML 实体解码 text = html.unescape(text) # Unicode 转义解码 try: text = text.encode().decode('unicode_escape') except Exception: pass # Base64 解码 text = try_base64_decode(text) if len(text) < 1000: candidates.append(text) extract_strings(data) return candidates # --- 检测逻辑 --- def detect_one(query): if re.match(r'^\/.*\.(php|html|js)$', query): return { "检测结果": "正常", "检测方式": "URI过滤", "可信度": 1.0 } result_buf = ctypes.create_string_buffer(8) is_libi_sqli = libinjection.libinjection_sqli(query.encode('utf-8'), len(query),result_buf,ctypes.sizeof(result_buf)) if is_libi_sqli: return { "检测结果": "存在SQL注入", "检测方式": "Libinjection", } else: return { "检测结果": "正常", "检测方式": "Libinjection", } @app.route('/') def home(): return "SQL 注入检测系统已启动" @app.route('/detect', methods=['POST']) def detect(): app.logger.info(f"接收到请求: {request.json}") try: data = request.get_json() if not data: return jsonify({"error": "缺少 JSON 请求体"}), 400 ip = request.remote_addr candidates = extract_sql_candidates(data) results = [] for query in candidates: result = detect_one(query) log_detection(ip, query, result) results.append(result) return jsonify({"detections": results}) except Exception as e: return jsonify({"error": f"检测过程中发生错误: {str(e)}"}), 500 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=True) nainx.conf: # 全局作用域(仅保留一份) user user; worker_processes 1; events { worker_connections 1024; } http { lua_package_path "/usr/local/openresty/lualib/?.lua;;"; include mime.types; default_type text/html; sendfile on; keepalive_timeout 65; server { listen 80; server_name 10.18.47.200; location /dvwa { rewrite_by_lua_file /usr/local/openresty/lualib/parse.lua; proxy_pass http://192.168.159.100/DVWA-master/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_redirect http://10.18.47.200/DVWA-master/ http://10.18.47.200/dvwa/; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; charset utf-8; } #屏蔽图标 location = /favicon.ico { access_log off; log_not_found off; } } } parse.lua: local cjson = require "cjson.safe" local http = require "resty.http" -- 1) 解析 Nginx 内置变量和 Headers local method = ngx.req.get_method() local uri = ngx.var.request_uri local headers = { user_agent = ngx.var.http_user_agent or "", cookie = ngx.var.http_cookie or "", host = ngx.var.http_host or "", content_type = ngx.var.http_content_type or "" } -- 2) 解析 GET 参数 ngx.req.read_body() -- 必须先读取 body,否则取不到 POST local args = ngx.req.get_uri_args() local query_params = {} for k, v in pairs(args) do query_params[k] = v end -- 3) 解析 POST 数据: 根据 content_type 判断JSON或表单 local post_data = {} if headers.content_type and string.find(headers.content_type, "application/json") then local body_data = ngx.req.get_body_data() if body_data then local json_data = cjson.decode(body_data) if json_data then post_data = json_data else ngx.log(ngx.ERR, "JSON 解析失败") end end else local post_args = ngx.req.get_post_args() for k, v in pairs(post_args) do post_data[k] = v end end -- 4) 整合请求数据并日志输出 local request_data = { method = method, uri = uri, headers = headers, query_params = query_params, post_data = post_data, client_ip = ngx.var.remote_addr } ngx.log(ngx.ERR, "OpenResty 解析的数据: " .. cjson.encode(request_data)) -- 5) 调用 Flask WAF 后端 local httpc = http.new() local res, err = httpc:request_uri("http://127.0.0.1:5000/detect", { method = "POST", body = cjson.encode(request_data), headers = { ["Content-Type"] = "application/json" } }) if not res then ngx.log(ngx.ERR, "Flask WAF 请求失败: ", err) ngx.status = 500 ngx.header["Content-Type"] = "text/html; charset=utf-8" ngx.say("WAF 检测异常") return ngx.exit(500) end -- 6) 复用连接 local ok, err_keep = httpc:set_keepalive(60000, 100) if not ok then ngx.log(ngx.ERR, "设置 keepalive 失败: ", err_keep) end ngx.log(ngx.ERR, "Flask 返回: ", res.body) -- 7) 解析Flask响应并处理(修正pcall返回值) if res.status ~= 200 then ngx.log(ngx.ERR, "Flask 返回非200状态码: ", res.status) ngx.status = 500 ngx.header["Content-Type"] = "text/html; charset=utf-8" ngx.say("Flask 服务异常") return ngx.exit(500) end local success, decoded_data = pcall(cjson.decode, res.body) if not success then ngx.log(ngx.ERR, "Flask 响应JSON解析失败: ", decoded_data) ngx.status = 500 ngx.header["Content-Type"] = "text/html; charset=utf-8" ngx.say("WAF 响应格式错误") return ngx.exit(500) end local waf_result = decoded_data -- 8) 判断是否存在SQL注入(根据app.py的响应结构) local is_sqli = false local detections = waf_result.detections or {} for i = 1, #detections do local detection = detections[i] -- 检查检测结果是否为表类型且包含检测结果字段 if type(detection) == "table" and detection["检测结果"] then if detection["检测结果"] == "存在SQL注入" then is_sqli = true break end end end -- for _, detection in ipairs(waf_result.detections or {}) do -- if detection["检测结果"] == "存在SQL注入" then -- is_sqli = true -- break -- end -- end -- 9) 根据检测结果决定是否拦截 if is_sqli then ngx.log(ngx.ERR, "WAF阻断 SQL注入") ngx.status = ngx.HTTP_FORBIDDEN ngx.header["Content-Type"] = "text/html; charset=utf-8" ngx.say([[ <!DOCTYPE html> <html lang="zh"> <head> <meta charset="utf-8"/> <title>访问受限</title> <style> /* 全局样式重置 */ * { margin: 0; padding: 0; box-sizing: border-box; } body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background-color: #000; color: #fff; font-family: "Microsoft YaHei", Arial, sans-serif; } .container { width: 90%; max-width: 600px; padding: 40px; text-align: center; border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 8px; background: rgba(10, 10, 10, 0.8); backdrop-filter: blur(5px); box-shadow: 0 0 15px rgba(255, 255, 255, 0.05); } h1 { margin-bottom: 20px; font-size: 2.5rem; letter-spacing: 2px; color: #fff; text-shadow: 0 0 10px rgba(0, 255, 255, 0.5); } p { margin-bottom: 30px; font-size: 1.1rem; line-height: 1.8; color: rgba(255, 255, 255, 0.9); } .btn-back { display: inline-block; padding: 12px 30px; background: transparent; color: #00ffcc; border: 1px solid #00ffcc; border-radius: 4px; font-size: 1rem; font-weight: bold; text-decoration: none; transition: all 0.3s ease; cursor: pointer; } .btn-back:hover { background: rgba(0, 255, 204, 0.1); box-shadow: 0 0 15px rgba(0, 255, 204, 0.3); transform: translateY(-2px); } </style> </head> <body> <div class="container"> <h1>访问受限</h1> <p> 检测到疑似SQL注入/跨站脚本攻击(XXS)的恶意行为特征,<br/> 为保障系统安全,本次请求未被授权执行<br/> </p> <a href="javascript:void(0)" class="btn-back" id="backBtn">返回上一页</a> </div> <script> // 点击按钮返回前一个页面状态 document.getElementById('backBtn').addEventListener('click', function() { history.back(); }); </script> </body> ]]) else ngx.log(ngx.ERR, "WAF 判断正常,放行请求") return -- 关键:放行请求,继续执行proxy_pass end
最新发布
06-29
<think>我们正在Debian系统上通过OpenResty配置ModSecurity,目的是替代现有的libinjection.so实现的SQL注入防护机制。步骤概述:1.确保OpenResty已安装。2.安装ModSecurity及其依赖。3.编译ModSecurity的Nginx连接器(动态模块)。4.在OpenResty配置中加载该模块并启用ModSecurity。5.配置ModSecurity规则,特别是针对SQL注入的规则(使用OWASP核心规则集)。6.禁用或移除原有的libinjection.so配置。注意:由于我们要替代libinjection,所以需要确保ModSecurity的规则能够覆盖SQL注入攻击的检测。详细步骤:</think>### Debian 系统通过 OpenResty 配置 ModSecurity 替代 libinjection 方案 #### **1. 卸载现有 libinjection 模块** ```bash # 定位当前加载的 libinjection 模块 grep libinjection /usr/local/openresty/nginx/conf/nginx.conf # 注释或删除相关配置行 sudo sed -i 's/load_module modules\/libinjection/# load_module modules\/libinjection/' /usr/local/openresty/nginx/conf/nginx.conf ``` #### **2. 安装 ModSecurity 核心组件** ```bash # 安装依赖 sudo apt install -y git g++ make automake autoconf libtool pkgconf \ libcurl4-openssl-dev libxml2-dev libyajl-dev ssdeep libgeoip-dev libpcre3-dev # 编译安装 ModSecurity v3 git clone --depth 1 -b v3/master https://github.com/SpiderLabs/ModSecurity cd ModSecurity ./build.sh ./configure --with-yajl --enable-standalone-module make sudo make install ``` #### **3. 编译 ModSecurity-Nginx 动态模块** ```bash # 获取 OpenResty 的 Nginx 版本 NGINX_VER=$(/usr/local/openresty/nginx/sbin/nginx -v 2>&1 | grep -oE '[0-9.]+') # 下载连接器 git clone https://github.com/SpiderLabs/ModSecurity-nginx.git # 编译动态模块 cd /usr/local/openresty/nginx ./configure --add-dynamic-module=/path/to/ModSecurity-nginx \ --with-compat make modules ``` #### **4. 配置 OpenResty 集成** ```nginx # /usr/local/openresty/nginx/conf/nginx.conf load_module modules/ngx_http_modsecurity_module.so; # 替代 libinjection http { modsecurity on; modsecurity_rules_file /etc/modsecurity/main.conf; # 禁用原有 SQL 注入检测 # libinjection_sqli on; # 注释或删除此行 server { location / { modsecurity on; # 配置防护规则... } } } ``` #### **5. 配置 SQL 注入防护规则** ```bash # 创建主配置文件 sudo mkdir /etc/modsecurity sudo cp ModSecurity/modsecurity.conf-recommended /etc/modsecurity/main.conf # 启用 SQL 注入规则 sudo tee -a /etc/modsecurity/main.conf <<EOF SecRuleEngine On SecRequestBodyAccess On # 加载 OWASP CRS SQL 注入规则 Include /etc/modsecurity/crs/crs-setup.conf Include /etc/modsecurity/crs/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf EOF # 下载 OWASP 核心规则集 sudo git clone https://github.com/coreruleset/coreruleset /etc/modsecurity/crs ``` #### **6. 优化 SQL 注入检测规则** ```nginx # 在 nginx.conf 的 http 块添加优化配置 modsecurity_rules ' # 禁用低准确率规则(根据业务调整) SecRuleRemoveById 942100 942110 942130 942150 942200 942230 942260 # 调整敏感度 (1-4) SecAction "id:900000,phase:1,nolog,pass,setvar:tx.paranoia_level=2" # 增强特定攻击检测 SecRule REQUEST_URI|REQUEST_BODY "@detectSQLi" \\ "id:1000,phase:2,log,deny,status:403,msg:\'SQL Injection Detected\'" '; ``` #### **7. 性能对比测试** ```bash # 使用 sqlmap 测试防护效果 sqlmap -u http://localhost/login.php --forms --batch --risk=3 --level=5 # 查看拦截日志 tail -f /usr/local/openresty/nginx/logs/error.log | grep ModSecurity ``` #### **8. 规则维护脚本** ```bash #!/bin/bash # /usr/local/bin/update_modsec_rules.sh cd /etc/modsecurity/crs git pull origin v3.3/dev nginx -t && systemctl reload openresty ``` ### **关键配置对比** | 特性 | libinjection | ModSecurity | |--------------------|----------------------------------|------------------------------| | 检测机制 | 特征匹配 | 正则+语义分析+机器学习[^1] | | SQL注入覆盖 | 基础注入模式 | 200+种变体检测 | | 误报率 | 低 | 可配置 (paranoia_level) | | 规则更新 | 手动更新 | 自动更新(CRS) | | 防护扩展性 | 仅SQL注入 | XSS/RCE/LFI等全方位防护 | ### **迁移注意事项** 1. **规则兼容性** - 保留原有合法请求白名单:`SecRuleUpdateTargetById 942360 "!REQUEST_HEADERS:User-Agent"` - 使用 `SecRuleRemoveById` 禁用与业务冲突的规则 2. **性能优化** ```nginx # 限制检测范围 modsecurity_rules ' SecRule REQUEST_FILENAME "@endsWith .jpg" "id:1001,phase:1,nolog,pass,ctl:ruleEngine=Off" SecRequestBodyLimit 12800000 # 调整请求体大小 '; ``` 3. **日志分析** 使用 ModSecLogParser 转换日志格式: ```bash alp -f /var/log/modsec_audit.log --format modsec ``` > **安全建议**:部署后使用 WAF 测试工具(如 WIVET)验证防护覆盖率,建议开启 `SecRuleEngine DetectionOnly` 观察 7 天后再切换为拦截模式[^2]。 --- ### **相关问题** 1. 如何验证 ModSecurity 的 SQL 注入检测准确率是否优于 libinjection? 2. ModSecurity 规则与 OpenResty 的 Lua 防火墙如何协同工作? 3. 如何将 ModSecurity 的审计日志集成到 SIEM 系统? 4. 在高流量场景下如何优化 ModSecurity 性能? 5. 如何自定义 ModSecurity 规则来防护零日 SQL 注入攻击? [^1]: OWASP CRS 规则集采用概率异常检测(PARANOIA)和机器学习增强检测能力。 [^2]: 商业支持方案提供实时威胁情报更新,如 Trustwave ModSecurity 规则订阅服务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值