譯者 | 陳峻
審校 | 重樓
在現(xiàn)代開(kāi)發(fā)環(huán)境中,持續(xù)集成(CI)和持續(xù)交付(CD)管道對(duì)于向最終用戶交付軟件的變更已是“家常便飯”。這導(dǎo)致了過(guò)去在部署之后才執(zhí)行安全測(cè)試的傳統(tǒng)方法,對(duì)于每天可能要進(jìn)行數(shù)十甚至數(shù)百次部署的場(chǎng)景而言,已不再有效。

安全測(cè)試人員為了能夠輕松地自動(dòng)運(yùn)行和協(xié)調(diào)一系列開(kāi)箱即用的安全測(cè)試工具,也往往需要一個(gè)模塊化的工具鏈。而secureCodeBox正是這樣一個(gè)基于Kubernetes(又稱 K8s)的、可被用于對(duì)軟件項(xiàng)目進(jìn)行持續(xù)安全掃描的工具。它能夠被集成到CI/CD管道中,自動(dòng)掃描變更,并向開(kāi)發(fā)人員提供測(cè)試結(jié)果,以便他們?cè)诓渴鹬靶迯?fù)軟件問(wèn)題。
架構(gòu)
總的說(shuō)來(lái),secureCodeBox的架構(gòu)如下圖所示:
secureCodeBox的架構(gòu)圖
而且,由于Kubernetes作業(yè)可以按需啟動(dòng),并只在需要時(shí)才使用資源,因此它能夠在掃描活動(dòng)之間節(jié)省大量資源。同時(shí),其另一個(gè)優(yōu)勢(shì)在于,所有不必要的掃描工件或元數(shù)據(jù)都會(huì)在Kubernetes作業(yè)執(zhí)行之間被刪除。
如圖所示,負(fù)責(zé)處理這一流程的主要組件便是secureCodeBox操作器(Operator)。該操作器通過(guò)為每個(gè)步驟觸發(fā)相應(yīng)的Kubernetes作業(yè)來(lái)協(xié)調(diào)掃描,即:從掃描活動(dòng)開(kāi)始,到解析結(jié)果,再到修改和持久化結(jié)果。整個(gè)過(guò)程無(wú)需依賴人工安全審查,而且具有可擴(kuò)展性,可以輕松添加更多的掃描器作為新的Kubernetes對(duì)象。
部署secureCodeBox
SecureCodeBox可以使用Helm圖表在Kubernetes中進(jìn)行部署。畢竟Helm在K8s中不需要太多的部署工作,而且部署的對(duì)象可以通過(guò)Helm變量輕松調(diào)整。
下面,我將使用Minikube創(chuàng)建一個(gè)本地Kubernetes集群。這里,Minikube并不是為生產(chǎn)環(huán)境的用例而設(shè)計(jì)的,不過(guò)您可以用它來(lái)測(cè)試性部署在K8s中。
首先,我們使用如下命令,以 4 個(gè)CPU和2048 MB內(nèi)存的方式啟動(dòng)Minikube:
minikube start --cpus=4 --memory=2048m啟動(dòng)Minikube之后,我們便可以使用如下命令添加Helm資源庫(kù):
helm repo addsecureCodeBoxhttps://charts.securecodebox.io接著,我們可以使用以下命令創(chuàng)建新的K8s命名空間。在此,我強(qiáng)烈建議您創(chuàng)建一個(gè)單獨(dú)的Kubernetes命名空間,將secureCodeBox對(duì)象與其他K8s對(duì)象分離開(kāi)來(lái),尤其是在K8s中已部署了其他服務(wù)的情況下。據(jù)此,我們可以更方便地管理新創(chuàng)建的、專用于該平臺(tái)的對(duì)象。
kubectl create namespacesecureCodeBox-system命令成功執(zhí)行后,我們就可以在新創(chuàng)建的名為securecodebox-system 的命名空間中,使用如下命令安裝secureCodeBox了:
helm --namespacesecureCodeBox-system upgrade --installsecureCodeBox-operatorsecureCodeBox/operator至此,secureCodeBox操作器已部署完畢,可隨時(shí)進(jìn)行掃描管理了。下圖展示了上述各項(xiàng)命令:
啟動(dòng)Minikube并部署secureCodeBox
如下圖所示,您可以通過(guò)執(zhí)行kubectl get pods -nsecureCodeBox-system來(lái)驗(yàn)證pod是否正常運(yùn)行。
在K8s中運(yùn)行secureCodeBoxPods
使用secureCodeBox進(jìn)行掃描
SecureCodeBox集成了許多適用于各種場(chǎng)景的流行掃描組件。其官方文檔就提及了 20 多種掃描集成,其中包括但不限于:
- 靜態(tài)應(yīng)用安全測(cè)試(SAST),如:Semgrep
- 動(dòng)態(tài)應(yīng)用安全測(cè)試(DAST),如:ZAP、Nikto、Nuclei
- 軟件構(gòu)成分析(SCA),如:用于容器掃描的Trivy
此外,SecureCodeBox還集成了各種常用工具,如:用于Web掃描的nmap、用于密鑰檢測(cè)的Gitleaks等。
SecureCodeBox的掃描集成
由于secureCodeBox中的掃描器是由ScanTypes表示的,而ScanTypes在Kubernetes中屬于定制資源定義(CustomResourceDefinition),因此在運(yùn)行掃描之前,我們必須通過(guò)如下Helm命令,將Semgrep安裝到secureCodeBox中:
helm upgrade --install semgrepsecureCodeBox/semgrep -nsecureCodeBox-system下圖展示了該命令的截圖:
安裝Semgrep掃描器
安裝好Semgrep掃描類型(ScanType)之后,我們就可以針對(duì)所選的存儲(chǔ)庫(kù)開(kāi)始配置掃描器了。以下是Semgrep配置的示例,您可以參見(jiàn)其官方文檔。該配置實(shí)際上是一個(gè)描述性的掃描(Scan)YAML文檔,即在K8s中secureCodeBox使用的一個(gè)自定義對(duì)象。
apiVersion: "execution.securecodebox.io/v1"
kind: Scan
metadata:
name: "semgrep-vulnerable-flask-app"
spec:
# Specify aKubernetesvolume that will be shared between the scanner and the initContainer
volumes:
- name: repository
emptyDir: {}
# Mount the volume in the scan container
volumeMounts:
- mountPath: "/repo/"
name: repository
# Specify an init container to clone the repository
initContainers:
- name: "provision-git"
# Use an image that includes git
image: bitnami/git
# Mount the same volume we also use in the main container
volumeMounts:
- mountPath: "/repo/"
name: repository
# Specify the clone command and clone into the volume, mounted at /repo/
command:
- git
- clone
- "https://github.com/we45/Vulnerable-Flask-App"
- /repo/flask-app
# Parameterize the semgrep scan itself
scanType: "semgrep"
parameters:
- "-c"
- "p/ci"
- "/repo/flask-app"在上述配置中,您可以看到,作為容器的prosision-git被用于執(zhí)行git clone,以下載所選的存儲(chǔ)庫(kù)。在本例中,它克隆了Vulnerable Flask App,以便對(duì)其執(zhí)行掃描。此處的Vulnerable Flask App是一個(gè)使用Python Flask框架創(chuàng)建的Web應(yīng)用。當(dāng)然,通過(guò)自定義的git參數(shù),您也可以改變命令參數(shù),以克隆任何選定的存儲(chǔ)庫(kù)。
在上例中,存儲(chǔ)庫(kù)被克隆到了/repo/flask-app目錄中,該目錄也是在provision-git和semgrep容器之間共享的Kubernetes卷。一旦存儲(chǔ)庫(kù)被克隆,Semgrep就會(huì)使用參數(shù)配置來(lái)啟動(dòng)掃描。這些參數(shù),尤其是使用到的規(guī)則,都是可以被調(diào)整的。而且,由于Semgrep的規(guī)則是公開(kāi)的,因此您可以在規(guī)則注冊(cè)表中輕松找到。
下面,讓我們將YAML文檔保存為semgrep-vulnerable-flask-app.yaml,然后使用如下kubectl命令啟動(dòng)掃描:
kubectl apply -f semgrep-vulnerable-flask-app.yaml -nsecureCodeBox-system該命令的輸出結(jié)果如下圖所示:

針對(duì)存在漏洞的Flask App運(yùn)行Semgrep掃描
我使用了kubectl get scan命令來(lái)檢查掃描狀態(tài)。由于secureCodeBox使用K8s對(duì)象來(lái)表示掃描,因此它們的訪問(wèn)方式與其他K8s對(duì)象類似。
后續(xù),您可以再次執(zhí)行相同的get命令,來(lái)驗(yàn)證掃描是否成功完成。


如上圖所述,Done狀態(tài)表示掃描已完成,且包含了1項(xiàng)發(fā)現(xiàn)。
獲取結(jié)果詳情
在默認(rèn)配置下,掃描結(jié)果不會(huì)保存在數(shù)據(jù)庫(kù)中。您可以使用如下kubectl describe命令來(lái)訪問(wèn)掃描的輸出:
kubectl describe scan semgrep-vulnerable-flask-app -nsecureCodeBox-system在kubectl的輸出中,我們可以看到如下內(nèi)容:

Semgrep執(zhí)行掃描后的輸出
在上圖中,我們可以通過(guò)“發(fā)現(xiàn)下載鏈接(Finding Download Link)”來(lái)下載報(bào)告。我據(jù)此訪問(wèn)了指向Kubernetes服務(wù)的URL,并收到了作為響應(yīng)的、JSON格式的Semgrep報(bào)告。下面,讓我們來(lái)查看這份報(bào)告:
{
...
"results": [
{
"check_id": "python.jwt.security.jwt-hardcode.jwt-python-hardcoded-secret",
"end": {
"col": 193,
"line": 184,
"offset": 6227
},
"extra": {
"engine_kind": "OSS",
"fingerprint": "221138ec7d837ea33e1e3346821e6bf50d3f21bf8600de705b7831ef2fe9139023f1f58202a21034ac06a54a67236bd9a41624ac7960e173627cb6298a92c5c6_0",
"is_ignored": false,
"lines": " auth_token = jwt.encode({'user': username, 'exp': get_exp_date(), 'nbf': datetime.datetime.utcnow(), 'iss': 'we45', 'iat': datetime.datetime.utcnow()}, app.config['SECRET_KEY_HMAC'], algorithm='HS256')",
"message": "Hardcoded JWT secret or private key is used. This is a Insufficiently Protected Credentials weakness: https://cwe.mitre.org/data/definitions/522.html Consider using an appropriate security mechanism to protect the credentials (e.g. keeping secrets in environment variables)",
"metadata": {
"category": "security",
"confidence": "HIGH",
"cwe": [
"CWE-522: Insufficiently Protected Credentials"
],
"cwe2021-top25": true,
"impact": "MEDIUM",
"license": "Commons Clause License Condition v1.0[LGPL-2.1-only]",
"likelihood": "HIGH",
"owasp": [
"A02:2017 - Broken Authentication",
"A04:2021 - Insecure Design"
],
"references": [
"https://semgrep.dev/blog/2020/hardcoded-secrets-unverified-tokens-and-other-common-jwt-mistakes/"
],
"semgrep.dev": {
"rule": {
"origin": "community",
"rule_id": "X5U8P5",
"url": "https://semgrep.dev/playground/r/l4T4vPA/python.jwt.security.jwt-hardcode.jwt-python-hardcoded-secret",
"version_id": "l4T4vPA"
}
},
...
}在上述報(bào)告中,我們可以看到:規(guī)則python.jwt.security.jwt-hardcode.jwt-python-hardcoded-secret識(shí)別出了存儲(chǔ)庫(kù)中的一個(gè)硬編碼密鑰。其問(wèn)題就出現(xiàn)在第 184行,與創(chuàng)建JWT令牌有關(guān)。作為令牌的密文,它使用了存儲(chǔ)在app.config['SECRET_KEY_HMAC']變量中的值。為了弄清楚這個(gè)值到底是硬編碼,還是從環(huán)境變量等中獲取的,我們搜索了設(shè)置該密鑰的位置,并最終確定了該變量定義的確源于硬編碼。
...
app.config['SECRET_KEY_HMAC'] = 'secret'
app.config['SECRET_KEY_HMAC_2'] = 'am0r3C0mpl3xK3y'
app.secret_key = 'F12Zr47j\3yX R~X@H!jmM]Lwf/,?KT'
...
if auth_user:
auth_token = jwt.encode({'user': username, 'exp': get_exp_date(), 'nbf': datetime.datetime.utcnow(), 'iss': 'we45', 'iat': datetime.datetime.utcnow()}, app.config['SECRET_KEY_HMAC'], algorithm='HS256')
resp = Response(json.dumps({'Authenticated': True, "User": username}))
#resp.set_cookie('SESSIONID', auth_token)
resp.headers['Authorization'] = "{0}".format(auth_token)
resp.status_code = 200
resp.mimetype = 'application/json'
return resp
...此外,為了加快漏洞報(bào)告的訪問(wèn)效率,我們可以使用DefectDojo作為與secureCodeBox集成的漏洞管理平臺(tái),以通過(guò)其友好的用戶界面和更高效的漏洞管理,來(lái)改進(jìn)流程。目前,SecureCodeBox允許我們將發(fā)現(xiàn)結(jié)果以持久方式傳遞給Azure Monitor、DefectDojo、Dependency-Track、以及ElasticSearch等服務(wù)。
小結(jié)
secureCodeBox作為一個(gè)獨(dú)立的掃描器,配置起來(lái)非常簡(jiǎn)單。在上文中,我們介紹了secureCodeBox的架構(gòu)、可用的掃描器、各種配置示例、以及典型用例。
在我看來(lái),secureCodeBox既是一個(gè)非常有前途的持續(xù)安全測(cè)試方案,也是為數(shù)不多的此類開(kāi)源項(xiàng)目之一。通過(guò)將其集成到CI/CD中,并根據(jù)代碼庫(kù)相關(guān)事件觸發(fā)掃描,它不但提供了在Kubernetes中執(zhí)行安全測(cè)試的能力,而且提供了許多開(kāi)源掃描器的集成,因此覆蓋了持續(xù)安全測(cè)試的大部分方面。同時(shí),它也可以被用作一體化的掃描服務(wù),針對(duì)代碼庫(kù)和已部署的應(yīng)用定期執(zhí)行自動(dòng)化的安全評(píng)估。
此外,secureCodeBox還可以直接向CI或?qū)S瞄_(kāi)發(fā)人員提供報(bào)告,使之能夠在將代碼合并到主分支之前,修復(fù)已發(fā)現(xiàn)的漏洞。當(dāng)然,應(yīng)該指出的是,由滲透測(cè)試人員進(jìn)行人工安全測(cè)試的傳統(tǒng)方法仍然十分重要,畢竟自動(dòng)化可能無(wú)法檢測(cè)到復(fù)雜的安全問(wèn)題。
總之,如果您正在尋找一個(gè)一體化的開(kāi)源掃描儀,且愿意使用Kubernetes和YAML文件去自定義掃描的話,secureCodeBox會(huì)是持續(xù)安全測(cè)試中最好、最被低估的開(kāi)源項(xiàng)目之一。
譯者介紹
陳峻(Julian Chen),51CTO社區(qū)編輯,具有十多年的IT項(xiàng)目實(shí)施經(jīng)驗(yàn),善于對(duì)內(nèi)外部資源與風(fēng)險(xiǎn)實(shí)施管控,專注傳播網(wǎng)絡(luò)與信息安全知識(shí)與經(jīng)驗(yàn)。
原文標(biāo)題:Exploring secureCodeBox— An Open-Source Continuous Security Testing Solution for DevSecOps,作者:Krzysztof Pranczk




























