[研究]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也可能無法辨識這一點。
********************************************************************************
目前的解決方法,似乎只能【硬編碼】,有空再研究看看有無其他解法。
(完)
相關
沒有留言:
張貼留言