顯示具有 null 標籤的文章。 顯示所有文章
顯示具有 null 標籤的文章。 顯示所有文章

2024年3月6日 星期三

[研究]ASP.NET, Fortify SCA 報告 Missing Check against Null ( Low )

[研究]ASP.NET, Fortify SCA 報告 Missing Check against Null ( Low )

2024-03-06

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

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

Fortify SCA 報告 Missing Check against Null 問題 ( 等級 Low ),把

string sessionID = Session["id"].ToString();

改成

string sessionID = Session["id"] != null ? Session["id"].ToString() : "";

問題依舊。

Filter Set 選 Quick View 時是沒有的,但選 Security Auditor View 會有。




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

【Fortify SCA】Recommendations:

如果一個函數可以回傳錯誤程式碼或其他任何能夠指明函數執行成功或失敗的證據,那麼請務必檢查錯誤情況,即便沒有明顯的跡象顯示會發生這個錯誤。除了避免安全性錯誤以外,許多乍看之下難以理解的錯誤,到最後都會歸究到使用包含 Unchecked Return Value 的錯誤方法進行呼叫。

建立一個容易使用的標準方法來處理應用程式的失敗。如果錯誤處理程序是簡單直接的,則程式設計師較不會忽略它。一個標準化的錯誤處理方法是,把檢查和處理錯誤狀況的常用函數寫入封裝程式,而不需程式設計師額外費力。執行並應用封裝程式後,便可使用自訂的規則禁止和限制使用非封裝函數的使用。 

範例 2:以下程式碼對 Item 屬性執行封裝,以檢查回傳值是否為 null,並在未定義要求的參數時使用預設值。

string safeGetParameter (HttpRequest request, string name)
{
string value = request.Item(name);
if (value == Null) {
return getDefaultValue(name);
}
return value;
}

敝人實際測試有問題



********************************************************************************
ChatGPT

Fortify SCA 報告中指出的 "Missing Check against Null" 問題是指在這行程式碼中沒有對 Session["oid"] 是否為 null 做適當的檢查。這可能會導致在 Session["oid"] 為 null 的情況下引發 NullReferenceException。為了解決這個問題,你可以進行如下修改:

string sessionID = "";
object idObject = Session["id"];
if (idObject != null)
{
    sessionID = idObject.ToString();
}

為了方便大量字串一行取代替換成另一行,可全部寫成一行

string sessionID = ""; object idObject = Session["id"]; if (idObject != null) { sessionID = idObject.ToString(); }

這樣做的話,首先將 Session["oid"] 存儲在一個臨時變數 oidObject 中,然後檢查 oidObject 是否為 null。如果不為 null,則將其轉換為字串賦值給 sessionOID,否則將 sessionOID 設置為空字串。這樣就可以避免在 Session["oid"] 為 null 時引發異常。





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

User

為何 string sessionID = Session["id"] != null ? Session["id"].ToString() : ""; 這種寫法不行 ? 當 Session["id"] 為 null 時會回傳 "" 啊 ?

ChatGPT

對於一般情況來說,你提供的寫法是可以正確處理當 Session["userID"] 為 null 時的情況的,它會將 sessionID 設置為空字串。但是 Fortify SCA 可能仍然會識別這種寫法為有問題,原因可能是 Fortify SCA 的靜態程式碼分析檢查方式的限制或者可能存在一些特殊情況。

如果 Fortify SCA 報告中顯示這種寫法有問題,你可以嘗試使用更保守的寫法來解決這個問題,比如使用臨時變數進行明確的 null 檢查,這樣可以確保 Fortify SCA 不再報告這個問題。

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

改寫成副程式


public class Example
{
    public static void Main()
    {
        // 調用副程式,並將 Session["id"] 的值傳遞給它
        string sessionID = GetSessionID(Session["id"]);
        Console.WriteLine("Session ID: " + sessionID);
    }

    // 定義副程式,將 Session["id"] 的值轉換為字符串
    public static string GetSessionID(object idObject)
    {
            // Fortify SCA 報告 Missing Check against Null ( Low )
            // string sessionID = Session["id"].ToString();

            // Fortify SCA 仍會報告 Missing Check against Null ( Low ),不認得這種精簡寫法
            // string sessionID = Session["id"] != null ? Session["id"].ToString() : "";

        string sessionID = "";
        if (idObject != null)
        {
            sessionID = idObject.ToString();
        }
        return sessionID;
    }
}


(下圖)實際測試,副程式寫法也可解決


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

改用 ChatGPT 建議後,Fortify SCA 報告相同問題,有可能無法判斷那種精簡的寫法。

其實 低等級問題,一般不會強制要求解決,只是因為報告上數量很大,想試試看會否增加掃描速度、減少報告檔案體積。

(完)

相關

2020年12月24日 星期四

[研究] ASP.NET、SQL Server、空字串、null 的恩怨情仇

[研究] ASP.NET、SQL Server、空字串、null 的恩怨情仇

2020-12-24

空字串 : 有個箱子,只是沒放東西。ASP.NET (C#) 是 "", MS-SQL Server 是 ''

null : 連箱子都沒有。

Undefined (未定義) : 是否為箱子都不知道。

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

在測試網頁上開發的查詢功能時,


<asp:SqlDataSource ID="SqlDataSource_Production_sub_type" runat="server" ConnectionString="<%$ ConnectionStrings:pmsConnectionString %>"

        SelectCommand="SELECT N'*' AS [Production_sub_type], N'<全部>' AS [Production_sub_type_display],'0' AS Priority

UNION

SELECT distinct [Production_sub_type], [Production_sub_type] AS [Production_sub_type_display],'1' AS Priority  FROM [ProductionList] ORDER BY Priority "></asp:SqlDataSource>


次類別 (Production_sub_type):<asp:DropDownList ID="DropDownList_Production_sub_type" runat="server" DataSourceID="SqlDataSource_Production_sub_type" DataTextField="Production_sub_type_display" DataValueField="Production_sub_type"></asp:DropDownList><br />


因為 table 中某些 records 的該欄位是 '' (空字串),結果下拉選單選到該項時候,查不到,選到其他項,正常。


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

測試

string queryString = SqlDataSource1.SelectCommand;

... (略)

queryString = queryString + queryString.Replace("@Production_sub_type", "N'" + DropDownList_Production_sub_type.SelectedValue + "'");

... (略)

把 queryString 內容丟到 SSMS ( Microsoft SQL Server Management Studio) 中執行是正常的。


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

敝人盡量不用 null  (可能有人讚同,有人反對,有人無意見)


(1)以前上課的老師建議


(2)個人經歷,例如

單一 table 倒沒甚麼問題,如過是多個 table 做 join 做 count、加、減、總和 或某些運算,

敝人碰過 SSMS 上可以正常執行一道複雜的 SQL (沒有參數),

ASP.NET 的 GirdView 無法顯示的情況,就是因為產出的欄位有些數值、有些null 

(詳情不記得,或許可以用 SQL 語法 CASE WHEN 處理後,再給 GridView 就可以顯示)


(3) SQL 語法判斷欄位值一般用 fieldName = '某值'

就算那個值是空字串也是這樣寫,但若是 null,要寫 filedname is null,指令下法不一致


所以 ASP.NET 網頁下拉選單選擇沒有值的項目,DB 要考慮把 '' 和 null 項目都撈出

ASP.NET 中 SQL 語法可能要寫成

WHERE (fieldname=@DropDownListChoice or (@DropDownListChoice=N'' and fieldname is null))


SQL 語法變麻煩了,如果這個欄位是數個 table join 時 on 的條件使用,那複雜度....


或者該欄位 '' 和 null 意義不同,ASP.NET 下拉選單可能要替 null 另給個名稱,例如 "null",

但好死不死,某些 table 的某些欄位的部分欄位值中有稱為 "null" 的字串值 ( 不是 null )

( Web API / Web Service 呼叫別系統而取得,儲存下來的 )


(4)不想欄位中又是 null,又是 "" (空字串)


--------------------


不用 null,SQL Server 的 Database Schema - Table Schema 設計


SQL Server 的資料表(table)「設計」時新增一個欄位(field)時候,預設是「允許Null」,且預設值是 null

敝人習慣把「允許Null」勾選拿掉,

若「資料型態」為字串類的,敝人會把預設值設定為 ''

若「資料型態」為數值類的,敝人會把預設值設定為 ''

若「資料型態」為日期類的,敝人會把預設值設定為 getdate() 或某個日期

若「資料型態」為布林值類的 (bit),敝人會把預設值設定為 1 或 0


(註:bit 後來不太用,因為原本需求只是表示 "未完成" 和 "完成",

後來需求又變,要求增加一種或 N 種狀態 (ex : 填寫中、階段X、階段Y、、,

只好把 bit 換成 nvarchar、int或其他,不然就新增一個欄位來用,

然後修改所有受影響的諸多程式 )


--------------------


不用 null 後,ASP.NET (WebForm) 的 .aspx 困擾與設計


<asp:SqlDataSource ID="SqlDataSource1" ..(略)

        <InsertParameters>

            <asp:Parameter Name="Production_sub_type" Type="String" />

要改成下面,不然如果沒有輸入值,會自動把空字串 "" 轉成 null,因為敝人設定欄位不允許 null,就出錯了

            <asp:Parameter Name="Production_sub_type" Type="String" DefaultValue="" ConvertEmptyStringToNull="false" />


日期欄位

<asp:Parameter Name="CreateDateTime" Type="DateTime" />

改為

<asp:Parameter Name="CreateDateTime" Type="DateTime"  DefaultValue="<%: DateTime.Now%>" ConvertEmptyStringToNull="false" />

<asp:Parameter Name="CreateDateTime" Type="string"  DefaultValue='<%: DateTime.Now.ToString("yyyy-MM-dd")%>' ConvertEmptyStringToNull="false" />


另外就是 需求者 希望該筆資料沒有填寫或送出時,

時間欄位和數值欄位不要顯示值 (只好在 GirdView 的 RowDataBound 或 DataBound 或其他地方動手腳)


--------------------

不用 null 後,ASP.NET (WebForm) 的 .aspx.cs 困擾與設計


也是這次碰到的情況,想到可能是 "" 被轉成 null 所以查不到


SqlDataSource1.SelectCommand = @"

-- DECLARE  @Product_ancestor_name nvarchar(50)

-- SET @Product_ancestor_name=N''


SELECT * FROM [ProductList] 

WHERE ... (略)

AND (@Product_sub_type ='*' or Product_sub_type=@Product_sub_type)


改成下面


AND (@Product_sub_type ='*' or Product_sub_type=@Product_sub_type or ( Product_sub_type='' and @Product_sub_type is null ))


但是無效 (有寫錯?)


後來在

SqlDataSource1.SelectParameters.Add("Product_sub_type", DropDownList_Product_sub_type.SelectedValue );

下方增加一行

SqlDataSource1.SelectParameters["Product_sub_type"].ConvertEmptyStringToNull = false;

成功解決。

註:另一種方式是 DropDownList 的 SELECT 用 WHERE 條件排除掉 "",讓 DropDownList 沒得選 "",但似乎不完善。

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

至於倒底怎樣最好,看情況,見人見智吧。

(完)