CIS 2021網路安全創新大會《程式碼安全體系建設》實錄

湯青松發表於2022-03-16

一、背景

湯青松 ,北京趣加科技有限公司 安全工程師,實體書《PHP WEB安全開發實戰》作者,擅長企業安全建設,SDL安全建設。
PHPCon 2020 第八屆 PHP 開發者大會分享《PHP安全編碼規範與審查》,NSC 2019第七屆中國網路安全大會分享《PHP反序列化漏洞分析實踐》看雪2018 安全開發者峰會擔任Web安全訓練營 講師

大家好,非常高興給大家分享《程式碼安全體系建設》議題,我是湯青松,目前在 SDL 方面做的比較多的。今天講的這個話題其實和 SDL 有很大關係的。我這次分享這個話題的其實就是 SDL 當中的一部分。很多同學如果在甲方也會去做 SDL 當中的一些工作,所以我希望我這次分享的內容對大家有所幫助。

這次分享的話題是 SDL 當中的一部分,但是它不完全是 SDL 因為我主要還是聚焦於在安全向左移的這樣一個概念當中。所以今天分享的話題主要是聚焦於這個程式碼風險管理。那在這個程式碼安全當中可能有哪些風險點了?那它可能會包含技術方面的工作和非技術方面的工作,比如說管理工作以及這個學習方面的一些事情都會有講解到。

1.1內容概要

我今天講的這個話題,主要還是在於意識、技術、監督和學習四個方面怎麼去開展我們的安全工作?這裡我做了一張腦圖,那在腦圖當中,我覺得從這個淡淡安全體系當中,我們有四個層面了可以去做的,比如說這個安全培訓。

在安全培訓當中,我們第一點要告訴他有哪些風險點,第二個就是我們得教他怎麼去避坑,那麼教他避坑了,我們就可以直接拿到他這個倉庫的程式碼,然後我們自己先去分析一遍,分析完之後,然後在培訓的時候我們就可以告訴他你這個程式碼了哪裡會存在一些風險點,把這個問題告訴他。

第三個就是我們告訴你了,你不能怎麼去寫,你應該怎麼去寫。那麼我們制定完這一套規則了,我們不可能說其實人工去盯著您得有一套監督機制。這裡我也會給大家去講一下,怎麼去結合semgrep 和GitLab做一個鉤子事件,實時檢測這個程式碼當中的一些風險點。

那麼第四個就是我們在上線前肯定會有安全測試。在安全測試當中可能會有哪些疑難點?那今天我大致會提到這樣幾個問題點。那首先我們來說一下安全培訓我們怎麼去做。那安全培訓我相信很多做技術的同學,他可能就是自己的技術了是比較好的,但是讓他去給別人講怎麼去踩坑以及一些案例,她不一定是他擅長的。

我們先來說一下我是如何理解保障整個應用安全的,我認為它不是由某一個維度是否做得足夠好來衡量,它是一個綜合的方面。也是多個團隊配合起來的一個工作,我們作為安全人員在這裡要負主要責任。

我們要想盡一切辦法去和開發和測試一起保障保證應用安全。我們首先給這些開發人員建立這樣一個安全意識,那告訴他了網際網路當中會有很多的一些漏洞,那這些漏洞了有哪些危害?那首先在他開發的時候,他就會想到不能讓這個應用有漏洞。

第二個讓他有意識之後,要教他怎麼去避開這些坑,不要讓他知道有這些安全風險起來,他不知道怎麼去處理,然後還是踩坑了。那麼這個時候我們安全人員自己在這個技術方面了,要有一定的這個能力。

第三個在監督層面。如果說你告訴開發人員網際網路當中有很多漏洞,也教他去避坑了。但是沒有監督很多人了他可能並不一定按照你的要求去做,所以這個時候您得有一定的監督機制。

第四點是是通過事件驅動,我相信作為甲方,你肯定還會遇到一些安全事件去驅動。比如說我們公司是做遊戲的,還時不時會有一些拖機掛或者等等一些外掛這些方面的問題。那麼我們會把這些事情給整理起來,整理成案例,再給這些開發人員去學習。

二、 安全培訓

所以這裡我講幾個非技術性的一個話題,就是我們怎麼去給這些開發做培訓。那首先我覺得做培訓有這幾個方面,我可以給大家一些參考意見。比如說首次的這個培訓我們講什麼話題?怎麼避免一次性把這個話講了,那麼我下個季度還講不講?是不是我一次性了就把話講完了我覺得都是有一些技巧的,就是你第一次該講什麼東西。

第二個說我們培訓了是,一次培訓了,我們就把所有的這個開發組成員了都叫上。那麼比如說幾十號人,上百人都叫上,然後我們自己在一個舞臺上去講還是這個小組去講了。那這裡頭我是推薦大家小組講,那一會我會講到為什麼去小組講。

第三個就是案例就地取材案例了,我們一定要在每次培訓之前把他那個程式碼開啟去看一下,拿著他的程式碼給她們做一完培訓。然後接著了我們就開展我們這次要培訓的一個話題,那這樣的一個形式。

2.1 首次基礎培訓

首次基礎培訓了我們可以給他講哪些東西了?我覺得你首先可以給他講一下你在這個甲方安全當中了,你是怎麼去給他們做程式碼審計的,你是怎麼去做安全的?這個其實是她比較關心的,讓他了解你的工作。那你平時會關注哪些點,你給他充分交流一下。那麼建立一個互信機制。

第二個你可以給他講一下這個漏洞分類,比如說了通用的一個編碼型漏洞,比如說SQL隱碼攻擊, XSS csrf 檔案上傳,然後命令執行程式碼注入等等這些問題。那把這些問題了給講完之後了,我們還可以給他介紹一下這個邏輯性漏洞,比如說這個支付漏洞、越全漏洞、驗證碼漏洞、簡訊漏洞等等這些漏洞了,我們可以給他科普一下。

那麼講這些漏洞的時候,你可以去結合他們這個小組了,他們是做哪方面業務的?比如說做中臺的了,他可能會脫離業務。他可能沒有這樣一個支付的問題,或者說沒有使用者的一些問或等等和他這個主無關的一些問題,可以給大概提一下,但不要講細了。

第三個你可以給他講一下程式碼自查的一些方法,你可以教他一些簡單的方法,比如說他寫完程式碼之後了,怎麼去審計自己的安全問題?但這個引數有沒有做過濾型別,是否強制的,比如說我要介紹一個 ID 那在 PHP 語言當中了,那可能他沒有使用這個整型轉換,那麼接受了有可能這個字元,那麼拼接到這個SQL隱碼攻擊當中了對吧?那這個時候你就要跟他講,你說你在這個接收的時候你得做一次過濾,你如果沒有做過濾了,在拼接社會語句的時候你得做 pdo ,然後查 SQL 大致教他一下怎麼去查。

那這個SQL漏洞怎麼查了?我相信做甲方的技術同學都有一定的見解,在這裡我就不展開了,你可以給這些開發的大概提一下。一般來說就是做開發的同學了。自己對這一塊也是比較瞭解的,你給他點個開頭,他自己很多事情他能想明白的。

2.2 小組培訓

第二個就要在做培訓的時候了,我的建議是小組培訓,比如說你們一個公司可能會分為很多個小組。那麼我目前來說我主要是給後端的同學做培訓。所以我一般做培訓的時候我會講後端的一些東西。那麼後端他每一個組了他其實涉及的東西都不一樣,比如說有些組了他不會用到 HTTP 協議,他就會用這個 socket TCP 這種協議。那麼你給他去講一些 web 業務的一些漏洞了,他可能不愛聽。

所以做小組培訓的目的了,我覺得主要就是因材施教。那每個組他有自己不同的一些特點,你得給他講他自己不同的。那麼你儘量在每次培訓的時候,你儘量控制在 10 個人以內。而且我覺得時間你要控制一下,就要控制在這個 45 分鐘以內。們平時上課了對吧,也是 45 分鐘以內。

說了你要有這個時間的一個意識,你不要一直講,講完之後翻其他人壓根就沒來聽,你要有以這樣一個互動機制。那這裡有三點了,我需要給大家去說的。就第一個了就是開始講到了,你一定要貼近這個團隊的一個真實程式碼。你每次給他做培訓的時候了,你得先把她程式碼審計一遍,審計完了多多少少可能會有一些安全問題,或者說有些不規範的問題。你拿著這個程式碼去跟他說,你不要直接上來,對案例那樣不是不好的,很多人可能就不樂意聽。那麼第二個就是要貼近他的業務場景,剛才也講到了,那做 TCP 的你給他講 HTTP 他不樂意聽他,我壓根就沒有這個業務,你給我講啥呢?第三個就是多分享故事的一個形式去形成一個互動的氣氛。比如說你在給他做培訓的時候,你給他講越全的時候,那你就講以前了,可能你挖過某個網站的一個預存漏洞,你是怎麼發現的,以及你可能在網上了看到過別人的一些案例,那這些分析步驟了你可以給他講一下。

你比如說我發現了這樣一個 URL 的 ID 等於100,那麼我覺得想試一下,我把這個 100 了改成 101 在 URL 位址列當中回車一下。發現看到了別人的一個資訊,也發現了別人訂單資訊,發現了別人的一個個人使用者資訊以及其他的一些許可權資訊,多以這種故事的形式給他去交流,我覺得是效果非常不錯的。

2.3 案例就地取材

第三個就是案例就地取材。那很多時候我們給 A 組的同學去做這個分享的時候了,那他不一定了有他們這個組的一個漏洞案例。這個時候我覺得你一定是就近的,你可以講他們部門的對吧,可以給他講這個整個公司的。然後這個案例就是儘量靠近他們這個團隊。那麼你怎麼取這些案例呢?我們知道在 2016 年以前,這些網際網路當中有很多這種漏洞案例,包括各個大公司的一些漏洞案例都是有的。但在 2016 年 6 月 1 號之後,我們基本上看不到了,為什麼網路安全法出來了,所以很多這種比較直觀的漏洞案例了,我們現在沒有辦法,說很輕鬆的拿到了。這個時候了,你可以從三個渠道取了。

第一個說你在平時做程式碼審計的時候,你把這些案例了給存起來,截好圖。然後把敏感資訊的打個碼。但是把意思大概說明白,把這些案例給整理起來。第二個就是從安全測試當中,我們每一次業務要上線了,肯定會有一輪安全測試,把業務測試當中發現了一些問題點,也可以整理起來,我們是有一個案漏案例庫的。第三個就是漏洞事件了。那比如說一些通用型的一些漏洞事件,像那個 2021 年年末的時候,是不是有個 logic4 的這樣一個元件,我記得在快過年的前幾天了,那個時候出了一個命令執行的漏洞,那影響範圍還蠻大的,那可以把這些事件了給它整理一下。你可以告訴他說你依賴了一些元件了,要及時升級。如果了你要引用一個元件了,你要最好查一下它的版本有沒有漏洞,有漏洞的話你就不要使用了。

一般來說我們 php會用 composer , Java會用另一個包管理器以及 Python 都會用包管理器,那麼我們要及時去更新一下,不要說我們打包一次,幾年我們都不更新,那樣很容易就會產生一個安全漏洞。

三、 風險提醒

那接下來我們要講的就是風險實時提醒。那麼我們給他做完培訓之後,我們有這個首次培訓,也有這個每個季度一次培訓,也有這些案例的一些講解對吧,我們還得有這個監督的一個作用,就是他們寫完程式碼之後,我們得及時去提醒他,以及了我們每一個季度了我們有一次全面掃描等等這些資訊。

3.1 風險提醒的作用

那首先我講一下這個風險提醒的一個作用,主要就是強化大家的一個提醒的意識。你不要講了之後就不提醒了,過不了一週兩週,他之前的程式碼習慣了,該怎麼寫還是怎麼寫?你會發現你之前的培訓白講了,你給他講了之後了沒有太大的改變。所以你要有提醒。

那實時提醒了我們可以在 git 的倉庫當中做一個勾子事件,每一次它 push 程式碼的時候,我們可以把他的程式碼了給拿出來,拿出來之後提取他改動的行,提取改動出來的行了。然後我們來判斷一下他有沒有危險函式等一些問題。那如果有這些問題了,我們就給他反饋一下,就告訴他你哪個地方了可能會存在危險。

提醒這件事了有三點意義。第一個就是加強他的安全意識,讓他知道這個安全事情有人在管。第二個就是從源頭當中去阻擋安全。但這個鉤子你不要說遇到這個危險函式了,就直接給打回去。你可以在這個 git 當中給它返回一下,返回一個提示資訊,告訴它這個地方可能存在風險,讓他去注意一下。比如說在命令執行這個地方你放了一個變數,那麼你需要確保你的變數是可控的,是過濾了的給他這樣一個提示作用。

第三個就是提升一下安全的反饋速度。那如果說你沒有這樣一個實時的提醒了,你每個兩週去給他這個倉庫全面掃描一次,那可能他程式碼都上線了對吧?

3.2 風險函式提醒

風險函式我簡單列了幾個函式,比如說這裡了有這個程式碼注入的,有這個執行系統的命令的,有使用這個明文 FTP 下傳檔案的,

還有一些加密庫以及一些正則庫,那這邊還有一些資訊洩露的提醒。

你都可以放到你的這個安全風險提醒裡面去。我覺得優先順序了,你可以把這些高危的了給大家放進去。比如像 FTP 的,你可以看情況,你放不放都行。那像 pprof 了,我覺得你肯定得注意。那 PP info 裡面還是有蠻重要的資訊的以及 Golang 裡面的,它直接使用了裸寫了這個語句以及讀取檔案內容以及執行系統命令的這些危險函式了,你都給它去提醒一下。

3.3 鉤子使用

那剛才說的這個勾子事件了怎麼去使用了?那其實這個勾子的原理主要就是在這個 git 伺服器當中了,存放一個勾子的這這個指令碼,每次他 push 的時候了,伺服器他會觸發這樣一個指令碼。


觸發指令碼的時候,你就可以通過一些命令列了,你去獲取到他有哪幾個檔案有改動,那改動了一些行號了,你都能拿到。完了這些資料之後了,你把這個檢測的規則就剛才我提供的一些危險函式,以及你自己去擴充一些,把這個規則檔案給它寫好。

第二個,這個semgrep現在已經比較流行了,已經有很多這個團隊在使用了,所以我覺得也是一個比較成熟的東西,你可以通過 sum group 加上這個規則去檢測這個程式碼,然後把這些風險給返回回來。那麼具體的實現地址了,我之前寫了一篇文章,還是比較詳細的,那大家可以去開啟,然後按照操作了去實現就行了。

那這裡我給大家展示一下這個鉤子了,它會是一樣一個什麼樣效果?比如說我在命令列當中,我輸入了一個 git commit 然後提交這個程式碼,然後在推送的時候它就會觸發。那麼在推送的時候,我們可以看到他這邊告訴我哪個檔案。那麼它的行號,當中有個 EXEC 執行了這個 git 當中的 A 這個變數,那麼它有可能會導致一個命令注入,那一定要確保內容不是使用者隨意控制的。那麼這樣一個提示性的話語,那具體了你可以去把這個介面了給它優化一下也可以。

三、 程式碼審計

在程式碼審計當中我們也有四點可以給大家去分享一下的。


那首先我們程式碼審計的方向,我們要怎麼去審計呢?那這裡就有一些偏技術型的話題了。那麼有一句話叫文無第一,武無第二,相信做技術了也一樣。

3.1 程式碼審計方向

那麼第一個就是通用編碼型這這個審計。那比如說我們可以審計這些這個sql注入、 XSS、 命令執行、檔案上傳等等這些,那麼我們可以通過通用型編碼升級出來。那麼第二個我們得結合她的業務去審計。那比如說你只有有使用者的系統,你才有這樣一個使用者密碼找回以及一些許可權方面的一些漏洞。

第三個就是元件型的一個,那你要根據這個倉庫所使用的語言,比如說 php 的,那用compose ,那 Java 的了,那用另外一種形式。那麼把這些元件了,確定一下它使用的這個元件版本,然後來確定他是不是有幾個元件漏洞。那具體了通用型編碼審計方法了。前面其實我也簡單提了一下,其實主要從這三個方面去看吧。


第一個就是接收引數,如果說我這個地方接收了一個 ID 我明確知道它是一個整形的。當我接收的時候了,我沒有用整形去強制接收。那在這種弱型別語言比如說 php 裡面比較常見,那麼你就可以去追蹤一下這個變數,有沒有放到sql語句裡面去執行,有沒有去返回到這個前臺,有沒有可能放到這個命令執行裡面放在這個程式碼執行裡面等等。這些方式就是追蹤接收的引數,它沒有過濾,我們就一直追到底,一直到這個程式結束。那麼這是一種方式。

那麼第二種方式就是關聯詞反常。關聯詞反常了主要說我們可以去這些函式的地方看一下它裡面放的是不是變數,如果放的是變數,我們就追蹤這個變數的來源。那如果說這個變數是接收使用者的,並且沒有做過濾,然後放到這個危險函式裡面來,那麼一定是有安全問題的對吧?第三個就是我們去解析它的依賴檔案。那麼目前來說就是 PhP 了, Java Python 以及 go 它都有依賴包管理。所以我們現在去檢測它的依賴其實是比較好實現的,我們這裡都可以去做一個。當然有一些它可能還是比較傳統的方式。比如說 PhP 在老版本了,在 PhP 7.0 以下了很多這個系統了,他並不會使用 composer 他直接把這個原始碼了直接下載到他的這個目錄下。那這個時候你解析可能會比較麻煩。

3.2 工具選型

那麼這個時候呢您得藉助一些第三方的一些工具去分析出來。說到這個程式碼審計的一些工具選型了,目前前這些我大部分都用過,比如說 fortify ,用的是比較熟練的。那麼 check max 了這一款工具了,我還沒用,因為還沒有買他們的第三款這個程式碼衛士的話是那個奇安信的。那這一款我倒是用過一段時間。

第四個了,我目前用的是比較多的,主要是用在這個鉤子檢測當中。審計系統當中也用到了它的一些功能,但目前來說就是全量程式碼審計了,我還是比較喜歡用這個fortify。那麼在這個鉤子事件的時候嘍,因為fortify帶它是那個 AST 的這種語法分析,它會比較吃記憶體,而且反應速度比較慢,所以目前主要還是依賴與這個 Sem group 那麼第五款這個 CodeQl 的 CodeQl 了這款工具了我前段時間還在瞭解,還沒有用到這個生產環境當中,所以我也不太好說。

第六款工具了目前來說我用過。的感受就是它是一個完全開源的,包括他的這個規則,包括他的這個引擎系統大家都開源了,但他只能目前來說能檢測 PhP 其他的後端語他不能檢測。所以目前我用的這個 fortify 和 Sem group 比較多一些。 fortify 就是要商業的和check max ,其實程式碼衛生也是商業的。 fortify 我目前來說還比較好用,checkmax沒用過,沒有太多發言權。

這個 fortify 泛了我用過一段時間,去年十二月的時候。用過一個月。主要的感受就是它和福利範檢測出來漏洞數量是比較相似的,但它的介面設計了點選起來我感覺很不順暢。據說這個今年 3 月份會有一個新版本,到時候大家也可以去試用一下他們的 SemGroup ,他的規則是 開源的。然後它的這個引擎了它是加密的。

第五個了 CodeQL 了。那 github 當中就已經大規模使用,當然也可以去體驗一下。但是你只能用於學習,不能用於商用。那現在我再來說一下就是批量程式碼審計的一個實現方式。那目前就是幾款產品,其實它對單個單款庫的支援都還比較好。我在做甲方的時候會遇到這樣一個問題,那因為我是要對整個公司的程式碼庫的安全性了負責的,所以我不能說就檢測幾個倉庫的一些安全問題點。那時候我得批量去審計。那像我們公司可能有 600 多個倉庫,一個一個開啟,我得瘋掉,像 fortify 開啟一個倉庫大的專案,它可能得一兩天。光審計起來可能得花個一年時間就讓他分析完。所以如果用這種預設方案其實不是太現實的。

3.3 批量程式碼審計工具

所以我寫了一個批量程式碼審計的一個工具,就是QingScan。那麼它主要的作用它其實是包含了四部分,一部分就是資訊收集,第二部就黑盒檢測,第三部分就是程式碼審計。那還有一個專項利用。那這裡我主要提一下它這個白盒審計。那白貨審計它其實主要的目的就是把你的這個專案了給拉下來,然後呼叫這個 fortify 以及這個sem group還有其他的一些程式碼審計的一些工具了,對它進行逐個掃描。那麼掃描完這個,然後接著就掃描下一個。那麼也可以分散式部署。那目前來說我已經在我們公司使用起來了,也推薦給大家去試用一下,那麼這個地址在這裡

https://github.com/78778443/Q...

四、 安全測試

再就給大家分享一個安全測試當中,安全測試主要有這幾個, web 站點測試、API介面測試、私有協議測試和案例輸出。

4.1 web站點測試

那這個web站點測試了其實我覺得還是比較常規的,目前也沒有什麼太大的一個技術難點

比如說測試個sql注入、 XSS 但一般目前來說是個sql注入和 XSS 這些問題點已經比較少了, XSS 可能是反射型 XSS 多一些,但是影響我覺得也不是太別大,因為現在都是那個cookie 加密的就是HTTP Only 另外這種形式,所以沒有太多可說的。

4.2 API介面測試

API 介面怎麼測試了? API 介面它和這個 web 站點它有一些區別。像 web 站點我們可能可以通過爬蟲的方式把那地址都爬蟲出來,然後再對這個地址進行掃描。那掃描有結果了,我們就把這個驗證一下,驗證完之後然後提出來。

那麼 API 介面有個問題點,就是我們沒辦法去爬蟲。所以這個時候了我們通常開啟一個xray的一個埠,用這個服務模式。然後手機了我們把這個埠指向xray的這個代理地址,然後我們去開啟一些請求,把這些地址收集起來,然後去掃描。同時我們還會有一個 URL 地址的清單,就是這個地址其實是開發那邊給我們提供的。然後這個功能測試那邊同學也有一份我們在對這個地址了去進行這個邏輯進行的一個測試,比如說越權以及這個支付漏洞等等這些方面的問題的檢測。

4.3 私有協議測試難點

第三個就是私有協議測試,那私有協議了其實測試起來是比較麻煩的,比如說這個socket的協議,那麼 TCP 協議,那麼我們其實是沒有辦法直接把這個資料包了給解析出來的,除非了我們得有一個模擬他們的客戶端。那目前來說只有幾個就是重點專案了,我們會和他們對一下這個端和服務端的資料的一個格式,然後進行模擬測試。那這個工作量還是蠻大的。所以這個私有協議了,看各位的這個人手夠不夠了,沒有太多好方法,只能去模擬這樣一個這個私有協議的客戶端。

那傳統的外部站點測出來是最簡單的,無非就是先收集地址,然後測試一下常規有沒有問題點,然後對這個業務功能進行測試一下。那業務功能也就是說我越權支付,然後使用者密碼找回驗證碼等等。好 API 介面了。那主要就是我們要把地址先拿到,拿到地址之後其實其他的測試方法都差不多。那麼拿了這個地址了,我們有兩種方式。第一種說從開發團隊那邊直接拿到一份 API 該的一個列表,然後並且搞得清楚他們每一個引數是做什麼用的。然後對這些介面了去進行一些掃描測試以及一些邏輯性測試,和傳統概念區別不大了。

第二個就是有可能我們從開發團隊那邊拿了不全對吧。所以我們可以用 reay 去開啟一個埠,會使用這個 burp suite 開啟一個埠。然後手機設定一下代理,把我們的資料包了從那邊經過一下,然後把這個地址也收集一批。第三個就是比較麻煩了,剛才也講到了,沒辦法輕易瞭解這個資料包的格式,然後比較麻煩。而且不好輕易去各做資料包,你必須通過程式的方式,你人工的是很沒有辦法去改資料的。但有些資料它就是這個十六進位制的。那他不是說就是你看到的銘文說了你得模擬一個客戶端,用於封裝資料包。看你的這個人手夠不夠,人手不夠的話,測了也沒有太大意義。

4.4 案例輸出

每次我們檢測出漏洞,或者遇到應急響應事件可以將它錄入到我們的安全系統中,方便我們積累經驗

那這裡有個圖,就我們這個團隊了,對公司的一些漏洞了一些整體情況。那有季度的一個報表,有這個部門的一個報表以及統計資訊,就是它的漏洞類別的一些統計資訊。

五、總結

那今天主要就分享這四點內容,從這個培訓到這樣一個鉤子的製作以及這個程式碼審計,那最後以及安全測試。那麼這一次的話題就講到這裡了,那希望對大家有所幫助。再見。


作者:湯青松
微信:songboy8888
日期: 2022年3月15日

相關文章