Re: [請益] 網站資安需注意哪些?

看板PHP作者 (天真可愛CQD)時間6年前 (2018/06/04 19:23), 6年前編輯推噓21(2100)
留言21則, 21人參與, 5年前最新討論串3/4 (看更多)
想試著來全部回答一下,我本業不是網路安全,所以可能內容會需要被訂正... : 1. 像是 XSS 是什麼?會帶來什麼危險?用 htmlentities 跟 htmlspecialchars 這兩個函式來防禦有什麼差別? 白話解釋 XSS:「別人在你的網站上塞他的 javascript」 可能的危害 - 所有使用者都會看到嘲笑你的對話方塊 - 你的網站被塞別人的廣告 - 別人可以用 javacsript 控制你的使用者做...任何在他在網站上能做的事情 - 其他很多... htmlenties 會把「每一個字」都編碼成 html entity,htmlspecialchars 只轉換 & " ' > < 這五個。 在大多數情況下這兩者的防禦效果差不多,差異在於出來的檔案大小會不一樣。 不過我記得有個 UTF-7 什麼碗糕的的鬼可以打穿 htmlspecialchars,只要 charset 用 utf-8 就沒事 剛剛一下 Google 找到都是講 wordpress 爛掉的事情就是了... (EDIT: 我弄錯了,是 htmlenties 會被 UTF7 攻擊打穿...) : 2. LFI 是什麼?除了被 access 到 /etc/passwd 之外,有沒有可能讓 source code 洩露? 白話解釋 LFI:「別人可以亂讀你的檔案」 a.php?file=aaa.doc => 吐 aaa.doc 的內容給他 a.php?file=a.php => 把 a.php 的內容(咦,不就自己嗎)吐給他 我看過比較有趣的搞法是讀 .git/ 把整個 repo 拿走,這樣還不用暴力硬掃你有哪些檔案... : 3. SQL Injection 的原理是?用 PDO 真的可以一勞永逸嗎? mysqli_real_escape_string 真的有助於防止 SQL injection 嗎? 組 SQL 字串的時候塞奇怪東西讓 SQL 的意思跟你以為的不一樣,然後幹奇怪的事情 例如 $id = $_POST['id']; // '123or1=1' $sql = "select * from user where id = {$id}"; 出來會是 select * from user where id = 123or1=1 然後所有的使用者資料就一起噴出來了 而且這個例子用 mysqli_real_escape_string 正好搞不定 理想的做法是不要自己組 SQL 字串,用 prepared statement 然後 bind 參數。背後做的事情大約像這樣 mysql> PREPARE stmt FROM "SELECT * FROM user WHERE uid = ?"; 「DB 哥哥,我等下要跑『select * from user where uid where id = ?』,問號我等下再跟你說是什麼」 Statement prepared 「好喔,我準備好了等你的參數」 mysql> SET @param='123or1=1'; EXECUTE stmt USING @param; 「DB 哥哥,參數是 '123or1=1' 喔,麻煩把結果跑給我」 Query OK, 0 rows affected (0.00 sec) Empty set (0.00 sec) 「喔, id 是『123or1=1』嗎?我看看...一個都沒有喔!」 是說看到上面推文才知道 PDO 的 mysql driver 預設是模擬的,不是真的叫 DB 做 prepared statement。 可以用 PDO::ATTR_EMULATE_PREPARES 這個選項切換... 爬了一下別人的 code Laravel 內部做 PDO 的時候會強制設定用真的 prepared statement doctrine 的 dbal 跟 maghead 乍看之下沒有管這件事 希望 PHP(或該說 MySQL Driver )模擬的效果夠好... : 4. 什麼是 SSRF?會讓系統服務遭受什麼樣的風險? 白話解釋 SSRF:「別人讓你的 server 幫他送 request 給其他機器」 例如抓檔案的 URL 如果可以自己亂填 upload_image.php?url=https://example.com/porn.png
然後你正好知道人家內部的網路狀況,或是剛好靈光一閃,就可以拿來打看看(? upload_image.php?url=https://dashboard.example.com/ upload_image.php?url=http://127.0.0.1/ 等於是讓人家間接鑽進內網幹亂連機器幹事情,而且你會以為是你的內部機器要連所以不一定擋得下來。 SSRF 我不確定有沒有什麼好招可以處理,只能想到黑名單白名單.... : 5. extract 這個函式很好用,但會不會不知不覺間被拿來提權? extract 把 array 的內容直接拆開變成變數 然後有些人會覺得 extract($_GET) 很好用 於是別人就可以亂打網址 ?var1=aaa&var2=bbb 來亂改你 code 裡面的變數內容,什麼魔法都能變得出來.. 我覺得啦,這年頭還是別這樣寫... : 6. serialize 跟 unserialize 的使用時要注意什麼? 唔...我原本猜你指的是「unserialize 的東西可能是別人家過料的,然後就可以亂改變數內容」 類似 extract 的狀況 不過為防萬一找了一下,發現 PHP 跟 unserialize() 有關的安全漏洞還真不少.... 我「猜」對 serialize 字串做數位簽章(例如 HMAC)驗證內容無誤,大概還擋得住。 不過更好的作法應該是...別 unserialize 任何使用者有機會動手腳(不論是網址帶入或 post 進來)的東西。 : 7. Hash 用戶的密碼是用什麼演算法好呢?bcrypt : ?argon2?它們又有什麼差別? 簡單的答案: 什麼演算法都不要管,PHP(5.5+)都包好了 把密碼這樣存 $hash = password_hash("password", PASSWORD_DEFAULT); 然後這樣比對密碼是否正確(別在 DB 比對) $passwordOK = password_verify($input, $storedHash); 然後用這裡的範例檢查有沒有需要更新密碼 hash http://php.net/manual/en/function.password-needs-rehash.php 最後,PHP 升級你盡量跟著升級。 真正的答案: 現代 hash 演算法的敵人主要有幾種 ## 從數學,相對容易算出碰撞值 例如數學方法可以快速算出其他值的 hash 跟你密碼的 hash 一樣 對應法: 選沒有已知攻擊的演算法 - md5 陣亡(2004的論文) - sha1 進棺材了(同一個人寫過 sha1 的論文,Google 做過示範攻擊) 還有,沒事就看一大堆講這種事情的文章.... ## 從實作上被攻擊 有些實作有 side channel attack 的問題,例如可以從計算時間推算數值 甚至有些比較誇張的,可以錄你電腦的聲音推斷 CPU 多忙,猜出在算的值是什麼... 對應法: 常常更新系統套件,用 libsodium 或是 PHP 5.5+ 的 password_ 系列 function 來算 hash 還有,沒事就看一大堆講這種事情的文章.... ## 預先算好巨大的對應表(所謂 rainbow table) 就是有人會先算好一大堆字串的 hash,做成查詢表方便對照。 所以看到 7c4a8d09ca3762af61e59520943dc26494f8941b 可以直接查出這是 123456 的 sha1 是說,有個網站叫做 CrackStation,線上讓你查 hash 對應表.. 對應法: 內容加鹽或是給 iv,每筆資料的鹽或 iv 都要都不一樣,而且要夠長 這會讓對應表很難做 也可以用 PHP 5.5+ 的 password_ 系列算,他預設會隨機產鹽撒進資料來算 hash ## 用巨大的運算力量暴力硬算 通常是雲端出租 GPU,也有靠 ASIC 之類的專門機器。 感謝數位挖礦產業,這方面的技術突飛猛進... 對應法: 選難以平行化運算的,記憶體使用量大的,計算效能差的 然後也許因此不該選 sha256,因為 bitcoin 挖礦就是在算 sha256,有利可圖就有專門產業... bcrypt 是前幾年的佼佼者,而 argon2 是最近幾年的國際 hash 比賽冠軍。 PHP 預設的密碼 hash PASSWORD_DEFAULT 應該還是 bcrypt 有找到 PHP 的 RFC 提到「暫時不把 PASSWORD_DEFAULT 改成 ARGON2」 https://wiki.php.net/rfc/argon2_password_hash 不過理由我一下沒找到 然後「最好的 hash 演算法」是會隨著時間變化的 : 8. json_encode 跟 json_decode 有什麼潛在問題嗎?有沒有可能造成 DoS? 其實我直覺想到的是「爬 log 的時候用 json_decode 好慢,我都用 jq 先 parse 過」... 不過我猜你指的是可以惡搞 json 的內容,故意製造一大堆 hash collision,導致 hash table 效率低落。 這解釋起來得把 hash table 從頭講一次...簡中連結,不過講得還滿清楚的 http://www.cnblogs.com/yangecnu/p/Introduce-Hashtable.html : 9. 什麼是 XXE?什麼情況可能會出現? 我我我我我很少用 XML 這個麻煩的小東西所以跟他不熟........ : 10. 什麼是 race codition?在 PHP + MySQL 這樣的經典組合中有沒有可能出現?要如何解決? 雷姆揍我右臉,我會往左邊飛 拉姆揍我左臉,我會往右邊飛 他們揍我的速度夠快,我被揍飛另一個揮拳就會落空 當雷姆跟拉姆幾乎同時出拳揍我,我可能往左邊飛,也可能往右邊飛,難以預測 race condition 就是指這種狀況 PHP 本身原則上是單一 Process 在跑的,所以只有 PHP 不太容易碰到 (我知道有 fork 或 pthreads,但是網頁上還是盡量別這麼幹,跑後端 job 就是另外一件事...) MySQL 比較常碰到是當 DB 規模大的時候,通常會讀寫分離到不同台機器上。 如果先做 update 然後又馬上 select,有可能 select 不到更新後的資料(還沒同步到所有機器 另外一個狀況是來自系統外部,例如 client 同時發兩個取 token 的 request 然後你不確定 client 會覺得自己取到哪個 race condition 有一些正面解法,例如說設置 lock 確保一次只有一個人通過 不過我的經驗是,非硬解不可的狀況並不多,比較建議的作法是調整工作流程 例如既然都 update 了表示你有資料,那就別再 select 了 或是跪求 client 不要同時發一樣的 request 上來,如果有 re-try 機制要間隔夠久 不讓拉姆跟雷姆有幾乎同時揍我的機會,就不會不知道自己被揍時會飛往何方 : 11. 如何正確取得使用者的 IP?$_SERVER['REMOTE_ADDR']?如果商業邏輯伺服器是放在 LoadBalancer 之後呢? $_SERVER 裡面有很多欄位跟 client IP 有關 REMOTE_ADDR 這是 server 看到當下 request 的來源 IP HTTP_X_FORWARDED_FOR HTTP_FORWARDED_FOR HTTP_CLIENT_IP 這堆(或是其他類似的欄位)則是 http header 裡面寫的 client IP 如果你的伺服器是放在外面直接讓 client 打,那麼 HTTP_ 系列的欄位全部不可信 因為 http header 很容易偽造,人家可以隨便亂塞 127.0.0.1 之類的鬼東西 但如果機器放在 Load Balancer 後面,那麼送 request 給你的機器是 LB,REMOTE_ADDR 只會拿到 LB 的 IP 通常 LB 會確保 HTTP_X_FORWARDED_FOR 是原始的 client ip ,外部惡搞這個欄位的時候會也把他洗掉 這部分細節請參照 LB 的說明書 所以如何正確取得使用者 IP,要看你的的服務架構 - 機器直接對外,看 $_SERVER['REMOTE_ADDR'] - 機器在 LB 後面,看 $_SERVER['HTTP_X_FORWARDED_FOR'],或是看你的 LB 要你看哪個(些)欄位 -- 頂天立地:愛孩子就要支持蘿莉控 https://goo.gl/Zmk62o -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 60.248.122.206 ※ 文章網址: https://www.ptt.cc/bbs/PHP/M.1528111425.A.0A8.html ※ 編輯: GALINE (60.248.122.206), 06/04/2018 19:38:12

06/04 20:38, 6年前 , 1F
06/04 20:38, 1F

06/04 22:30, 6年前 , 2F
推詳細好文!
06/04 22:30, 2F

06/04 23:06, 6年前 , 3F
感謝分享,解釋的很仔細!
06/04 23:06, 3F

06/05 03:12, 6年前 , 4F
受小弟一拜
06/05 03:12, 4F

06/05 07:05, 6年前 , 5F
race condition那邊太好笑了吧xD
06/05 07:05, 5F

06/05 09:30, 6年前 , 6F
好文
06/05 09:30, 6F

06/05 11:56, 6年前 , 7F
06/05 11:56, 7F
※ 編輯: GALINE (60.248.122.205), 06/05/2018 15:09:40

06/06 12:51, 6年前 , 8F
推拉姆跟雷姆 XD
06/06 12:51, 8F

06/06 14:10, 6年前 , 9F
丟妳拉姆
06/06 14:10, 9F

06/06 14:22, 6年前 , 10F
丟你雷姆
06/06 14:22, 10F

06/06 19:34, 6年前 , 11F
受益良多
06/06 19:34, 11F

06/07 13:24, 6年前 , 12F
有答案有推 而且夠白話
06/07 13:24, 12F

06/09 10:38, 6年前 , 13F
06/09 10:38, 13F

06/25 11:32, 6年前 , 14F
跪...
06/25 11:32, 14F

07/05 16:43, 6年前 , 15F
07/05 16:43, 15F

07/11 22:10, 6年前 , 16F
07/11 22:10, 16F

10/16 23:01, 6年前 , 17F
10/16 23:01, 17F

12/02 00:02, 6年前 , 18F
12/02 00:02, 18F

01/03 23:28, 6年前 , 19F
真神人也
01/03 23:28, 19F

03/17 19:07, 6年前 , 20F
猛!!
03/17 19:07, 20F

06/06 19:35, 5年前 , 21F
06/06 19:35, 21F
文章代碼(AID): #1R5I512e (PHP)
文章代碼(AID): #1R5I512e (PHP)