※ 引述《red0whale (red whale)》之銘言:
: 昨天我的資料庫老師說
: PHP是一個漏洞相當多、非常不安全
: 而且是外面業界鮮少在使用的後端程式語言
: 他還說PHP只是給學生在用的程式語言
你老師的說法雖然有不少...誤會,不過反正前面打臉也滿多了
我覺得可以認真思考一下那些有沾到邊的部分
: 而他建議我們做網頁後端最好使用像C#或Java之類的需要編譯過後才能使用的「編譯語言
: 」
: 而非使用像PHP這種「直譯語言」
: 原因之一在於PHP是以明文儲存程式碼
: 在外面業界如果使用明文丟後端程式語言給其他人,早就造成安全上的漏洞了
: 所以非常不建議使用PHP作為網頁後端的程式語言
先假裝不知道可以用 java decompiler 或 dotPeek 反組譯程式碼這件事
這個論點看起來像是「程式碼被看光光很危險」(某些時候這是事實)
延伸出來的下一個問題是「什麼情況下『別人』會看到我寫的 PHP 程式碼?」
我比較常聽說這兩種狀況
- 網頁伺服器明明該執行 PHP 卻沒執行,把 PHP 當成文字檔直接吐出來
- 程式本來該讀讓使用者下載的檔案,卻不知道為什麼(笑)去讀了 PHP 檔案本身
- ex: 使用者在網址列輸入 /download.php?file=download.php
前者屬於伺服器設定錯誤,不是 PHP 本身的包
但寫 PHP 的人通常可以多做一層防護:
確保你的網頁目錄裡面只有 index.php 這隻 PHP
裡面只做最小程度的初始化,沒有其他邏輯
所有的邏輯都該放在網頁目錄之外
比較新的 PHP 框架都是這麼幹
- https://github.com/laravel/laravel/tree/master/public
- https://github.com/slimphp/Slim-Skeleton/tree/master/public
這樣就算設定出包,外面的壞人也只能看到裡面沒什麼料的 index.php
這題有個延伸注意事項:小心別讓 .git 目錄出現在網頁目錄內
不然不管你用哪種語言都會被人整包端走,出這種包的網站意外多...
動態下載這題,鍋會是開發者要背
如果你需要讓人動態下載檔案,我一下想到這幾種做法
- 檔案名稱做白名單檢查,不在白名單內就不給下載
- 取檔案的 key 不要直接就是檔案名稱,自己做一個對應表
還有,如果你是接案的乙方,結案時只想給能動的程式不想給原始碼
PHP 確實不會是優先選擇
: 另外,他也提及
: 用PHP連後端資料庫是非常危險的
: 原因也是因為直譯式的關係
: 如果用PHP的話,資料庫的帳號密碼之類的也很容易外露造成資安漏洞
這看起來像是上面的延伸:看到 code,不就知道資料庫密碼了
我的回答是:誰把資料庫密碼寫死到 code 裡面我就揍誰 =__=
程式邏輯應該從其他地方取得密碼或 token 之類的機敏資訊
- 也許是環境變數(對 server 要有控制權)
- 也許是某個跟程式碼分開管理的機敏資料檔案(記得別放進網頁 public 目錄)
- 也許是專門的機敏資訊管理服務,ex: HashiCorp Vault、AWS Secrets Manager
- 個人或學生通常不會搞這麼大,知道這件事可以複雜到有人靠這個賺錢就好
然後不要覺得編譯過的語言就可以把密碼寫死在 code 裡面
就算假裝不知道可以用 java decompiler 或 dotPeek 反組譯程式碼
程式碼沒混淆的話有耐心的人用 hex editor 一樣找得出來
另,資料庫連線有問題時,PDO 噴出的錯誤訊息可能會包含機敏資訊
所以對外服務用的 server 應該要確保使用者不會看到錯誤訊息
例如:關掉 error_reporting;用 framework 的時候,關掉 debug 訊息
: 所以他說在外面業界幾乎很少有人會使用像PHP這種直譯式程式語言作為網頁後端的程式
: 語言
: 也非常不建議使用PHP,因為它本身的漏洞實在太多,且相當不安全
: 不曉得各位有什麼看法?
: 對於PHP不安全、漏洞多有沒有什麼能夠補救的辦法?
PHP 本身沒有那麼不安全,安全紀錄不算特別差
但由於 PHP 的出身是開發者要自己處理跳脫問題的 HTML 樣版引擎
而自己處理跳脫囉唆又麻煩又容易忘記(或根本不知道要處理跳脫問題)
所以 PHP 很容易引誘寫程式的人寫出不安全的網頁程式
PHP 過去一些失敗的設計也會加深這件事(有興趣可以找找 Magic quote)
縱使現在 PHP 脫胎換骨了,許多舊的寫法在現代依然能被使用
當你發現你正在寫 HTML 跟 PHP 纏在一起的的程式,你應該覺得緊張害怕
然後深呼吸,平復情緒
接著花至少一個小時去看搜尋「PHP injection」能找到的每一篇網頁
又或者,你應該用其他人寫的樣板引擎,例如 twig
(有一大堆人在 PHP 這套樣版引擎裡面寫自己的樣版引擎,這也是個成就...)
如果你看到眼前的教材是 HTML 跟 PHP 纏在一起的的程式
請記住,你工作時不該那樣寫 code,但那些東西做為教材(也許)是及格的
知道怎麼飛雙人座單引擎螺旋槳小飛機
跟能知道怎麼飛承載數百人的雙引擎噴射客機是兩回事
但是每個廣體噴射機駕駛都得從螺旋槳小飛機開始
再重申一次,如果看到有 code 把 PHP 跟 HTML ,或其他任何語言寫在一起
就應該小心 injection 問題
不管是看到 PHP 組 HTML // <p><?=$foo?><p>
還是看到用 PHP 組 SQL // "select * from table where id={$id}"
或是看到用 PHP 組 javascript // <script>let a = <?=$a?>;</script>
都要讓心裡面有個紅燈號亮著
: 順帶一提,我也有想過,像Facebook、Wikipedia 之類的大網站不也是使用PHP作為其中
: 一種程式語言嗎?
: 雖然昨天也有跟老師討論到這個
: 不過老師是跟我說,那些大網站使用PHP也只是用來做顯示前端的一些部分
: 真正使用後端像是連資料庫之類的根本不可能使用PHP來寫
: 他說如果他們用PHP做後端的話是相當不安全、風險很高的作法
PHP 連資料庫沒什麼稀奇...
對於大型服務,重點是整體服務架構,這群東西能不能放在一起打群架
程式語言只是眾多抉擇的其中一個
PHP 是不是「不好的選擇」,要連需求跟整包架構一起看
回過頭來講一下 PHP 用在超大網站上的弱勢
這年頭不管你用 apache 還是 nginx,通常你的後端會用 php-fpm 來幫你處理 PHP
他會先幫你長出一群 PHP process 在後台等著
一隻 process 同時間只處理一個 request
類似銀行有固定數量的櫃檯人員,櫃檯一次只能服務一個人
web server 收到 request 之後會幫他抽號碼
若櫃檯有空位就叫號引導 request 去櫃檯
若是有個 CPU 吃比較兇的奧客,那也只影響一個櫃檯,不會影響其他櫃檯的服務
這個模式的問題是,櫃檯不可能無限擴充,所以萬一突然衝進一堆人,或者奧客太多
後面的 request 就整群得排隊等櫃檯有空出來,跑不進 PHP
換句話說,一台 server 同時間能處理的 request 上限相對小(ex: 數十個)
與這個模式相對的是 nodejs 或 React PHP 那種 event loop 的做法。
不管來幾個人,怎樣反正就先收單下來
如果處理到一半發現有事情可以叫其他人(例如 DB)做
就把事情先推出去,然後處理下一個人。等到 DB 把結果發回來,再回頭來處理。
這種一個棋王同時跟一群人下棋的搞法,好處是可以同時應付一大群人還不會明顯變慢
甚至能應付有人雖然不吵不鬧但一直待在櫃檯不走(長時間連線)
壞處是只要有一個奧客吃比較多 CPU 資源,用掉棋王的腦力,所有人都得陪他一起慢
所以傳統(?) PHP 能夠同時應付比較多的奧客,但對簡單的事情的容量無法大幅提升
也無法應付長時間連線
而 event loop 能夠同時應付大量邏輯簡單,或效能瓶頸在 IO(如資料庫)的的請求
但如果 server 需要處理複雜的商業邏輯就會卡彈
與其說弱勢,問題終究是「打群架的時候角色適不適合」
話說回來,如果設定沒有問題,機器也不要小的太誇張
php-fpm 一秒處理到上百個 request 並不難
如果你的網頁一秒被戳不到一次,上面的考量都只是腦內運動,實務上沒有差
: 然而,我已經使用PHP做為後端語言已經好幾年了
: 聽到老師這番話要我全部改學另一種語言而且又要把先前已寫好好幾萬行的PHP碼全部都
: 改寫
: 我認為這是個相當相當浩大的工程
: 希望各位可以給些建議和看法
: 謝謝
PHP 的安全性問題,來自於他讓開發者可以輕鬆的行惡
作為開發者,解決方法是自己應該比其他人認真追尋這些知識
推薦的起點有
- http://phptherightway.p2hp.com/
- Laravel Taiwan 那份好像有點舊了
- https://www.tenlong.com.tw/products/9789863477785
- 我竟然想不到 PHP 7 時代的推薦書,可能我太久沒看書...
至於改寫,建議判斷條件是...這會不會影響你的分數(汗