iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
Security

槍林彈雨下的資安防守:從品質觀念切入,帶開發者從零動手作資安 30 天系列 第 10

【Day 10】【動手做】把程式碼丟進去掃描!解讀 SonarQube 的資安評分與漏洞報告

  • 分享至 

  • xImage
  •  

💡 今日學習目標:學會使用 SonarScanner 執行專案靜態檢測,並掌握看懂 SonarQube 資安評分 (A~E) 與 Quality Gates 門檻的核心技巧。


📌 前言:把程式碼丟進去,迎接你的第一份資安健檢報告!

昨天我們成功用 Docker 架設好了個人專屬的 SonarQube 伺服器。今天,我們要將專案程式碼發送過去,進行全方位的靜態分析,並學會如何解讀那份看似複雜的資安儀表板報告!


🛠️ Step-by-Step:執行 SonarScanner 專案掃描

步驟 1:下載或呼叫 SonarScanner

掃描器一樣不用安裝,直接用 Docker 跑就好。

掃描之前,要先在 SonarQube 網頁上建立專案。 這一段的介面設計有點反直覺,照著走:

① Projects ➔ Create Project

你會看到一整頁在推銷「從 DevOps 平台匯入」的大卡片:Azure DevOps、Bitbucket、GitHub、GitLab。

SonarQube 建立專案的第一頁,畫面主要被 DevOps 平台匯入選項佔滿,Create a local project 被放在最下方

我們要的不是那些。 往頁面最下面看,在「Are you just testing or have an advanced use-case?」這個標題底下,有一個不太顯眼的 Create a local project。點它。

② 1 of 2:填專案資訊

  • Project display namemy-first-security-project
  • Project key:會跟著自動帶入,不用改
  • Main branch name:保持 main

Next

③ 2 of 2:設定 New Code

它會問你「新程式碼」怎麼定義,並列出兩張卡片。點選 Follows the instance's default(Current default: Previous version),然後 Create project 才會從灰色變成可以按。

💡 這一步在問什麼? SonarQube 要知道「哪些算是這次新寫的」,才能只針對新程式碼算分。這正是 Day 29 會談的「Clean as You Code」 的底層機制:不要求你把十年的技術債一次還清,只要求你新寫的每一行都是乾淨的。對今天的練習來說怎麼選都不影響,用預設值最省事。

建完之後,SonarQube 會直接產生一段為你客製好的掃描指令,可以照抄;下面這段則是通用版本。先切換到昨天建立的那個專案資料夾再執行

cd ~/my-first-security-project
docker run --rm \
  --add-host=host.docker.internal:host-gateway \
  -e SONAR_HOST_URL="http://host.docker.internal:9000" \
  -e SONAR_TOKEN="$SONAR_TOKEN" \
  -v "$(pwd):/usr/src" \
  sonarsource/sonar-scanner-cli \
  -Dsonar.projectKey=my-first-security-project

📌 $(pwd) 會自動帶入你目前所在的目錄,所以不用手打絕對路徑。Windows 的 PowerShell 請改用 ${PWD},或直接把路徑寫死成 -v "D:\sonar-lab\my-first-security-project:/usr/src"

🔧 為什麼要多一行 --add-host
掃描器跑在容器裡,localhost 指的是容器自己,不是你的電腦。host.docker.internal 這個特殊名稱才是「宿主機」。
在 Windows / macOS 的 Docker Desktop 上它本來就能解析;但在 Linux 原生 Docker 上預設不存在,必須靠 --add-host=host.docker.internal:host-gateway 補上;少了它,你會看到連線被拒絕。

🔑 Token 不要直接貼在指令裡。 但要注意一個很多人以為有效、其實沒有的做法:單純打 export SONAR_TOKEN="xxx" 並不會避免它進入歷史紀錄,那一整行照樣會被寫進 ~/.bash_history

真正不留痕跡的寫法是分成兩個動作:

read -rs SONAR_TOKEN

按下 Enter 之後,畫面會完全沒有反應:沒有提示字元、沒有游標閃爍、貼上去也看不到任何字。那都是正常的(-s 代表 silent)。這時候才貼上 Token,再按一次 Enter。

接著洗掉可能混進來的看不見字元,再驗長度:

export SONAR_TOKEN="$(printf '%s' "$SONAR_TOKEN" | tr -d '[:space:]')"
echo ${#SONAR_TOKEN}

應該印出 44sqa_ 四個字元加上 40 個十六進位字元)。用長度驗證,不要直接 echo 出內容,否則前面的功夫就白費了。

⚠️ read 有一個很容易犯的錯:那一行裡的 SONAR_TOKEN 是「要存進哪個變數」,不是叫你把 Token 打在那個位置。如果寫成 read -rs sqa_xxxxx,你只是建立了一個名字很長的空變數,而那串 Token 反而原封不動地進了歷史紀錄,跟原本想避免的事情一模一樣。

這就是 Day 08 那條「硬編碼機密」規則實際派上用場的地方,而且順帶示範了一件事:「我以為這樣就安全了」跟「實際上真的安全」之間,往往差一個查證的動作。

💻 PowerShell 沒有 read -rs,對應的寫法是:

$env:SONAR_TOKEN = (Read-Host "Token" -MaskInput)
$env:SONAR_TOKEN.Length

-MaskInput 需要 PowerShell 7 以上。舊版的 Windows PowerShell 5.1 沒有這個參數,最簡單的替代是先在編輯器裡把 Token 貼好、確認沒有多餘的空白與換行,再貼進終端機,並在用完之後執行 Clear-History

掃描過程會看到系統依序分析語法樹與規則庫,約耗時 10 ~ 30 秒,最後出現 EXECUTION SUCCESS

https://ithelp.ithome.com.tw/upload/images/20260829/20007542D4DUf8IzLS.png
終端機顯示掃描完成,出現 ANALYSIS SUCCESSFUL 與 EXECUTION SUCCESS,總耗時 14.4 秒

看到 EXECUTION SUCCESS 就成功了。上面幾行也值得看一眼:ANALYSIS SUCCESSFUL, you can find the results at: ... 那一行會直接給你儀表板的網址。


🔧 掃描失敗?這三個是最常見的

ERROR Failed to query server version: invalid header value: "Bearer sqa_..."

看到 invalid header value,先別往網路設定或防火牆的方向查。它的意思是 HTTP 標頭裡有不合法的字元,而十之八九是你的 Token 尾端混進了看不見的東西:一個空格、一個換行,或是從 Windows 複製時帶過來的

錯誤訊息不會告訴你這件事,它只會把整串 Token 原封不動印出來(順帶一提,這也表示失敗訊息本身就會洩漏 Token,截圖前要留意)。

解法就是前面那行 tr -d '[:space:]',然後用 echo ${#SONAR_TOKEN} 確認長度是 44。

EXECUTION FAILURE 但完全沒有錯誤細節

多半是連不到伺服器。先確認容器還活著:

docker ps --filter name=sonarqube

如果 STATUS 不是 Up,用 docker start sonarqube 啟動它。重開機之後容器不會自己起來,這是很多人第二天回來就卡住的原因。

Conflict. The container name "/sonarqube" is already in use

這是昨天架設時可能撞到的:容器已經存在,只是停掉了。不要重跑 docker run,直接 docker start sonarqube 就好。真的要重建才用 docker rm -f sonarqube 砍掉再來一次;因為我們有掛資料卷,砍容器不會丟資料。


🔍 核心儀表板解讀:A~E 評分與 Quality Gates

回到瀏覽器打開 http://localhost:9000,點進剛剛分析的專案頁面,就會看到整份健康度報告。

https://ithelp.ithome.com.tw/upload/images/20260829/200075429LcNV2qBgm.png


1. 先講一件事:你查到的教學,分類方式可能跟你的畫面不一樣

如果你 Google 過 SonarQube,八成看過這組名詞:Vulnerabilities(漏洞)/ Bugs(缺陷)/ Code Smells(程式碼壞氣味),再加上獨立的 Security Hotspots(資安熱點)

但你現在的畫面上找不到它們。 你看到的是這三個:

面向 它在問什麼
🔐 Security(安全性) 這段程式碼會不會被拿來攻擊?
🎯 Reliability(可靠性) 這段程式碼會不會在執行時出錯?(大致對應舊的 Bugs)
🔧 Maintainability(可維護性) 這段程式碼好不好改?(大致對應舊的 Code Smells)

這是 SonarQube 的 MQR 模式(Multi-Quality Rule,多品質規則),也是新版的預設。它換了一個提問角度:舊的分類問「這是什麼類型的問題」,新的分類問「這個問題影響了哪一種軟體品質」。

同一段爛程式碼,可能同時傷害好幾個面向,舊的三選一分類裝不下這件事,這就是它被換掉的原因。

💡 想切回舊的分類也可以。 在 Issues 頁面的左側,SonarQube 會直接問你:Looking for Bugs, Vulnerabilities, or Code Smells? If your team prefers working with these types, change it in the settings。點進去就能切成 Standard Experience

本文一律以新版預設的 MQR 模式為準,因為那是你全新安裝後會看到的樣子。


2. ⚠️ 這份報告「沒說」的事,比它說了什麼更重要

看到 Quality Gate 亮綠燈、Security 只有一筆,很容易鬆一口氣。但先別急。

把儀表板往下捲,SonarQube 自己印了一行話在那裡:

https://ithelp.ithome.com.tw/upload/images/20260829/20007542ZqzJsRBWyG.png

SonarQube Community Build does not scan for critical injection vulnerabilities (SQL injection, XSS, and more).
(SonarQube Community Build 不會掃描關鍵的注入類漏洞,包含 SQL 注入、XSS 等等。)

這正是 Day 07 說過的那件事,只是這次由產品自己承認:免費版沒有跨檔案的污點分析,而 SQL Injection、XSS、Command Injection 這些注入類漏洞,必須追蹤資料流才認得出來。它不是沒抓到,是根本沒有在找

所以,你要這樣讀這份報告:

  • 它抓到的,都是真的問題。 沒有誤報就當沒事的問題。
  • 它沒抓到的,不代表沒有。 尤其是整個注入家族,那正好是 OWASP Top 10 裡的 A05。

🔑 這是使用任何工具最重要的一件事:知道它的量表是怎麼刻的。

一把體重計不會告訴你血壓有沒有問題,但它也從來沒有宣稱過自己會。真正危險的不是工具有邊界,而是你以為它沒有邊界

而這也是為什麼這 30 天不會停在「裝好工具」就結束。Day 12 開始,我們要把防線往前挪到「寫的時候就不要寫錯」,因為那才是掃描器永遠涵蓋不到的部分


3. 資安評分機制 (Security Rating)

SonarQube 會給專案 A 到 E 的等級評分。這裡有個細節容易搞混:新舊版本用的嚴重度名稱不一樣,你看到哪一組,取決於伺服器啟用的是哪種模式。

🔍 怎麼知道自己這台是哪一種模式?看頁尾。 SonarQube 每一頁的最下方都會印出版本資訊,例如 Community Build • v26.8.0.126808 • MQR MODE。那個 MQR MODE 就是「多品質規則模式」(Multi-Quality Rule),也是新版的預設值。如果你看到的是別的字樣,就對照下表的另一欄。

評分 多品質規則模式(新版預設)Multi-Quality Rule Mode 標準模式(舊版體驗)Standard Experience
🟢 A 沒有 Low 以上的資安問題 0 個 Vulnerability
🟡 B 至少 1 個 Low 至少 1 個 Minor
🟠 C 至少 1 個 Medium 至少 1 個 Major
🔴 D 至少 1 個 High 至少 1 個 Critical
🚨 E 至少 1 個 Blocker 至少 1 個 Blocker

原則是共通的:只要出現一個某等級的資安問題,整個專案的評分就被拉到對應的那一級。它取的是最嚴重的那一個,不是平均值。這個設計是刻意的,因為資安沒有「平均起來還不錯」這回事。


4. 品質閘門 (Quality Gates)

什麼是 Quality Gate
這是「資安是管理出來的」核心通則之一。品質閘門就像是專案門禁系統,您可以設定標準(例如:「若 Security Rating 低於 A 級,就不准 Merge 至主分支!」)。

當掃描結果通過標準,會顯示綠色的 [ Passed ];若沒通過,則顯示紅色的 [ Failed ]


🎯 今日重點小結與防守心法

  • 🔹 心法 1:綠燈只代表「這把尺量得到的範圍內沒問題」。Community Build 自己印在儀表板上:它不掃注入類漏洞。Security 評 A 不是安全證明,是量表的邊界。 另外,先看一眼頁尾那行 MQR MODE,確認你讀的分類跟你查到的教學是同一套。
  • 🔹 心法 2:評分取最嚴重的那一個,不是平均。一個 Blocker 就能把整個專案拉到 E,資安沒有「平均起來還不錯」這種事。
  • 🔹 心法 3:讓數據說話。一份客觀的掃描報告,比口頭宣稱「我的 Code 很安全」有說服力得多,而且下次改版還能拿來比對趨勢。

💬 明日預告:【Day 11】【動手做】修復你的第一個資安問題:安全重構與狀態歸檔
報告拿到了,Security 那一欄躺著一筆問題。明天我們手把手走完一次完整的審查流程:讀懂它、修掉它,並且弄清楚「修掉」與「標記為可接受」這兩條路,各自該在什麼時候走。


上一篇
【Day 09】【動手做】零成本建置資安檢測站:使用 Docker 5 分鐘架設 SonarQube
系列文
槍林彈雨下的資安防守:從品質觀念切入,帶開發者從零動手作資安 30 天10
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言