2024年3月18日 星期一

[研究]ASP.NET, Fortify SCA 說 SqlCommand command = new SqlCommand(queryString, connection); 有 SQL Injection 問題

[研究]ASP.NET, Fortify SCA 說 SqlCommand command = new SqlCommand(queryString, connection); 的來源不可靠,有 SQL Injection (Security Auditor View: Low) 問題,該如何改 ?

2024-03-18

環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C# + SQL Server 2019 + SQL Server Management Studio (SSMS) 19

********************************************************************************

下面程式 Fortify SCA 說 SqlCommand command = new SqlCommand(queryString, connection); 的來源不可靠,該如何改 ?

string queryString = SqlDataSource1.SelectCommand;
using (SqlConnection connection = new SqlConnection(
    WebConfigurationManager.ConnectionStrings["pmsConnectionString"].ConnectionString))
{
    SqlCommand command = new SqlCommand(queryString, connection);
    command.Parameters.Clear();
    command.Parameters.AddWithValue("@loginID", loginID);
    command.Parameters.AddWithValue("@queryedID", Common.MyAntiXssFilter(DropDownList_id.SelectedValue));
    connection.Open();
    using (SqlDataReader reader = command.ExecuteReader())
}

ChatGPT

Fortify SCA可能提示這段程式碼有安全性風險,因為它可能容易受到SQL注入攻擊。為了改善這個問題,你可以使用參數化查詢來處理輸入,而不是直接將查詢字串與用戶輸入串接在一起。這樣可以防止SQL注入攻擊。以下是修改後的程式碼:

string queryString = "SELECT * FROM YourTable WHERE LoginID = @loginID AND QueryedID = @queryedID";

using (SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["pmsConnectionString"].ConnectionString))
{
    SqlCommand command = new SqlCommand(queryString, connection);
    command.Parameters.Clear();
    command.Parameters.AddWithValue("@loginID", loginID);
    command.Parameters.AddWithValue("@queryedID", Common.MyAntiXssFilter(DropDownList_id.SelectedValue));

    connection.Open();
    using (SqlDataReader reader = command.ExecuteReader())
    {
        // 在這裡處理讀取的資料
    }
}

這裡,我們將SQL查詢字串硬編碼到程式碼中,並使用@loginID和@queryedID來代表參數。這些參數將由command.Parameters.AddWithValue方法來設定,這樣可以確保用戶輸入不會被解釋為SQL指令,從而防止SQL注入攻擊。

********************************************************************************

為何不能 string queryString = SqlDataSource1.SelectCommand;  

ChatGPT

在ASP.NET Web Forms中,SqlDataSource是用於資料存取的控制項之一。但是,SqlDataSource.SelectCommand屬性在設定時是一個string,而不是一個SQL命令物件(如SqlCommand),因此無法直接使用。

SqlDataSource.SelectCommand是用來指定要在資料庫中執行的SQL查詢字串,它只是一個字串。而且,它通常在ASP.NET控制項的生命週期中,在執行時階段才會被使用,而不是在編譯時。因此,直接將SqlDataSource.SelectCommand賦值給另一個變數是不適當的。

如果您想要在程式碼中使用相同的SQL查詢字串,您應該將查詢字串硬編碼到程式碼中,就像之前示範的那樣。

********************************************************************************

不想  queryString  重寫一次和  SqlDataSource1.SelectCommand 相同的內容,也為了 SqlDataSource1.SelectCommand 變化時,queryString 又重新寫一次,有好方法? 

ChatGPT

您可以使用SqlDataSource的SelectParameters屬性來設定查詢的參數,這樣您就可以在程式碼中使用SqlDataSource的SelectCommand而不需要重複寫一次查詢字串。下面是修改後的程式碼:

using (SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["pmsConnectionString"].ConnectionString))
{
    SqlCommand command = new SqlCommand(SqlDataSource1.SelectCommand, connection);

    // 將 SqlDataSource 的參數設定給 SqlCommand
    foreach (Parameter parameter in SqlDataSource1.SelectParameters)
    {
        command.Parameters.AddWithValue(parameter.Name, parameter.DefaultValue);
    }

    // 設定其他參數
    command.Parameters.AddWithValue("@loginID", loginID);
    command.Parameters.AddWithValue("@queryedID", Common.MyAntiXssFilter(DropDownList_id.SelectedValue));

    connection.Open();
    using (SqlDataReader reader = command.ExecuteReader())
    {
        // 在這裡處理讀取的資料
    }
}

********************************************************************************

【實際測試】

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" 
    Inherits="WebApplication1.Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:SqlDataSource ID="SqlDataSource1" runat="server"></asp:SqlDataSource>
        <asp:DropDownList ID="DropDownList_id" runat="server"></asp:DropDownList>
        <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
        <asp:Button ID="Button2" runat="server" Text="Button" OnClick="Button2_Click" />
        <asp:Button ID="Button3" runat="server" Text="Button" OnClick="Button3_Click" />
    </form>
</body>
</html>


Default.aspx.cs

using System;
using System.Data.SqlClient;
using System.Web.Configuration;
using System.Web.UI.WebControls;

namespace WebApplication1
{
    public partial class Default : System.Web.UI.Page
    {
        string loginID = "abc";
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            string queryString = SqlDataSource1.SelectCommand;
            using (SqlConnection connection = new SqlConnection(
                WebConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString))
            {
                SqlCommand command = new SqlCommand(queryString, connection);
                command.Parameters.Clear();
                command.Parameters.AddWithValue("@loginID", loginID);
                command.Parameters.AddWithValue("@queryedID", DropDownList_id.SelectedValue);
                connection.Open();
                using (SqlDataReader reader = command.ExecuteReader())
                {
                    //
                }
            }
        }

        protected void Button2_Click(object sender, EventArgs e)
        {
            string queryString = "SELECT * FROM YourTable WHERE LoginID = @loginID AND QueryedID = @queryedID";

            using (SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString))
            {
                SqlCommand command = new SqlCommand(queryString, connection);
                command.Parameters.Clear();
                command.Parameters.AddWithValue("@loginID", loginID);
                command.Parameters.AddWithValue("@queryedID", DropDownList_id.SelectedValue);

                connection.Open();
                using (SqlDataReader reader = command.ExecuteReader())
                {
                    // 在這裡處理讀取的資料
                }
            }

        }

        protected void Button3_Click(object sender, EventArgs e)
        {
            using (SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString))
            {
                SqlCommand command = new SqlCommand(SqlDataSource1.SelectCommand, connection);

                // 將 SqlDataSource 的參數設定給 SqlCommand
                foreach (Parameter parameter in SqlDataSource1.SelectParameters)
                {
                    command.Parameters.AddWithValue(parameter.Name, parameter.DefaultValue);
                }

                // 設定其他參數
                command.Parameters.AddWithValue("@loginID", loginID);
                command.Parameters.AddWithValue("@queryedID", DropDownList_id.SelectedValue);

                connection.Open();
                using (SqlDataReader reader = command.ExecuteReader())
                {
                    // 在這裡處理讀取的資料
                }
            }
        }
    }
}

Fortify SCA掃描結果


********************************************************************************

User

Fortify SCA 報告 SqlCommand command = new SqlCommand(SqlDataSource1.SelectCommand, connection); 有 SQL Injection 問題

ChatGPT

如果Fortify SCA報告SqlCommand的建構函式中的SqlDataSource1.SelectCommand有SQL注入問題,那麼原因可能是因為Fortify SCA無法直接分析和確定SqlDataSource1.SelectCommand是否是安全的。 即使SqlDataSource1.SelectCommand在設計時是使用了參數化查詢,Fortify SCA也可能無法辨識這一點。

********************************************************************************

目前的解決方法,似乎只能【硬編碼】,有空再研究看看有無其他解法。

(完)

相關


沒有留言:

張貼留言