看板 PHP 關於我們 聯絡資訊
直接寫一篇可能比較清楚 「存資料的時候應該存未處理過的原始資料,吐 html 的時候才做 escape」 原因有幾個 - 你先 escape 了以後,你就沒有原始資料,只剩下加料過的資料 - 東西不見得塞在 HTML 裡面,不同的地方要做不同的 escape - 萬一未來發現了新的攻擊方法,你有機會改 code 應對,而不是進 DB 改資料 =============================================================== 第一點跟第三點我就不特別討論了,這邊專注在第二點上 範例像這樣 <h1><?= $title?></h1> <script>alert("標題是<?= $title?>")</script> 如果你存檔的時候就做 $title = htmlspecialchars($title) 那麼你就會不知道該怎麼對 javascript 做處理,於是 - <最新>高雄宇宙港遭恐怖份子攻擊 - h1 會顯示,但 script 會噴出怪訊息 - 群星齊唱"愛還記得嗎" - h1 會顯示,但 script 會爛掉 而且完全可以寫出不會被 htmlspecialchars 影響的 xss... 正解會是這樣 <h1><?= htmlspecialchars($title)?></h1> <script>alert("標題是" + <?= json_encode($title)?>)</script> 這些問題就算你用 template engine 也還是得注意,頂多是做起來比較輕鬆 例如 twig,預設是當成 html 來 escape,所以 <h1>{{ title }}</h1> <script>alert("標題是{{ title }}")</script> 還是會死在 javascript,正確的做法是 <h1>{{ title }}</h1> <script>alert("標題是{{ title|e('js') }}")</script> BTW,這邊有個隱藏大魔王叫做 URL 雖然塞在 html 裡面,但是用 htmlspecialchars() 清理是不夠的 因為有 data: 跟 javascript: 這種東西可以用,讓 escape 變得很麻煩 這邊建議用第三方 lib 來處理(例如 htmlpurifier),或根本不讓使用者自填 url... =============================================================== 總之,你在不同的地方,需要用不同的方式 escape 資料 「事先 escape 然後到處通用」這條路...很可惜的是不通的 而為了讓每個地方都能正確的 escape,你必須保留原始的輸入資料 -- 這閃電拳能射出雷射光,威力每平方公分一萬億瓦特 威力無比,拳到之處,攻無不克 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 60.248.122.206 ※ 文章網址: https://www.ptt.cc/bbs/PHP/M.1469071079.A.9CD.html
MOONRAKER: Yea, use the source 07/21 12:03
※ 編輯: GALINE (60.248.122.206), 07/21/2016 13:00:59
Kenqr: 推 07/21 13:17
kajm: 感謝G大分享,這篇真的很實用,尤其對我這種新手 QQ 07/21 13:35
kajm: 另外想補問,用了escape是否就無法使用n2lbr? 可是這樣取jso 07/21 13:36
kajm: n格式時,會被換行符號斷行.. 用了n2lbr會變成取<br> 囧! 07/21 13:37
MOONRAKER: 可以先htmlspecialchars()再nl2br()阿 07/21 16:25
MOONRAKER: 還是你escape的情況不一樣 07/21 16:25
kajm: 我是希望能像Dcard取留言的json格式一樣,像是這樣: 07/21 16:55
kajm: https://goo.gl/qgExPE 裡面把換行換成\n,其他都能正常顯示 07/21 16:56
kajm: 可是我用n2lbr的話,會在json變成<br>,然後在urldecode()後 07/21 16:56
kajm: 就會變成斷行了 07/21 16:57
xdraculax: 斷行經過json_encode就會變\n不需要先nl2br啊 07/22 11:05
kajm: 感謝各位前輩指點,後來發現header沒設定到json格式,才衍伸 07/25 02:09
kajm: 很多問題出來 XD 07/25 02:09