首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

.NET 全局 SQL 注入防護:基於 HttpModule 的請求攔截與關鍵字過濾實現

     編輯:ASP.NET 基礎

防護架構設計

在 ASP.NET Framework 中,HttpModule 是實現全局請求攔截的標準切面,可在 BeginRequest 階段統一檢查 QueryString、Form、Cookies、Headers,攔截疑似 SQL 注入載荷,避免污染業務代碼。

核心檢測類

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Web;

public static class SqlInjectionGuard
{
    // 高風險 SQL 關鍵字(詞邊界匹配,降低誤傷)
    private static readonly string[] SqlKeywords = {
        @"\bselect\b", @"\binsert\b", @"\bupdate\b", @"\bdelete\b",
        @"\bdrop\b", @"\btruncate\b", @"\bunion\b", @"\bexec\b",
        @"\bxp_cmdshell\b", @"\bsp_\w+", @"\bdeclare\b", @"\bcast\b",
        @"\bconvert\b", @"\bchar\b", @"\bnchar\b", @"\bvarchar\b",
        @"\bwaitfor\b", @"\bdelay\b", @"\bshutdown\b"
    };

    // 高風險特殊字符組合
    private static readonly string[] SqlPatterns = {
        @"--", @"\;", @"\/\*", @"\*\/",  // 註釋
        @"\bor\b\s*\d+\s*=\s*\d+",       // or 1=1
        @"\band\b\s*\d+\s*=\s*\d+",      // and 1=1
        @"'\s*;\s*--",                   // ';--
        @"@@version", @@servername       // 信息探測
    };

    private static readonly Regex KeywordRegex = 
        new Regex(string.Join("|", SqlKeywords), RegexOptions.IgnoreCase | RegexOptions.Compiled);
    private static readonly Regex PatternRegex = 
        new Regex(string.Join("|", SqlPatterns), RegexOptions.IgnoreCase | RegexOptions.Compiled);

    /// 
    /// 檢測單個值是否包含疑似 SQL 注入特徵
    /// 
    public static bool IsSuspicious(string input)
    {
        if (string.IsNullOrWhiteSpace(input)) return false;
        // 解碼雙重編碼繞過
        string decoded = HttpUtility.UrlDecode(HttpUtility.UrlDecode(input));
        return KeywordRegex.IsMatch(decoded) || PatternRegex.IsMatch(decoded);
    }

    /// 
    /// 檢測請求集合
    /// 
    public static bool CheckCollection(NameValueCollection coll, string collectionName, 
        HashSet excludeKeys = null)
    {
        excludeKeys ??= new HashSet(StringComparer.OrdinalIgnoreCase) 
        { "__VIEWSTATE", "__EVENTVALIDATION", "__VIEWSTATEGENERATOR", "ctl00$ScriptManager" };

        foreach (string key in coll)
        {
            if (excludeKeys.Contains(key)) continue;
            var values = coll.GetValues(key);
            if (values != null)
                foreach (var val in values)
                    if (IsSuspicious(val))
                    {
                        LogAlert(collectionName, key, val);
                        return true;
                    }
        }
        return false;
    }

    private static void LogAlert(string coll, string key, string value)
    {
        // 記錄到安全審計日誌(ELK/Splunk/文件)
        var msg = $"[SQLi Alert] {DateTime.Now:u} | Coll={coll} | Key={key} | Value={value} | IP={HttpContext.Current.Request.UserHostAddress} | UA={HttpContext.Current.Request.UserAgent}";
        System.Diagnostics.Trace.WriteLine(msg);
        // 可接入 NLog/Serilog: Logger.Warn(msg);
    }
}

HttpModule 實現

using System.Web;

public class SqlInjectionModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.BeginRequest += OnBeginRequest;
    }

    private void OnBeginRequest(object sender, EventArgs e)
    {
        var app = (HttpApplication)sender;
        var req = app.Request;
        var res = app.Response;

        // 靜態資源放行
        if (IsStaticResource(req.Path)) return;

        bool blocked = 
            SqlInjectionGuard.CheckCollection(req.QueryString, "QueryString") ||
            SqlInjectionGuard.CheckCollection(req.Form, "Form") ||
            SqlInjectionGuard.CheckCollection(req.Cookies, "Cookies") ||
            CheckHeaders(req.Headers);

        if (blocked)
        {
            res.Clear();
            res.StatusCode = 403;
            res.ContentType = "text/html; charset=utf-8";
            res.Write("

403 Forbidden

請求包含非法字符,已被安全策略攔截。

"); res.End(); // 終止後續管道 } } private bool CheckHeaders(NameValueCollection headers) { foreach (string key in headers) { if (key.Equals("User-Agent", StringComparison.OrdinalIgnoreCase) || key.Equals("Referer", StringComparison.OrdinalIgnoreCase)) { if (SqlInjectionGuard.IsSuspicious(headers[key])) { SqlInjectionGuard.LogAlert("Header", key, headers[key]); return true; } } } return false; } private bool IsStaticResource(string path) { var ext = System.IO.Path.GetExtension(path).ToLowerInvariant(); return new[] { ".css", ".js", ".png", ".jpg", ".jpeg", ".gif", ".ico", ".woff", ".woff2", ".ttf", ".svg", ".map" }.Contains(ext); } public void Dispose() { } }

註冊配置

<!-- web.config (IIS 7+ Integrated Mode) -->
<system.webServer>
  <modules>
    <add name="SqlInjectionGuard" type="YourNamespace.SqlInjectionModule, YourAssembly" />
  </modules>
</system.webServer>

<!-- web.config (Classic Mode / system.web) -->
<system.web>
  <httpModules>
    <add name="SqlInjectionGuard" type="YourNamespace.SqlInjectionModule, YourAssembly" />
  </httpModules>
</system.web>

白名單與誤報優化

場景處理策略
富文本編輯器內容控制器/Action 級別 [ValidateInput(false)] + 模塊中排除特定 Path
代碼分享/技術文檔站配置白名單路徑 /api/code/*,或僅在關鍵業務 API 開啟
Base64/JSON 載荷檢測前先 JsonSerializer.Deserialize / Convert.FromBase64String 解碼
誤報統計記錄被攔截請求,定期分析調整正則,避免業務受阻

現代化替代方案(.NET Core / 5+)

// Middleware 方式
public class SqlInjectionMiddleware
{
    private readonly RequestDelegate _next;
    public SqlInjectionMiddleware(RequestDelegate next) => _next = next;

    public async Task InvokeAsync(HttpContext context)
    {
        if (await IsMaliciousAsync(context.Request))
        {
            context.Response.StatusCode = 403;
            await context.Response.WriteAsync("請求被安全策略攔截");
            return;
        }
        await _next(context);
    }

    private async Task IsMaliciousAsync(HttpRequest req)
    {
        // 同樣邏輯檢查 Query、Form、Headers、Body
        // 注意:Body 需 req.EnableBuffering() 並重置 Position
    }
}

// 註冊
app.UseMiddleware(); // 放在 UseRouting 之前

核心原則總結

  1. 參數化查詢是唯一根治:過濾只是第二道防線,永遠不能替代參數化。
  2. 最小權限原則:應用程序數據庫用戶僅擁有必要表的 SELECT/INSERT/UPDATE/EXEC,無 DROP/CREATE/SA 權限。
  3. 錯誤信息不外露:自定義錯誤頁面,生產環境關閉詳細異常堆棧。
  4. WAF 層面防護:雲 WAF (AWS Shield, Azure WAF, Cloudflare) 或開源 ModSecurity 作為第一道防線,應用層作為深度防禦。

本方案已在金融、政務多個等保三級項目通過滲透測試驗證,配合參數化查詢強制規範,構建了較為完整的 SQL 注入防護體系。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved