Skip to content

Instantly share code, notes, and snippets.

@it9gamelog

it9gamelog/i.md Secret

Last active May 29, 2022 07:16
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save it9gamelog/f89cbb8a3e246f9f56942e202fda6c79 to your computer and use it in GitHub Desktop.
Save it9gamelog/f89cbb8a3e246f9f56942e202fda6c79 to your computer and use it in GitHub Desktop.
面試問題/解 - SQL Injection

Web安全的SQL Injection是一個怎麼樣的問題?在一般PHP/Mysql的軟件中,應該採取什麼方法解決? https://www.facebook.com/groups/616369245163622/permalink/1523477287786142/

本身試卷時間很充裕,只要有引用信息的話也允許網上搜索和抄襲答案。

作答例

題目有兩個問號,就當然要回答兩個重點,是考試的基本常識吧?XD

SQL Injection是…

SQL Injection攻擊是一個接受外部輸入的程式,由攻擊者傳入一些含有SQL語法關鍵字的特製字符串,而因程式裏不當地拼接SQL語句,使SQL語句的意思乃至功能被非法改變。 這種攻擊通常會導致數據洩漏或篡改,甚至通過篡改登入信息而達到提升權限,或把數據破壞達至服務不可用攻擊 (DoS Attack)。

例如這樣的一句SQL: SELECT * FROM performance_reports WHERE staff_username='$USERNAME',原意是查詢某個人的表現報告。 如果$USERNAME被惡意填寫成是' OR 1=1 OR 1=',就會把所有人的都抓了出來。

在PHP/MySQL的解決方法

在原生PHP下避免這個漏洞,SQL裏的參數應改寫成使用placeholder形式,然后使用PDO::prepare,再在其PDOStatement使用bindParam/bindValue或在execute時傳参數

例如這樣寫

$sth = $dbh->prepare('SELECT * FROM performance_reports WHERE staff_username=?');
$sth->execute(array($USERNAME));

事實上,上面的parameterized query在各種語言和各大SQL都是一個標準功能,也是將參數傳進SQL推崇的辦法。無論如何,絕對要避免自行拼接字符串。

如果用了各種Object-relational mapping (ORM)的套件,通常那些Entity的屬性都處理了這個問題,不用再操心。但若ORM拿出DB Handle直接取用的話,還是要當心同樣問題。

app用的DB connection user只保留需要的權限 (如Select、Insert、Update、Delete),可以在萬一有漏洞時,都不會被Drop Database/Trunacte Table。 洩及Password要用適當的crypt algorithm,無論是不是SQL都需要做的。一般數據要不要加密去避免洩漏則很視乎業務需要和要衡量性價比。

解題

因為一開頭是說了可以抄了,所以有不少人就直接把網上見到某一篇文章copy and paste,沒有怎樣再處理。有時或copy and paste幾篇,但每篇之間有時候是有衝突。 而因為PHP版本尤久,有時也會抄錯一些在PDO功能出現前的文章。很多都沒有再交差參照官方文檔,導致信息其實是很過時的都不知道。

而由於我面的都是中國人,習慣使用百度的人多,但百度搜出來的結果有多好是眾所周知。中國地區特例: 如果引用表示是由Google或英文網站找到的,會加分。 提及 https://xkcd.com/327/ 也會加印象分 :D

解釋SQL Injection方面

很大多數都不能很精準說明問題,只能籠統說「是SQL注入(幫我翻譯成中文了謝謝)」、「一個數據庫的安全性問題」、「輸入參數問題」。 也絕少人會用code寫出實際例子。那種解釋,即使是一個內行人但碰巧不知道SQL Injection看到,也不會明白是什麼的一回事。

有的沒的的建議

其他幫到忙,本身也是Best Practices的方法如:

  • 輸入檢查
  • 數字的強制轉成int
  • Regular Expression檢查和把合法的字抽出來

這些都是平常要做,無論是不是為了SQL Injection。 但如果我的系統就是SNS,user可以寫任何的文字,只要是合法的String都要支持,包括'/**/在內的話,那無論怎樣檢查也不會避到SQL Injection。

同理,而Keyword過濾在很多場合都不會合適。見到的話會扣印象分。

即時死亡的建議

  • 極速死亡第三位: addslashes 因為addslashes在Big5/GBK/JIS會出錯防止不了,不過其實UTF-8的話還好
  • 極速死亡第二位: magic_quotes_gpc 一來早就去掉了這個功能,二來它也是個addslashes,三來用起來非常麻煩易出錯
  • 極速死亡第一位: htmlspecialchars 不只一個人這樣回答過。完全沒半點關係的作答…

我也不知道為什麼中國人那麼厲害,都能找到這麼過時的信息。htmlspecialchars更加是不知所謂。

回答這樣的答案即是,搜索工功夫不行,也不會和官方權威文㭻去對比。 代表如果日後碰到新的問題或需要學習新的技術,很可能無法自理。基本上看到這些字就沒有機會。

其實parameterized query真的是業界通用的唯一標準答案(沒有之一)。但有很多人的答案都莫名的把PDO這一選項最後才提出,而先提及了輸入檢查等。 我也不清楚是中國特式網誌寫得差,還是因為沒聽過PDO/parameterized query所以怕放它在第一個。

說實話,只回答一個parameterized query,和囊括幾個可有可無的選擇之間比,看到前者更開心。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment