如果你開發和架設過網站,也有注意開發網站所需要的安全問題,那讓我們來思考一下幾個問題:

1. 回想一下你現在擁有的網站(或是曾開發過的網站),有注意過哪些資安弱點?
2. 有辦法列出十個以上要注意的資安弱點嗎?
3. 第二題想到要注意的項目,在真正開發時(第一題)有去注意嗎?

第一題通常最耳熟能詳的應該就是 SQL 注入(SQLI,SQL Injection),再來第二個常見的答案會是跨網站指令碼攻擊(XSS,Cross-site scripting)。如果有密碼相關的,可能想到密碼要加鹽(Salt)並且將密碼雜湊(Hash)過後儲存。

第二題的話,網站安全並不只有上述要注意的這些。較了解資安的人會想到要參考 OWASP Top 10 的項目來讓自己的網站更安全,雖然有些人可能會有一些 OWASP Top 10 的迷思,但它確實列了網站較容易被駭的弱點列表。

至於第三題,雖然知道要防禦的資安攻擊有哪些,但就得看你在開發上、架構設計上,是否有真的想到這些資安攻擊項目,或在進行評估時考慮到需要做哪些資安防禦。

今天會從開發角度來看資安弱點,並且更深入探討前三個的問題,來延伸到開發時的資安要如何思考。

不同的資安等級

網站安全的測試項目其實比 OWASP Top 10 項目還多,每個都要注意的話其實會影響整個開發進度。我們應該要看那些保護的東西,依照它們的特性給予相對應的保護:例如你的腳踏車,你會把它放在騎樓並且是使用大鎖來防止偷竊;而你的銀行存簿和印章可能會鎖在保險箱裡並且藏在一個很難拿到的地方。

通常不會為了怕腳踏車被偷,而把它鎖在箱子裡並且藏在很隱密的地方,畢竟價格也許不高而且腳踏車時常要取用,便利性便是一個考量。當然也可能有為了保護高價的公路車而把它放在家裡;存簿和印章我們也不會為了方便而放在騎樓信箱用個大鎖鎖著而已,畢竟一般來說這些東西沒有這麼經常要使用。我們根據「要保護的東西的特性和重要性」來決定要處理什麼樣程度的安全弱點。

像是要管理一般使用者連線的 Session Token,會需要不斷存取和更新,且有有效期限,你可能會想用 Redis 這種記憶體快取資料庫來幫助存取和加速。而這邊要顧慮的安全,包含前端使用 XSS 來偷別人的 Session Token,以及後端 redis 本身的安全性問題、認證等等。

而如果要管理處理網站金流的私密金鑰,也許你就會思考是否要放在雲端上還是實際硬體存放,並且未了防止擁有金鑰的人可以直接取走現金,而做了多重擁有者認證的機制。這邊要考慮的也許也有 XSS 的問題,和存放服務本身的安全性問題、認證,但更多要做的地方還有在金鑰的存放機制以及存取控制的部分等等。

我們可以「對要保護的東西分級」,第一級可能就屬於一般資產,視情況做好基本預防如 OWASP Top 10 即可;第二等級可能就屬於較敏感的資訊,要做好更多資安弱點管理;而第三等級則屬於機密資料,你也許需要花更多心力和更全面思考來處理它的資安弱點。

我們無法把所有東西都當作第三等級來處理,畢竟資源、時間、人力有限,我們可以做的是依照這些特性和資產的重要程度,分級和評估,找出適合的資安防禦方法,並且讓開發進度可以持續下去。

開發時對資安的考量

畢竟身為一個工程師,在開發時考慮到的其實不會只有資安:這份程式碼的可讀性、可維護性、效能等等,都是要考慮的一環,但這也許就是資深工程師比一般工程師技高一籌的地方。更厲害的工程師會考慮到各種細節,並且評估適當的方法,當然資安也是在各種細節中的其中一項。

在這麼多要注意的情況下,往往資安弱點的修復時程都會一直被延後,甚至放在待做清單上長灰塵。「這個資安弱點什麼時候要修?」一直是一個不容易有共識的問題。我們其實可以從簡單評估「讓這段程式碼變得更安全,所花的時間成本」和「如果被攻擊,所造成的嚴重程度」開始衡量:

cp

成本其實不只有時間:改架構造成系統不穩定的成本、系統更複雜的成本、人力成本等等也是需要考量的。而嚴重程度則是這個駭客如果找到了這個漏洞,他可以做到什麼程度,當然這與你想保護的資產分在哪個等級有關。

在開發時遇到的資安弱點,我們可以大概分成如上圖的四個區域。而其中最可能要被放棄修復的資安弱點,是屬於左上塊,屬於不僅耗時、改架構且就算修復了對資安成效也沒有太多幫助。我們應該持續關注在「右下橘色塊」和「右上紅色塊」,屬於評估後嚴重程度較高的資安弱點,並且從橘色塊由下往上至紅色塊,分成「短(衝刺週期)、中、長(季計畫)期」規劃去修復這些弱點。橘色塊就是屬於短期可修正「高 CP 值」的部分,而紅色塊則是需要長期規劃,判斷是否要 Workaround 暫時修復,再來慢慢調整架構來讓產品脫離高風險的弱點。

當然不嚴重的弱點如果累積太多,也是可能會被駭客拿來組合利用,變成一個高嚴重性的攻擊。清理技術債相信也是每一位工程師持續在做的事情。上圖給那些如果對資安弱點無從判斷起的話,這個方法是僅單純用「成本」和「風險效益(弱點的嚴重程度)」來做考量,算是一種方便起步評估的方法。

檢查與攻擊

資產分級、成本、嚴重程度,有了初步評估資安弱點的方法,我們還需要培養看出弱點的能力。

OWASP Top 10 的第一名是注入(Injection),常有人認為它就是 SQL Injection,或只談 SQL 相關的注入議題。其實「注入」攻擊類型裡面包含了各種攻擊手法,SQL 注入只是其中一種。其他像是指令注入(Command Injection)、XML 注入、程式碼注入等等,都屬於注入類型。

而這些注入攻擊,在做滲透測試時,它們都會被歸類在輸入檢查的測試(Input Validation Testing) 項目中。比起只學到要注意 SQL 注入,更好的思考方式是「把所有使用者的 Input 和 Output 都確實做檢查」。如果後端拿到一個使用者的參數,它直接拿去資料庫查詢,就可能會造成 SQL 注入;如果直接拿去執行某個指令,就可能會造成指令注入。但在每次拿到使用者給的參數時,檢查它的合法性再做動作,就比較可以減少攻擊的發生。

假如在一個新聞網站的查詢頁面可以用 https://secview.io/news.php?id=1id 用來查詢要看的新聞,這個 id 就是一個使用者可以任意修改的數值。我們也許會檢查它的數字是否在合法範圍,有時還要確認它的資料類型是否如你所想像。如果有個攻擊者輸入:https://secview.io/news.php?id[]=1 你覺得會發生什麼事?原本應該是字串的參數卻變成了陣列。如果要放進資料庫查詢,id 是不是必須為數字且不該有單引號 ' 這種符號存在?

在開發時,不論在何種狀態下,使用者可以控制的參數都要列為不可信,對參數做檢查。並且做輸入檢查測試,想像自己是可以任意控制這個參數的人,如果我這樣做檢查,是不是有辦法可以「繞過」這個檢查機制,導致攻擊者一樣稱心如意?

根本開始,架構設計的考量

其實在開發前,架構設計的時候把資安考慮進去,就可以避免不少資安的問題和一些 Workaround 的做法。不管是設計什麼樣的類型網站,大致可以用 CIA 金三角來做考量,以下來自維基百科的解釋:

機密性(Confidentiality):一般稱秘密,是指個人或團體的訊息不為其他不應獲得者獲得。

完整性(Integrity):在傳輸、存儲信息或數據的過程中,確保信息或數據不被未授權的篡改或在篡改後能夠被迅速發現。

可用性(Availability):系統處在可工作狀態的時間的比例。

我們舉一個例子:假如我們要做一個聊天 APP,每個人可以註冊登入後,開啟一個聊天室並且隨機配對其他用戶來聊天。這樣的聊天室架構要考量 CIA 像是:使用者連上一個聊天室的時候,是否要驗證他有權限可以瀏覽這個聊天室的訊息(機密性)?今天有人在聊天室貼訊息,是不是走加密的通訊防止被攔截訊息並且竄改(完整性)?有沒有流量限制(Rate Limit)的機制當有人送大量惡意流量時可以防止伺服器無法負荷(可用性)?

或是微服務設計,微服務間的通訊也許會透過 API 溝通,並且使用 Token 來驗證。Token 的儲存和發佈方法、訊息是否被竄改、API 的可用,都是一開始可以先設計好的。這樣在實作整個架構的時候,不會因為後來發現哪裡要加上某個權限,但系統已經無法更改而導致用 Workaround 的解法暫時解決。

其實到這裡你會發現,之前提到要評估資安弱點的「嚴重程度」,就可以用 CIA 的方式來評判,這個漏洞是否影響了哪個等級資產的機密性、完整性還是可用性。從這三個指標可以更容易定位出嚴重的等級。

開發之後、部署之前

程式開發不會只有面對「程式」而已,部署相關的服務、部署時的設定檔、雲端設定等等,這些也都會稍微接觸到。當然如果是一個 CI/CD 相當成熟的公司,也許工程師不會特別接觸這些,這些會由 SRE 專門負責。但在開發時我們還是需要注意一些部署時的問題,例如第三方套件就是一個值得小心的地方。

尤其像是 nodejs 軟體套件,因為相依性實在太廣,牽扯到的第三方套件太多,實在很難一一追蹤哪個套件現在存在資安弱點、哪個已經棄用不維護。雖然有工具可以幫助追查,但也還是得靠工程師在開發時提高警覺,不要誤用來路不明的惡意第三方套件。

在開發時,還有一個好習慣可以幫助在部署之後遇到資安事件的搜查,就是做好日誌紀錄(Logging)。並不是寫越多越好,而是紀錄在追查資安事件時可以用的證據。其實可以假想如果今天網站被攻陷,但在「完全不知道原因」的情況下,你會想看哪些日誌?也許你會想看攻擊者請求封包的內容(但可能有敏感訊息,需要做過濾或調整日誌)、也許你會想看各個資料庫查詢時的時間點,這些都是可以在資安事件發生時幫助搜查的日誌。

開發時加上安全的考量並不是一件特別難的事情,但在開發時因為有太多東西要考慮,有時還是會不小心忽略一些要注意的議題。所以平時開發如果隨時保持著:「我這樣寫,這地方會不會被駭客利用?」的想法時時問自己,我認為考慮資安這件事也會漸漸內化在自己腦海中,自然也會主動去思考更多:資產分級、成本、嚴重程度等等的考量,並且做出一個高品質高安全的產品。