iT邦幫忙

2025 iThome 鐵人賽

DAY 8
0
DevOps

連DevSecOps都不知道怎麼發音怎麼開始學習?系列 第 8

Day.8 從網工到 DevSecOps:用 Bandit 打造程式碼第一道防線

  • 分享至 

  • xImage
  •  

程式碼裡的一行小疏忽,就是巨人攻破城牆的缺口。

自我介紹:寫到Day8才想到

在開始導入安全檢查之前,先說一下背景。
我原本是網路工程師,日常工作多半圍繞在網路維運、權限控管,像 Active Directory 的操作權限設定。嚴格說起來,這些雖然跟資安沾邊,但偏基礎,並不直接涉及應用程式或軟體開發的安全。

也因為這樣,踏進 DevSecOps 的直覺是:這很像我以前管網路,只是守門位置從交換機、防火牆,延伸到整個軟體生命週期。

安全檢查(特別是 SAST 這類靜態分析工具)就是這個概念的體現。
在程式碼還沒部署前,就能先檢查出潛在的危險語法,避免弱點跟著進入生產環境。

過去我在做的是「守住誰能進網路門口
而現在我要學會的是「在軟體還沒出門前,就把漏洞攔下來」。

那我們就正式進入今天的重點吧


1.前言

功能測試過關,不代表系統安全,只代表它能正常跑。

DevSecOps 的做法是把安全檢查左移到日常開發與 CI:在程式上線前,就先把可能的洞找出來、擋下來。今天用Bandit,把「巡牆」這件事自動化——每次提交都掃一次,裂縫別留到明天。

為什麼要做 SAST(靜態程式碼安全測試)?

SAST 是在「不執行程式」的狀態下,直接從原始碼找安全風險。它補的是功能測試看不到的盲區,常見像:

  • 硬編碼敏感資訊(密碼、Token、金鑰)
  • 危險 API 使用eval / execsubprocess(..., shell=True)
  • 不安全雜湊/隨機數hashlib.md5random 拿去做安全用途)
  • 未驗證的網路請求requests(..., verify=False)

SAST 不就多一層檢查,會不會拖慢節奏?

在本機你可以只掃改到的檔案、或在 commit 前跑一次;完整掃描交給 CI。養成小步快掃的節奏,效能與安心感會一起上來。

2. Bandit 快速上手

安裝:

pip install bandit

掃描整個專案:

bandit -r .

掃描單檔或特定目錄:

bandit app.py
bandit -r src/

判讀結果(範例):

>> Issue: [B307:blacklist] Use of possibly insecure function - eval.
   Severity: High   Confidence: High
   Location: app.py:42
  • Severity=嚴重性(High/Medium/Low)
  • Confidence=判斷可信度
  • Location=精確行數

掃出一大堆警告,要全修嗎?

不必追求 0 警告。先處理 High 嚴重 + High 可信 的項目;Medium 視情況排期;Low 多半是提醒。把風險排序,比盲修有效。

3. 典型問題與修正範例

(a) 危險執行

# ❌ 風險:任意輸入可被執行(B307/B102)
eval(user_input)
# ✅ 安全做法:白名單或結構化解析
import ast
safe_value = ast.literal_eval(user_input)  # 僅允許字面常量

(b) Shell 注入

# ❌ 風險:shell=True(B602)
subprocess.run(f"ls {arg}", shell=True)

# ✅ 安全做法:避免 shell,使用參數陣列
subprocess.run(["ls", arg], check=True)

(c) 不安全的雜湊/隨機數

# ❌ 風險:弱雜湊 / 非安全用途隨機(B303)
hashlib.md5(password).hexdigest()

# ✅ 安全做法:使用強雜湊或 KDF
import hashlib
hashlib.sha256(password).hexdigest()

(d) 關閉憑證驗證

# ❌ 風險:跳過 SSL 驗證(B501)
requests.get(url, verify=False)

# ✅ 安全做法:保留驗證,必要時配置信任根
requests.get(url, timeout=10)  # 預設 verify=True

遇到誤報怎麼辦?
可以在單行末尾加 # nosec 暫時忽略,但務必附註理由,例如:

safe_eval = ast.literal_eval(user_input)  # nosec: literal_eval 限制了輸入型態

或集中管理在設定檔排除特定路徑/規則,避免把真正的洞當誤報蓋過去。

4. 專案設定與門檻

在專案根目錄加入 bandit.yaml,統一規則與門檻:

# bandit.yaml
exclude_dirs:
  - tests
  - venv
  - .venv
# 只擋中高風險、判斷可信度至少 Medium
severity: medium
confidence: medium

執行時帶上設定:

bandit -r . -c bandit.yaml

好處:

  • 團隊行為一致(本機與 CI 用同一套規則)
  • 排除測試或虛擬環境等不需要掃的目錄
  • 明確定義「什麼等級要擋」→ 可對齊 Branch 保護

5. 串到 CI:讓巡邏自動化(GitHub Actions)

在你現有的 ci.yml 加一個步驟即可(放在 lint 後、測試前或後都行):

- name: Security check (Bandit)
  run: |
    bandit -r . -c bandit.yaml \
      --severity-level medium \
      --confidence-level medium \
      -f json -o bandit-report.json

結論

  • SAST ≠ 功能測試:它專盯安全用法,補功能測試看不到的洞。
  • Bandit 易上手:一行指令先掃起來;用設定檔把門檻與排除路徑固化。
  • 自動化最好:掛進 CI,配合 Branch 保護,把「巡牆」變日常。

城牆不會瞬間崩塌,但裂縫沒人看,總有一天會變缺口。
把 Bandit 放進你的流程,就是安排一支不下線的巡邏隊,安靜但有效。


上一篇
Day.7 守門人升級:Python 多版本驗證(本地 tox × GitHub Actions Matrix)
下一篇
Day.9 DevSecOps 的第二道防線:pip-audit 揪出城牆內的臥底
系列文
連DevSecOps都不知道怎麼發音怎麼開始學習?21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言