2017-10-20 51 views
1

我必須將一個SQL字符串注入數據庫中供第三方讀取,執行它並使用結果生成報告。由於用戶可以選擇列通緝的報告,以及重命名列,我已經有這樣的代碼結束:清理不可參數化的sql的最佳方式

string sql = "SELECT "; 
foreach(KeyValuePair<string, string> field in report.fields) 
{ 
    sql += "[" + field.Key + "] as [" + field.Value + "]; 
} 
sql += " WHERE [email protected]"; 

此查詢我可以參數化的唯一部分是WHERE子句,但如果我在網上的研究沒有被誤導,就沒有辦法參數化SELECT子句中的列名和別名。現在,鑑於我無法改變程序的工作方式(我必須爲第三方生成一個有效的SQL查詢來執行它),那麼對輸入字符串進行清理的最佳方式是什麼?

我已經解決了關於列名稱的部分,通過檢查列表的有效列,但我不能這樣做的別名,可以是任何小於80個字符的字符串用戶願意給。

+0

這是一個很大的X/Y問題。一個答案是不要這樣做,並改變你的程序設計不需要這個。 – Magisch

+0

另一種方法是僅允許字母數字ASCII字符和指定的空白字符,然後也可以轉義字符串 – Magisch

+0

您錯過了關於「我無法改變程序工作方式」的部分。這讓你的評論成爲XY咆哮的一大提示。順便提一句,更多的解決方案是......我可以將名稱別名上的有效字符限制爲正則表達式。我會給它一個想法。 – Rekesoft

回答

1

對,所以你有一個SQL佈局,你不能改變,這就需要你這樣做。這是不幸的,但讓我們充分利用它。

正如你在你的評論中所述,你可能需要一些特殊字符的支持,所以特意轉義這些特殊字符。

除此之外,您應該將允許的名稱縮小爲字母數字字符和可能的空格。根據您選擇的驗證機制驗證這些機制,例如正則表達式,並僅允許這些字符。這可能會讓你幾乎免於SQL注入。

這不是最佳,但它似乎是你在這種情況下可以做的最好的。

1

正如您所指出的那樣,沒有辦法參數化列名和別名。因此,您打開SQL注入。爲了最大限度地減少問題,您可以使用quotename,這與您當前使用的方法類似。

string sql = "SELECT "; 
foreach(KeyValuePair<string, string> field in report.fields) 
{ 
    sql += "quotename(" + field.Key + ") as quotename(" + field.Value + ")"; 
} 
sql += " WHERE [email protected]"; 
+0

是的,這是我現在使用的最新方法。事實上,我使用QUOTENAME(「+ field.Value.Replace(」'「,」''「)+」)「,但我仍然不確定。 – Rekesoft

+0

不錯,那麼我猜你沒有太多可以做得更多。 –

相關問題