trx
Published on 2025-01-10 / 70 Visits
0

常见漏洞修复(持续更新)

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>

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>