iT邦幫忙

2026 iThome 鐵人賽

DAY 11
1

💡 今日學習目標:掌握在 SonarQube 介面中審查一筆資安問題的標準流程,學會把不安全的程式碼重構掉,並理解「修掉」與「標記」這兩條路各自該在什麼時候走。


📌 前言:發現問題後的關鍵一步,是修復與安全重構

經過昨天的掃描,我們在 SonarQube 的儀表板上拿到了專案報告:Security 面向有 1 筆待處理的問題

今天就用它走完一次完整流程:解讀 ➔ 判斷 ➔ 重構 ➔ 重新掃描 ➔ 歸檔

遇到這種告警,新手最常犯的兩個錯誤是:

  1. 視而不見:懶得看,直接全部標成「不是問題」把數字清空。
  2. 亂改一通:不知道正確做法,隨手改個寫法讓告警消失就算了。

這兩件事我們今天都會避開。


🧭 開始之前:一個你一定會發現的矛盾

先處理一件會讓你困惑的事,不然你會一直覺得哪裡怪怪的。

Day 08 在 IDE 裡,那條 md5 的告警被歸類為 Security Hotspot(資安熱點)。 但你昨天掃進伺服器之後,它出現在 Issues(問題) 清單裡,而不是獨立的 Hotspots 區塊。

點進去看,你會看到這個標籤:

SonarQube 的 Issues 清單,那筆問題被標上 Security、High 以及 former-hotspot 標籤

former-hotspot,直譯就是「曾經是 Hotspot」。SonarQube 自己承認了這件事。

為什麼會這樣?

Sonar 官方正在進行一項轉換:把過去歸類為 Security Hotspot 的規則,逐步改成直接產出資安問題。用官方文件的說法:

Rules that previously raised security hotspots will start raising vulnerabilities (Standard Experience) or security issues (MQR Mode).
(過去產出資安熱點的規則,將開始產出漏洞(標準模式)或資安問題(MQR 模式)。)

📖 資料來源:Sonar Documentation — Managing Security Hotspots

而且不只是規則層級的調整:在 v26 的左側選單裡,整個 Security Hotspots 頁面已經被掛上 Deprecated 標籤(步驟 4 的那張截圖就看得到)。這條路 Sonar 是真的打算收掉。

這對你來說其實是好事

Hotspot 這個設計原本的用意很好:「這段程式碼碰到了敏感領域,但我不知道你的用途,你自己判斷」。問題是它多了一層心智負擔,很多團隊看到 Hotspot 就不知道該不該當一回事,久了就整批忽略。

改成 Issue 之後,處理方式跟其他問題一致:要嘛修掉,要嘛明確標記為「已接受」並寫下理由。少一種特殊分類,就少一個被推託的藉口。

🔑 不過概念本身沒有消失。 「工具只能指出敏感用法,判斷用途的責任在你」這件事永遠成立,這也是 Day 08 心法 3 講的。變的只是它在介面上叫什麼名字。


🛠️ Step-by-Step:資安問題修復全流程

步驟 1:點開問題詳情,先讀完再動手

在儀表板點擊 Security 底下的 1 Open issues,會進到 Issues 清單。點那筆問題,右側會展開完整說明。

SonarQube 的問題詳情頁,顯示規則 javascript:S4790、Security High 影響,以及 Where is the issue 等分頁

畫面上有幾個地方值得看清楚:

  • 規則編號 javascript:S4790:點它會連到官方規則說明,那是最權威的出處。
  • Software qualities impacted:Security | High:它影響哪個品質面向、影響有多大。
  • Code attribute:Responsibility | Not trustworthy:Sonar 對這類問題的歸因分類。
  • Effort:30min:SonarQube 估計的修復成本。這個數字在排優先序時很有用。
  • 五個分頁Where is the issue?(問題在哪)、Why is this an issue?(為什麼這是問題)、How can I fix it?(怎麼修)、Activity(處理紀錄)、More info(延伸資料)。

請務必把 Why is this an issue? 讀完再動手。 這幾分鐘是整個流程裡最有價值的部分。你不是在應付一個紅字,而是在讀一份寫得很好的資安教材。


步驟 2:閱讀程式碼現況

我們要修的就是 Day 09 建立的那個 checksum.js,它在計算檔案的完整性校驗碼:

❌ 不安全的寫法(修復前)

const crypto = require("node:crypto");

// 計算檔案的完整性校驗碼(checksum)
function generateChecksum(fileBuffer) {
    // ⚠️ MD5 已被證實可以人為製造碰撞
    return crypto.createHash("md5").update(fileBuffer).digest("hex");
}

module.exports = { generateChecksum };
import hashlib

def generate_checksum(file_bytes: bytes) -> str:
    # ⚠️ MD5 已被證實可以人為製造碰撞
    return hashlib.md5(file_bytes).hexdigest()

⚠️ 風險解析:MD5 與 SHA-1 在密碼學上都已被證實存在**雜湊碰撞(Collision)**缺陷:攻擊者有辦法構造出兩份內容完全不同、但雜湊值一模一樣的檔案。

一旦如此,「用雜湊值確認檔案沒被掉包」這件事就失效了:惡意檔案可以偽裝成正常檔案通過你的校驗。


步驟 3:進行安全重構 (Refactoring)

依照 How can I fix it? 分頁的建議,把弱雜湊換成現代標準的 SHA-256

✅ 安全的寫法(修復後)

const crypto = require("node:crypto");

function generateChecksum(fileBuffer) {
    // 🛡️ 改用 SHA-256,目前沒有已知的實用碰撞攻擊
    return crypto.createHash("sha256").update(fileBuffer).digest("hex");
}

module.exports = { generateChecksum };
import hashlib

def generate_checksum(file_bytes: bytes) -> str:
    # 🛡️ 改用 SHA-256
    return hashlib.sha256(file_bytes).hexdigest()

🧭 順帶釐清一組很常被搞混的概念

  • 校驗碼(Checksum):只是要確認「內容有沒有被改動」,用 SHA-256 這種強雜湊就夠了,不需要金鑰
  • 簽章(Signature):要證明「這份資料確實出自持有金鑰的人」,就必須有金鑰,該用的是 Day 08 提過的 HMAC

換句話說,如果你的函式名字裡有「signature」,那光把 MD5 換成 SHA-256 是不夠的。你缺的不是更強的雜湊,而是根本還沒有金鑰參與。


步驟 4:重新掃描與狀態歸檔

審查一筆資安問題,最後一定會走到兩條路的其中一條。分清楚這兩條路,是這整篇最重要的觀念。

路徑 A:程式碼真的有問題 ➔ 修掉它

  1. 存檔改好的程式碼。
  2. 重新執行一次昨天那段 sonar-scanner 指令。
  3. 回到 SonarQube 重新整理,這筆問題會自己從清單上消失,Security 評分也會跟著回到 A。

因為程式碼裡已經沒有 md5 了,規則自然不再命中。這種情況你不需要去按任何按鈕,什麼都不用標記。

💡 這也是為什麼儀表板上的數字會自己變好。你要做的不是「處理掉那個數字」,是處理掉那段程式碼。

路徑 B:這段程式碼在你的情境下確實安全 ➔ 標記並留下理由

有些時候,工具點出的敏感用法在你的情境裡是無害的。例如:這個 MD5 只是用來為快取產生一個鍵值,跟安全性完全無關。

這時候才輪到標記功能上場。在問題詳情頁點開狀態下拉選單(預設是 Open),會跳出 Change issue status

SonarQube 的 Change issue status 下拉選單,列出 Accept、False Positive,以及被標為 Deprecated 的 Confirm 與 Fixed

四個選項,但實際上你只該用前兩個

選項 官方說明 什麼時候用
Accept Won't fix immediately, but will no longer affect the quality gate 風險已知、已評估,且在這個情境下可以接受
False Positive Analysis is incorrect 規則誤判,例如它把測試用的假資料當成真金鑰
Confirm 已標示 Deprecated 不要用
Fixed 已標示 Deprecated 不要用

AcceptFalse Positive 的差別很重要:前者是「我知道它是問題,我選擇承擔」,後者是「它根本不是問題」。用錯會誤導下一個看報告的人。

⚠️ 請把 Accept 的官方說明再讀一次:「will no longer affect the quality gate」。

按下去的那一刻,這筆問題就不再擋你的品質關卡了。這正是它危險的地方:它是一個可以把紅燈變成綠燈的按鈕。 所以下面那句「一定要寫理由」不是形式主義,那是唯一能攔住這個按鈕被濫用的東西。

不論選哪一個,一定要在留言欄寫下判斷理由。一個夠格的理由要能回答三件事:這段程式碼實際在做什麼、為什麼在這個用途下無害、誰在什麼時候做的判斷。像這樣:

此 MD5 僅用於產生本地快取的鍵值,不參與身分驗證、完整性校驗或任何安全決策,輸入也不受外部使用者控制。經團隊評估後接受此風險。確認日期:2026-xx-xx

反過來說,下面這幾種寫法等於沒寫:「不影響」「這個沒問題」「之後再處理」「PM 說先上線」。它們共同的問題是沒有描述用途,而用途正是這整個判斷唯一的依據。

🛑 這一步不能省。 一個沒有理由的 Accept,對三個月後的你或接手的同事來說,跟沒審查過完全一樣,他無從判斷你是真的想過,還是只是想把數字清成零。

而 Day 06 說過的那個判準在這裡依然適用:你是真的解決了風險,還是只是讓工具閉嘴?

📊 順帶一提,SonarQube 有幫你盯著這件事。 儀表板上有一個獨立指標叫 Accepted issues,說明文字寫著「Valid issues that were not fixed(有效但未修復的問題)」。

這個數字如果一路往上長,代表你的團隊正在累積技術債而不自知。它被單獨拉出來顯示,就是為了不讓「標記完就忘記」變成常態。


那我們手上這一筆,該選哪一個?

一個都不要選。

我們的 checksum.js 是拿 MD5 去做檔案完整性校驗,這正好就是 MD5 碰撞會讓防線直接失效的場景。它不是誤判,也不是可以接受的風險,它就是一個該修的問題。所以我們走路徑 A:改成 SHA-256、重新掃描,讓它自己從清單上消失。

上面那張下拉選單的截圖,是點開來看、然後關掉的。

認識這個選單長什麼樣子是必要的,但認識它真正的目的,是為了知道自己什麼時候不該用它。在你伸手去按 Accept 之前,先問一次:我是沒辦法修,還是不想修?


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

  • 🔹 心法 1:棄用過時的弱演算法。在任何與安全沾上邊的場景中,堅決不用 MD5 與 SHA-1。
  • 🔹 心法 2:一筆資安問題只有兩個結局:修掉,或寫下理由。修好的會自己消失;標記為已接受的,一定要留下判斷依據給下一個人。
  • 🔹 心法 3:把審查當成免費的資安課。每一筆問題的「Why is this an issue?」都是一份寫得很好的教材,你每讀一篇,功力就長一分。

🚀 階段二完結:從「檢查」走向「製造」

恭喜!到今天為止,我們完成了 階段二:資安是檢查出來的(Day 06 - Day 11)

這六天,我們一路走過:

  1. 搞懂了 Code Review 與 SAST 的分工,以及污點分析的四個核心概念。
  2. 認識了 SonarQube 家族,也誠實劃清了免費版的能力邊界,而昨天 SonarQube 自己也在儀表板上印出了同一句話。
  3. 親手裝上 IDE 外掛、用 Docker 架起檢測站、跑完第一次掃描、讀懂評分報告,並完成了第一次安全重構。

你現在擁有的,是一條實實在在、一毛錢沒花的檢查防線。

但別忘了 Day 03 戴明說的那句話:「檢查已經太遲了。品質的好壞,早就已經在產品裡面了。」

我們今天修掉的這個問題,其實是幾天前就已經寫進去的。如果在敲下那行程式碼的當下就寫對,這些重掃、重構、重新審查的時間,通通可以省下來。

接下來,我們即將進入:階段三 — 資安是「製造」出來的

Day 12 開始,我們要往品質演進的下一階前進,探討卡內基梅隆大學 SEI 的 Secure Coding 十大法則,以及 OWASP Top 10 的逐項攻防實戰,讓漏洞從一開始就沒有機會被寫出來。


💬 明日預告:【Day 12】既然事後要修,為什麼不一開始就寫好?SEI Secure Coding 核心哲學
明天我們將進入階段三,學習 SEI 提出著名的 Secure Coding 哲學與法則!


上一篇
【Day 10】【動手做】把程式碼丟進去掃描!解讀 SonarQube 的資安評分與漏洞報告
下一篇
【Day 12】既然事後要修,為什麼不一開始就寫好?SEI Secure Coding 核心哲學
系列文
槍林彈雨下的資安防守:從品質觀念切入,帶開發者從零動手作資安 30 天14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

1
AndyAWD
iT邦新手 1 級 ‧ 2026-08-30 21:58:24

原來現代標準是 SHA-256

我要留言

立即登入留言