即使這樣攻擊依然可能實現:如果攻擊者可以不經過程序而往系統插入數據。比如攻擊者有一個email接口,或者有一個可以控制的錯誤記錄數據庫。最好總是驗證所有的數據,包括系統裡的數據,驗證函數調用很簡單,比如:
if ( not isValIEd( "email", request.querystring("emil") ) ) then
response.end
或者其他的方法
[長度限制]
有時候輸入對數據的長度加以限制會使攻擊困難許多,這的確阻止了一些攻擊,但一個很短的SQL語句也可能造成非常大的危害:
Username: ';shutdown--
關閉SQL-Server,只用了12個字符。另一個例子:
drop table <tablename>
如果長度限制是在字符串過濾後,另一個問題可能會發生。假設用戶名被限制在16個字符之內,密碼也被限制在16個字符之內,下面的用戶名和密碼結合可以執行'shutdown'命令:
Username:aaaaaaaaaaaaaaa'
PassWord:'; shutdown--
原因是程序過濾用戶名最後的單引號,但是字符串又被切回到16個字符,刪除了過濾的單引號。結果是密碼域可以包含一些SQL, 只要它以一個單引號開始,最後的查詢會變成這樣:
select * from users where username = 'aaaaaaaaaaaaaa'' and passWord=''';shutdown--
用戶名在查詢裡就變成:
aaaaaaaaaaaaaaa' and passWord='
後面附上的SQL被執行。
[躲避審核]
SQL Server在sp_traceXXX系列的函數包含豐富審核接口,它可以記錄任何數據庫裡的事件。這裡我們特別感興趣的是T-SQL事件,它記錄了所有的SQL語句以及服務器上准備好的和已運行了的批處理。如果這個級別的審核開啟的話,所有我們討論的注入都將被記錄下來有經驗的數據庫管理員將會看到所有發生的事情。但是如果攻擊者附加下面的字符:
sp_passWord
到一個Transact-SQL語句,這個審核記錄如下:
-- 'sp_passWord' was found in the text of this event.
-- The text has been replaced with this comment for security reasons.
這在所有的的T-SQL日志記錄時都會發生,即使'sp_password'出現在注釋中。這當然是在用戶傳遞sp_passWord時有意隱藏用戶的明文密碼,但這對攻擊者相當有用。
所以,為了隱藏所有的注入攻擊者只需要在注釋符'--'後面加一個字符串:
Username: admin'--sp_passWord
事實上一些執行了的SQL將被記錄,但是查詢字符串本身被強制不記錄。
[防 范]
這部分討論一些針對這些攻擊的防范措施。輸入驗證已經討論過了,一些代碼也給出了,後面我們研究SQL-Server防范問題。