對付SQL Injection,換掉單引號到底夠不夠?

雖然現在遇到使用者輸入條件查詢DB,我一律都用參數化查詢(順推超好用的Dapper)不再偷懶組裝SQL指令,但關於SQL Injection,我心中始終藏著一個疑問:流傳千古的… WHERE Col = '" + input.Replace("'", "''") + "'"換單引號大法,人人都知它不夠安全,但網路流傳一種說法,指稱換單引號只是自欺欺人根本無效,奇怪的是卻很少看到它被打穿的實例。我完全同意置換法不夠安全,黑名單法一旦漏列就會破功,但既然要把它說得不堪一擊,拿點證據出來很難嗎?很難嗎?很難嗎?

我試了,還真的不簡單…

爬文找到幾種主張置換法無效的說法:

  • 遇到WHERE NumberCol = " + input.Replace("'", "''")時置換無效
    如果欄位是數字型別,將input字串轉成數字才嚴謹,寫成這様是自己跳坑,不列入考慮
  • 利用編碼轉換偷渡單引號
    字串置換函式、資料庫驅動程式或資料庫採用非Unicode編碼,透過巧妙安排讓傳入的Unicode字串轉換後形成單引號。若以SQL Server為例,Client與Server幾乎都已是Unicode,以C# System.String.Replace()、內建SqlClient程式庫、SQL2005-2012為例,置換單引號的做法不致留下轉碼漏洞(參考),但在其他環境則很難說。
  • 利用單引號等效字元
    爬文發現一種傳說中的神奇字元0x02bc(Modifier Letter Apostrophe),串接在SQL指令效果等同單引號。這讓我為之一震,可以替代單引號的神祕字元?好一隻黑天鵝

眾多說法中最吸引我目光的莫過0x02bc字元,尤其不少人說這招在SQL Server及MySQL都管用,甚至有範例程式:參考

string badValue = ((char)0x02BC).ToString();
badValue = badValue + ";delete from widgets--";
string sql = "SELECT * FROM WIDGETS WHERE ID=" + badValue.Replace("'","''");
TestTheSQL(sql);

迫不及待想驗證,很可惜,對SQL Server Express 2014做了類似測試,攻擊失敗!0x02bc被視為一般字元,安全過關。

如果SQL不行,那MySQL呢?特地安裝了MySQL 5.7 Community,如法泡製拔出0x02bc進攻,再次鎩羽而歸。

由以上實測,至少證明0x02bc已不具備打穿SQL Server Express 2014跟MySQL 5.7的神奇功效。或許在以前的某些SQL或MySQL版本上是可行的,但至少在我測的兩種DB版本已不存在。無心再去找活化石老DB試玩,就此打住。

意思是我們可以安心繼續組SQL字串再用單引號置換法嗎?當然不是,遇上特定資料庫、程式庫版本,只置換單引號必然存在等效特殊字元偷渡做亂的可能性,無論換掉多少可疑的字元,只要有漏網之魚就會破功,這是黑名單法無法被補強的本質缺陷。所以,乖乖使用參數化查詢,不要組裝SQL指令才是治本之道!

【結論】我百分之百贊同「置換單引號不能杜絕SQL Injection,在某些特殊情境下會被攻破」,但在沒有強力佐證的情況下要說「哼!換掉單引號根本沒屁用」則略嫌浮誇。

以上看法屬爬文及實驗後的心得,受限個人所見所學,就當拋磚引玉吧,以下開放想打臉、補刀的朋友提出實證討論。(我真的好想看到單引號置換法被打穿)

歡迎推文分享:
Published 20 March 2016 11:22 PM 由 Jeffrey
Filed under: ,
Views: 10,234



意見

# 可可 said on 20 March, 2016 11:24 AM

用LINQ不就好了?

# mis2000lab said on 20 March, 2016 08:54 PM

Q : 用LINQ不就好了?

我喜歡黑暗執行緒這篇文章(blog.darkthread.net/post-2008-05-14-transaction-in-linq-to-sql.aspx)結尾"最後兩段"的說法。  :-)

# 霧隱虎 said on 21 March, 2016 07:04 AM

Dear 黑大:

有使用偏門資料庫FireBird,另外附上測試資料與測試DB,無 Injection問題

# 霧隱虎 said on 21 March, 2016 07:05 AM

github.com/.../KirigakuretoraProjectsHexadecimal1st

# Jeffrey said on 21 March, 2016 08:59 PM

to 霧隱虎,感謝測試,0x02bc字元目前戰績:0勝3敗。

# OXXO said on 06 April, 2016 08:41 PM

LINQ不是萬能,有時你還要用的組SQL字串才能WORK

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<March 2016>
SunMonTueWedThuFriSat
282912345
6789101112
13141516171819
20212223242526
272829303112
3456789
 
RSS
創用 CC 授權條款
【廣告】
twMVC
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication