💡 今日學習目標:學會使用 SonarScanner 執行專案靜態檢測,並掌握看懂 SonarQube 資安評分 (A~E) 與 Quality Gates 門檻的核心技巧。
昨天我們成功用 Docker 架設好了個人專屬的 SonarQube 伺服器。今天,我們要將專案程式碼發送過去,進行全方位的靜態分析,並學會如何解讀那份看似複雜的資安儀表板報告!
掃描器一樣不用安裝,直接用 Docker 跑就好。
掃描之前,要先在 SonarQube 網頁上建立專案。 這一段的介面設計有點反直覺,照著走:
① Projects ➔ Create Project
你會看到一整頁在推銷「從 DevOps 平台匯入」的大卡片:Azure DevOps、Bitbucket、GitHub、GitLab。

我們要的不是那些。 往頁面最下面看,在「Are you just testing or have an advanced use-case?」這個標題底下,有一個不太顯眼的 Create a local project。點它。
② 1 of 2:填專案資訊
my-first-security-project
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}應該印出 44(
sqa_四個字元加上 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。

終端機顯示掃描完成,出現 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 砍掉再來一次;因為我們有掛資料卷,砍容器不會丟資料。
回到瀏覽器打開 http://localhost:9000,點進剛剛分析的專案頁面,就會看到整份健康度報告。

如果你 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 模式為準,因為那是你全新安裝後會看到的樣子。
看到 Quality Gate 亮綠燈、Security 只有一筆,很容易鬆一口氣。但先別急。
把儀表板往下捲,SonarQube 自己印了一行話在那裡:

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 這些注入類漏洞,必須追蹤資料流才認得出來。它不是沒抓到,是根本沒有在找。
所以,你要這樣讀這份報告:
🔑 這是使用任何工具最重要的一件事:知道它的量表是怎麼刻的。
一把體重計不會告訴你血壓有沒有問題,但它也從來沒有宣稱過自己會。真正危險的不是工具有邊界,而是你以為它沒有邊界。
而這也是為什麼這 30 天不會停在「裝好工具」就結束。Day 12 開始,我們要把防線往前挪到「寫的時候就不要寫錯」,因為那才是掃描器永遠涵蓋不到的部分。
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 |
原則是共通的:只要出現一個某等級的資安問題,整個專案的評分就被拉到對應的那一級。它取的是最嚴重的那一個,不是平均值。這個設計是刻意的,因為資安沒有「平均起來還不錯」這回事。
什麼是 Quality Gate?
這是「資安是管理出來的」核心通則之一。品質閘門就像是專案門禁系統,您可以設定標準(例如:「若 Security Rating 低於 A 級,就不准 Merge 至主分支!」)。
當掃描結果通過標準,會顯示綠色的 [ Passed ];若沒通過,則顯示紅色的 [ Failed ]。
MQR MODE,確認你讀的分類跟你查到的教學是同一套。💬 明日預告:【Day 11】【動手做】修復你的第一個資安問題:安全重構與狀態歸檔
報告拿到了,Security 那一欄躺著一筆問題。明天我們手把手走完一次完整的審查流程:讀懂它、修掉它,並且弄清楚「修掉」與「標記為可接受」這兩條路,各自該在什麼時候走。