CA3001:檢閱程式碼是否有 SQL 插入式攻擊弱點

屬性
規則識別碼 CA3001
標題 檢閱程式碼是否有 SQL 插入式攻擊弱點
類別 安全性
修正程式是中斷或非中斷 不中斷
預設在 .NET 8 中啟用 No

原因

可能不受信任的 HTTP 要求輸入會到達 SQL 命令的文字。

根據預設,此規則會分析整個程式代碼基底,但這是可設定

檔案描述

使用不受信任的輸入和 SQL 命令時,請留意 SQL 插入式攻擊。 SQL 插入式攻擊可以執行惡意 SQL 命令,進而危害應用程式的安全性和完整性。 一般技術包括使用單引號或單引號分隔常值字串、批注的兩個破折號,以及語句結尾的分號。 如需詳細資訊,請參閱 SQL 插入

此規則會嘗試從到達 SQL 命令文字的 HTTP 要求尋找輸入。

注意

此規則無法追蹤元件之間的數據。 例如,如果某個元件讀取 HTTP 要求輸入,然後將它傳遞給另一個執行 SQL 命令的元件,則此規則不會產生警告。

注意

此規則在方法呼叫之間分析數據流的深度有可設定的限制。 如需如何在EditorConfig檔案中設定限制,請參閱 分析器 組態。

如何修正違規

使用參數化 SQL 命令或預存程式,搭配包含不受信任輸入的參數。

隱藏警告的時機

如果您知道輸入一律會根據已知的安全字元集進行驗證,則隱藏來自此規則的警告是安全的。

隱藏警告

如果您只想要隱藏單一違規,請將預處理器指示詞新增至原始程式檔以停用,然後重新啟用規則。

#pragma warning disable CA3001
// The code that's violating the rule is on this line.
#pragma warning restore CA3001

若要停用檔案、資料夾或項目的規則,請在組態檔中將其嚴重性設定為 。none

[*.{cs,vb}]
dotnet_diagnostic.CA3001.severity = none

如需詳細資訊,請參閱 如何隱藏程式代碼分析警告

設定程式代碼以分析

使用下列選項來設定程式代碼基底要執行此規則的部分。

您可以只針對此規則、它套用的所有規則,或針對套用至此類別的所有規則(安全性)設定這些選項。 如需詳細資訊,請參閱 程式代碼品質規則組態選項

排除特定符號

您可以從分析中排除特定符號,例如類型和方法。 例如,若要指定規則不應該在名為 MyType的任何程式代碼上執行,請將下列機碼/值組新增至 專案中的 .editorconfig 檔案:

dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType

選項值中允許的符號名稱格式(以 |分隔):

  • 只包含符號名稱(包含名稱的所有符號,不論包含類型或命名空間為何)。
  • 符號 檔案識別碼格式的完整名稱。 每個符號名稱都需要符號種類前置詞,例如 M: 方法、 T: 類型和 N: 命名空間。
  • .ctor 用於建構函式和 .cctor 靜態建構函式。

範例:

選項值 摘要
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType 符合所有名為 MyType的符號。
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 比對名為 MyType1MyType2的所有符號。
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) 比對特定方法 MyMethod 與指定的完整簽章。
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) 比對特定方法和MyMethod1MyMethod2個別的完整簽章。

排除特定類型及其衍生類型

您可以從分析中排除特定類型及其衍生類型。 例如,若要指定規則不應該在具名 MyType 類型及其衍生型別內的任何方法上執行,請將下列機碼/值組新增至 專案中的 .editorconfig 檔案:

dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType

選項值中允許的符號名稱格式(以 |分隔):

  • 僅限類型名稱(包含名稱的所有類型,不論包含類型或命名空間為何)。
  • 符號 文件識別碼格式的完整名稱,具有選擇性 T: 前置詞。

範例:

選項值 摘要
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType 比對所有具名 MyType 的類型及其所有衍生型別。
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 比對所有名為 MyType1MyType2 的型別,以及其所有衍生型別。
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType 比對具有指定完整名稱的特定型 MyType 別及其所有衍生型別。
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 比對特定類型和MyType1MyType2個別的完整名稱,以及其所有衍生型別。

虛擬程式代碼範例

違規

using System;
using System.Data;
using System.Data.SqlClient;

namespace TestNamespace
{
    public partial class WebForm : System.Web.UI.Page
    {
        public static string ConnectionString { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            string name = Request.Form["product_name"];
            using (SqlConnection connection = new SqlConnection(ConnectionString))
            {
                SqlCommand sqlCommand = new SqlCommand()
                {
                    CommandText = "SELECT ProductId FROM Products WHERE ProductName = '" + name + "'",
                    CommandType = CommandType.Text,
                };

                SqlDataReader reader = sqlCommand.ExecuteReader();
            }
        }
    }
}
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Linq

Namespace VulnerableWebApp
    Partial Public Class WebForm
        Inherits System.Web.UI.Page

        Public Property ConnectionString As String

        Protected Sub Page_Load(sender As Object, e As EventArgs)
            Dim name As String = Me.Request.Form("product_name")
            Using connection As SqlConnection = New SqlConnection(ConnectionString)
                Dim sqlCommand As SqlCommand = New SqlCommand With {.CommandText = "SELECT ProductId FROM Products WHERE ProductName = '" + name + "'",
                                                                    .CommandType = CommandType.Text}
                Dim reader As SqlDataReader = sqlCommand.ExecuteReader()
            End Using
        End Sub
    End Class
End Namespace

參數化解決方案

using System;
using System.Data;
using System.Data.SqlClient;

namespace TestNamespace
{
    public partial class WebForm : System.Web.UI.Page
    {
        public static string ConnectionString { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            string name = Request.Form["product_name"];
            using (SqlConnection connection = new SqlConnection(ConnectionString))
            {
                SqlCommand sqlCommand = new SqlCommand()
                {
                    CommandText = "SELECT ProductId FROM Products WHERE ProductName = @productName",
                    CommandType = CommandType.Text,
                };

                sqlCommand.Parameters.Add("@productName", SqlDbType.NVarChar, 128).Value = name;

                SqlDataReader reader = sqlCommand.ExecuteReader();
            }
        }
    }
}
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Linq

Namespace VulnerableWebApp
    Partial Public Class WebForm
        Inherits System.Web.UI.Page

        Public Property ConnectionString As String

        Protected Sub Page_Load(sender As Object, e As EventArgs)
            Dim name As String = Me.Request.Form("product_name")
            Using connection As SqlConnection = New SqlConnection(ConnectionString)
                Dim sqlCommand As SqlCommand = New SqlCommand With {.CommandText = "SELECT ProductId FROM Products WHERE ProductName = @productName",
                                                                    .CommandType = CommandType.Text}
                sqlCommand.Parameters.Add("@productName", SqlDbType.NVarChar, 128).Value = name
                Dim reader As SqlDataReader = sqlCommand.ExecuteReader()
            End Using
        End Sub
    End Class
End Namespace

預存程式解決方案

using System;
using System.Data;
using System.Data.SqlClient;

namespace TestNamespace
{
    public partial class WebForm : System.Web.UI.Page
    {
        public static string ConnectionString { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            string name = Request.Form["product_name"];
            using (SqlConnection connection = new SqlConnection(ConnectionString))
            {
                SqlCommand sqlCommand = new SqlCommand()
                {
                    CommandText = "sp_GetProductIdFromName",
                    CommandType = CommandType.StoredProcedure,
                };

                sqlCommand.Parameters.Add("@productName", SqlDbType.NVarChar, 128).Value = name;

                SqlDataReader reader = sqlCommand.ExecuteReader();
            }
        }
    }
}
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Linq

Namespace VulnerableWebApp
    Partial Public Class WebForm
        Inherits System.Web.UI.Page

        Public Property ConnectionString As String

        Protected Sub Page_Load(sender As Object, e As EventArgs)
            Dim name As String = Me.Request.Form("product_name")
            Using connection As SqlConnection = New SqlConnection(ConnectionString)
                Dim sqlCommand As SqlCommand = New SqlCommand With {.CommandText = "sp_GetProductIdFromName",
                                                                    .CommandType = CommandType.StoredProcedure}
                sqlCommand.Parameters.Add("@productName", SqlDbType.NVarChar, 128).Value = name
                Dim reader As SqlDataReader = sqlCommand.ExecuteReader()
            End Using
        End Sub
    End Class
End Namespace