CORS跨域漏洞
通过nginx结合lua脚本实现
# 在server块中指定lua脚本路径
access_by_lua_file '/opt/lua/cors.lua';
-- lua脚本
-- cors.lua
-- 打印调试信息
ngx.log(ngx.NOTICE, "Lua script is running")
-- 定义允许的 Origin(支持多个 Origin)
local allowed_origins = {
"https://x.x.x.x:777",
"https://x.x.x.x" -- 新增的允许的 Origin
}
-- 获取请求头
local headers = ngx.req.get_headers()
-- 打印所有请求头(调试用)
for k, v in pairs(headers) do
ngx.log(ngx.NOTICE, "Header: ", k, " = ", v)
end
-- 获取 Origin 头
local origin = headers["Origin"]
ngx.log(ngx.NOTICE, "Request Origin: ", origin or "nil")
-- 如果 Origin 为空,允许请求(可能是同源请求)
if not origin then
ngx.log(ngx.NOTICE, "Origin is empty, allowing request")
return
end
-- 检查 Origin 是否匹配
local is_allowed = false
for _, allowed_origin in ipairs(allowed_origins) do
if origin == allowed_origin then
is_allowed = true
break
end
end
if is_allowed then
-- 设置 CORS 头
ngx.header["Access-Control-Allow-Origin"] = origin
ngx.header["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS"
ngx.header["Access-Control-Allow-Headers"] = "Content-Type, Authorization"
ngx.header["Access-Control-Allow-Credentials"] = "true"
ngx.header["Vary"] = "Origin"
-- 如果是 OPTIONS 请求,直接返回 204
if ngx.req.get_method() == "OPTIONS" then
ngx.header["Content-Length"] = "0"
ngx.header["Content-Type"] = "text/plain"
ngx.exit(ngx.HTTP_NO_CONTENT)
end
else
-- 如果 Origin 不匹配,返回 403 Forbidden
ngx.log(ngx.ERR, "Origin not allowed: ", origin or "nil")
ngx.exit(ngx.HTTP_FORBIDDEN)
end
通过nginx配置修复
server {
listen 80;
server_name localhost;
# 动态设置允许的域名
set $cors_origin "";
if ($http_origin ~* "^https://(abc.com|cde.com)$") {
set $cors_origin $http_origin;
}
# 处理预检请求(OPTIONS)
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' $cors_origin;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
# 处理实际请求
add_header 'Access-Control-Allow-Origin' $cors_origin;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
# 代理到后端服务器
proxy_pass http://x.x.x.x;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
API成批分配漏洞修复
nginx+lua脚本修复
此方法只适用于无法进行代码修复的情况,建议在代码层修复。
-- 同上CORS跨域漏洞,也需要在nginx引入此脚本
-- 引入 cjson 模块
local cjson = require "cjson"
-- 定义允许的字段
local allowed_fields = {
name = true,
beginTime = true,
endTime = true,
levelId = true,
topCaseClassId = true,
status = true,
reportType = true
}
-- 定义需要限制的路径
local restricted_paths = {
["/eos/"] = true,
["/emergency/"] = true,
["/ctiOperator/"] = true
}
-- 定义放行的路径
local allowed_paths = {
["/eos/event/user"] = true,
["/eos/communication/icp/agent"] = true
}
-- 递归检查字段
local function check_fields(data)
for key, value in pairs(data) do
-- 如果字段是禁止的,返回错误
if not allowed_fields[key] then
return false, key
end
-- 如果值是表(嵌套字段),递归检查
if type(value) == "table" then
local is_valid, invalid_key = check_fields(value)
if not is_valid then
return false, invalid_key
end
end
end
return true
end
-- 获取请求方法、URI 和客户端 IP
local request_method = ngx.req.get_method()
local request_uri = ngx.var.request_uri
local client_ip = ngx.var.remote_addr
-- 记录请求信息
ngx.log(ngx.NOTICE, "Received request: method=", request_method, ", uri=", request_uri, ", client_ip=", client_ip)
-- 检查请求方法是否允许
local allowed_methods = { GET = true, POST = true, OPTIONS = true }
if not allowed_methods[request_method] then
ngx.log(ngx.ERR, "Method not allowed: ", request_method, ", uri=", request_uri, ", client_ip=", client_ip)
ngx.exit(ngx.HTTP_NOT_ALLOWED)
end
-- 检查是否需要放行当前路径
if allowed_paths[request_uri] then
-- 放行路径,不进行字段检查
ngx.log(ngx.NOTICE, "Path allowed, skipping field check, uri=", request_uri, ", client_ip=", client_ip)
else
-- 检查是否需要限制当前路径
local is_restricted = false
for path, _ in pairs(restricted_paths) do
if string.find(request_uri, path, 1, true) == 1 then
is_restricted = true
break
end
end
if is_restricted then
-- 如果是 POST 或 PUT 请求,检查请求体
if request_method == "POST" or request_method == "PUT" then
-- 读取请求体
ngx.req.read_body()
local body_data = ngx.req.get_body_data()
if body_data then
-- 解析 JSON 数据
local json_data, err = cjson.decode(body_data)
if json_data then
-- 检查请求体中的字段
local is_valid, invalid_key = check_fields(json_data)
if not is_valid then
ngx.log(ngx.ERR, "Forbidden field detected: ", invalid_key, ", uri=", request_uri, ", client_ip=", client_ip)
ngx.exit(ngx.HTTP_BAD_REQUEST)
end
else
ngx.log(ngx.ERR, "Failed to decode JSON: ", err, ", uri=", request_uri, ", client_ip=", client_ip)
ngx.exit(ngx.HTTP_BAD_REQUEST)
end
else
ngx.log(ngx.ERR, "Empty request body, uri=", request_uri, ", client_ip=", client_ip)
ngx.exit(ngx.HTTP_BAD_REQUEST)
end
end
else
-- 其他路径直接放行
ngx.log(ngx.NOTICE, "Path not restricted, skipping field check, uri=", request_uri, ", client_ip=", client_ip)
end
end
-- 记录允许的请求信息
ngx.log(ngx.NOTICE, "Method allowed: ", request_method, ", uri=", request_uri, ", client_ip=", client_ip)
易受攻击的组件
一般各种js组件出现此漏洞比较多,直接到官网下载新版本替换现有版本文件即可,如替换后出现兼容性问题,则使用nginx配置进行限制。
nginx限制访问IP
# nginx.conf
# 限制具体某一个文件只允许特定IP访问。
location /static/js/1.js {
allow 192.168.1.1;
allow 192.168.2.0/24;
deny all;
}
Spring Boot中druid未授权访问漏洞
配置tomcat用户密码认证修复
<!-- config/tomcat-users.xml中定义用户和角色 -->
<tomcat-users>
<!-- 定义角色 -->
<role rolename="druid-admin"/>
<!-- 定义用户 -->
<user username="admin" password="admin123" roles="druid-admin"/>
</tomcat-users>
<!-- config/web.xml中配置安全约束 -->
<web-app>
<!-- 定义安全约束 -->
<security-constraint>
<!-- 限制的 URL 路径 -->
<web-resource-collection>
<web-resource-name>Druid Monitor</web-resource-name>
<url-pattern>/druid/*</url-pattern>
</web-resource-collection>
<!-- 允许访问的角色 -->
<auth-constraint>
<role-name>druid-admin</role-name>
</auth-constraint>
</security-constraint>
<!-- 配置认证方式 -->
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Druid Monitor Realm</realm-name>
</login-config>
<!-- 配置安全角色 -->
<security-role>
<role-name>druid-admin</role-name>
</security-role>
</web-app>
启用了不安全的“options”http方法
tomcat web.xml:
<security-constraint>
<web-resource-collection>
<web-resource-name>Disable WebDAV Methods</web-resource-name>
<url-pattern>/*</url-pattern> <!-- 对所有路径生效 -->
<http-method>OPTIONS</http-method>
<http-method>PUT</http-method>
<http-method>DELETE</http-method>
<http-method>PROPFIND</http-method>
<http-method>PROPPATCH</http-method>
<http-method>MKCOL</http-method>
<http-method>COPY</http-method>
<http-method>MOVE</http-method>
<http-method>LOCK</http-method>
<http-method>UNLOCK</http-method>
</web-resource-collection>
<auth-constraint>
<!-- 拒绝所有用户访问 -->
<role-name>none</role-name>
</auth-constraint>
</security-constraint>
tomcat1:
<!-- 1. 优化 CORS 过滤器配置 -->
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.methods</param-name>
<param-value>GET, POST, OPTIONS</param-value>
</init-param>
<!-- 新增以下参数 -->
<init-param>
<param-name>cors.exposed.headers</param-name>
<param-value>Allow</param-value>
</init-param>
<init-param>
<param-name>cors.preflight.maxage</param-name>
<param-value>3600</param-value>
</init-param>
<init-param>
<param-name>cors.support.credentials</param-name>
<param-value>false</param-value>
</init-param>
</filter>
<!-- 2. 扩展安全约束,覆盖更多方法 -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Disable Unsafe Methods</web-resource-name>
<url-pattern>/*</url-pattern>
<!-- 原有 WebDAV 方法 -->
<http-method>PUT</http-method>
<http-method>DELETE</http-method>
<http-method>PROPFIND</http-method>
<http-method>PROPPATCH</http-method>
<http-method>MKCOL</http-method>
<http-method>COPY</http-method>
<http-method>MOVE</http-method>
<http-method>LOCK</http-method>
<http-method>UNLOCK</http-method>
<!-- 新增需要禁用的标准方法 -->
<http-method>TRACE</http-method>
<http-method>PATCH</http-method>
<http-method>HEAD</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>none</role-name>
</auth-constraint>
</security-constraint>
<!-- 3. 新增 OPTIONS 方法的安全约束 -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Override OPTIONS</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>OPTIONS</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>none</role-name>
</auth-constraint>
</security-constraint>
tomcat context.xml
<Context>
<!-- 禁用Tomcat自动生成Allow头 -->
<JarScanner scanManifest="false"/>
<Resources cachingAllowed="false"/>
</Context>
支持较老的TLS版本
tomcat:
<Connector
protocol="org.apache.coyote.http11.Http11NioProtocol"
port="8681"
maxThreads="200"
SSLEnabled="true"
scheme="https"
secure="true"
clientAuth="false"
sslProtocol="TLS"
keystoreFile="/usr/local/tomcat_cas/conf/tomcat.keystore"
keystorePass="123456"
sslEnabledProtocols="TLSv1.2,TLSv1.3"
ciphers="TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
/>
弱密码套件:不支持弱密码套件:不支持 AEAD
<VirtualHost *:80>
ServerName localhost:80
DocumentRoot "E:/Program Files/dist"
SSLEngine on
SSLCertificateFile aaa.crt
SSLCertificateKeyFile aaa.key
SSLCertificateChainFile bbb.crt
# 仅启用 TLS 1.2 和 1.3(禁用 TLS 1.0/1.1)
SSLProtocol -TLSv1.2 +TLSv1.3 -TLSv1 -TLSv1.1
# 仅保留安全的密码套件(移除 SHA-1 和 CBC 模式)
SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4:!SHA1
# 优先使用服务器端的密码套件顺序
SSLHonorCipherOrder on
# 启用 HSTS(强制 HTTPS)
#Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
# 启用 OCSP Stapling(提高 SSL 验证性能)
#SSLUseStapling on
#SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"
</VirtualHost>
主机头注入攻击
tomcat:
<Engine name="Catalina" defaultHost="yourdomain.com">
<!-- 允许的合法 Host -->
<Host name="yourdomain.com" appBase="webapps" unpackWARs="true">
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="10\.10\.0\.\d+|10\.20\.0\.\d+" />
<!-- 正常应用配置 -->
</Host>
<!-- 拒绝所有其他 Host 请求 -->
<Host name="_default_" appBase="webapps_deny">
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
deny=".*" /> <!-- 拒绝所有IP -->
<Valve className="org.apache.catalina.valves.ErrorReportValve"
showReport="false" showServerInfo="false" /> <!-- 隐藏错误信息 -->
</Host>
</Engine>
不安全、不正确或缺少 SameSite 属性的 Cookie 问题
tomcat中context.xml和web.xml只配置一个即可:
<!-- context.xml -->
<Context>
<CookieProcessor sameSiteCookies="Lax" secure="true"/>
</Context>
<!-- tomcat8.5+ web.xml -->
<session-config>
<cookie-config>
<!-- 设置为Strict、Lax或None -->
<attribute name="SameSite">Lax</attribute>
<!-- 如果设置为None,必须同时启用Secure -->
<secure>true</secure>
</cookie-config>
</session-config>
LDAP盲注
tomcat web.xml:
<filter>
<filter-name>LdapInjectionFilter</filter-name>
<filter-class>com.example.security.LdapInjectionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LdapInjectionFilter</filter-name>
<url-pattern>/ldap/*</url-pattern>
</filter-mapping>