這篇整理一台持有程式碼與正式環境存取權的主機被入侵之後,從止血完成到可以宣告事故已解除之間要做的事。以長期存在的 CI 建置主機(自架的 Jenkins、自架的 runner)為例,因為它同時碰得到原始碼、建置產物與部署目標。範圍從入侵已經被確認、主機的對外連線已經被斷開那一刻開始;如何判斷這是資安事故、如何啟動,在 8.17 Security Incident vs Operational Incident 分流 與 8.1 事故分級與啟動條件。用每次執行後就銷毀的託管 runner 時,沒有主機可以重建,清查改從儲存庫與組織層級的 secrets、OIDC 信任設定與 workflow 的修改紀錄開始,存取憑證、產物與監看的部分照本篇處理。

〈對外宣告已掌握狀況的條件〉與〈對外承諾賠償的時機〉兩節以多租戶電商平台為例,三個角色分別是:平台(服務提供者,也就是這台主機的擁有者)、商家(平台的客戶,即租戶)、會員(商家的終端使用者,訂單資料裡的當事人)。平台在事前如何限制一台主機碰得到的租戶數,見 7.44 多租戶平台的隔離層級。

根除在事故處理中的位置

NIST SP 800-61 Rev. 2 把資安事故處理的中段命名為 Containment, Eradication, and Recovery。三個動作的對象不同:

  • 止血(Containment,其他中文資料常寫作圍堵或遏制) 切斷攻擊者已知的存取路徑,讓擴散停止:斷開主機的對外連線、停用已知外洩的帳號。對應 8.3 止血、降級與回復策略。
  • 根除(Eradication) 移除攻擊者在環境裡留下的全部立足點(foothold):他拿到的憑證、他放進去的後門、他改過的程式、產物與資料。
  • 回復(recovery) 用已知乾淨的元件把服務帶回來,並觀察攻擊者是否再次進入。

NIST SP 800-61 的 Rev. 3 改以 NIST Cybersecurity Framework(CSF)2.0 的功能組織,見 NIST SP 800-61r3 素材。

運維事故的故障原因不會主動尋找新的路徑;資安事故中間多了根除,因為攻擊者是一個會主動回來的對手。止血只切斷已知的路徑,攻擊者手上還沒被發現的憑證在止血之後仍然可用。所以止血完成時若就宣告事故解除,攻擊者可以用另一把還沒被發現的憑證再進來一次。

清查範圍:主機上的存取憑證、讀寫得到的資料、網路連得到的系統、產物與可寫入的程式碼

事故處理團隊從列出這台主機遭攻擊者控制期間,攻擊者可能碰過的全部系統、憑證、資料與產物開始根除。這份清單從主機的權限推出,而不是從已經發現的攻擊者動作推出(這個做法在資安領域稱為 assume breach:假設權限範圍內的一切都已經被碰過):日誌只記錄留下痕跡的動作,攻擊者讀取一份設定檔或環境變數多半不留痕跡。CI 建置主機的清單通常包含以下幾類:

  • 主機上的存取憑證:環境變數與管線設定裡的雲端存取金鑰、資料庫密碼、部署用的 SSH 金鑰、套件庫與容器映像庫的發佈權杖、程式碼儲存庫(repository)的寫入權杖、通知與第三方服務的 API 金鑰,以及建置主機自己簽章時的產物簽章金鑰。這些憑證全部視為外洩,不論日誌是否顯示被讀取。例外是放在 HSM 或雲端 KMS、不可匯出的簽章金鑰:主機只有呼叫簽章的權限,金鑰本身沒有離開過,所以撤銷的是主機的簽章權限、金鑰保留,入侵期間簽過的產物依 KMS 自己的稽核紀錄列出,照〈被入侵主機與入侵期間產物的處置〉處理。可以匯出的簽章金鑰處置與其他憑證不同:撤銷之後,用它簽過的產物全部失去可信度,見 7.6 秘密管理與機器憑證治理〈簽章金鑰跟長期信任根〉。
  • 主機讀得到的原始碼與快取:主機為了建置而讀得到的原始碼、建置快取與相依套件快取,裡面寫死的金鑰與連線字串同樣視為外洩,與主機上的憑證一起列進清單。
  • 存取憑證能到達的系統與資料:每一把憑證往下推一層:資料庫密碼能讀哪幾座資料庫、雲端金鑰能操作哪些帳號與資源。這一類決定客戶資料是否在範圍內;建置主機持有正式資料庫的讀取權時,那些資料庫裡的資料就在範圍內。憑證有寫入權時,範圍還包含入侵期間被改過的資料:應用程式裡新增的管理員帳號、被改過的撥款帳號與 webhook 位址,以及資料庫裡新增的 trigger、function 與使用者。這些是攻擊者留在資料裡的立足點,要拿入侵前的備份或稽核紀錄比對找出來。
  • 主機在網路上連得到的系統:不需要任何憑證、只憑這台主機在內網或 VPN 裡的位置就連得到的服務,例如假設「連得到的都是自己人」而不驗證來源的內部 API、管理介面與監控端點。這一類不在憑證清單上,要從主機所在網段的存取規則與連線紀錄推出;主機向平常不連的位址發起過連線,代表擴散可能已經發生。攻擊者以這台主機為起點往其他機器擴散的方式見 Lateral Movement(橫向移動)。
  • 主機建置的產物:入侵期間建置的每一個產物(套件、容器映像、行動 App 安裝檔)都可能被植入程式,而那些產物可能已經部署到正式環境、或已經發佈給商家與會員。處置的範圍是仍在正式環境執行、仍能從套件庫或映像庫取得、或仍安裝在使用者裝置上的產物;已經不再執行也不再發佈的舊產物,只列進受影響範圍的說明。
  • 主機能寫入的程式碼:持有儲存庫寫入權杖時,審查的對象是現在的程式碼:拿現在的分支與清查起點之前最後一個經過審查的版本比對差異,逐一審查差異裡對原始碼、建置腳本與相依套件版本的修改;儲存庫平台自己的推送紀錄查得到用主機上的權杖推送的 commit 時,那些 commit 優先審查。入侵期間被加入、之後又被移除的程式碼只影響當時建出的產物,由產物那一類涵蓋。

清單的時間起點是最早一筆可疑存取,不是偵測到的那一刻。判讀以送到主機外、主機沒有權限改寫的紀錄為準:集中日誌、雲端稽核紀錄、儲存庫與映像庫自己的存取紀錄;只存在被入侵主機上的日誌可能已經被攻擊者修改過,不能拿來縮短清查範圍。入口若是已知的漏洞或被盜的存取憑證,起點至少推到漏洞開始暴露或憑證被核發的時間。無法排除入侵早於這些紀錄時,憑證、產物與重建來源的起點往前推到能證明主機乾淨的最近一個時間點,也就是上一次從已知乾淨來源重建這台主機的時間;沒有這個時間點,就從主機建立時算起。紀錄保留期的邊界只用在對外說明裡標出「早於某日的存取無法確認」。

被入侵主機與入侵期間產物的處置

被入侵主機的處置是重建:從已知乾淨的來源建一台新的。理由是找到並刪掉攻擊者放的檔案,證明不了攻擊者沒有放別的檔案:排程工作、加進 authorized_keys 的公鑰、被改過的系統工具、被改過的基礎映像,每一種都可以藏在檢查沒有看的地方。

舊主機保留下來供數位鑑識(Digital Forensics),不再接回網路。鑑識資料的擷取次序由資料的揮發程度決定(order of volatility):記憶體、執行中的程序與網路連線只在主機開機時存在,關機就消失,磁碟快照在關機後仍然取得到,所以事故處理團隊要在關機之前擷取前三項。

「已知乾淨的來源」本身要先確認。這台主機若持有儲存庫或映像庫的寫入權,版本控制裡的基礎設施設定與映像庫裡的基礎映像都可能在入侵期間被改過,所以重建取的是:基礎設施設定用清查起點之前的 commit,或審查過起點之後每一筆修改的版本,兩者擇一;基礎映像用起點之前就固定下來的 digest,而且這個映像的簽章是由不在被入侵主機上的金鑰簽出的(金鑰若在主機上,攻擊者可以替改過的映像補簽)。重建的前提是主機的設定本來就寫成程式碼(Infrastructure as Code);沒有的話,這次重建同時是把它寫成程式碼的時機。重建主機與發放新憑證都要用一個不在被入侵主機上、入侵期間沒有暴露過的管理身分;手上沒有這樣的身分時,取得它的方式是先向雲端業者或系統管理者取回帳號的控制權。

「刪掉找到的檔案證明不了沒有別的檔案」這個理由同樣適用於產物:入侵期間建置的產物要從已審查過的原始碼重新建置,並與先前的產物比對雜湊值。雜湊值相同的產物可以保留;不同的視為被改過,撤下並追蹤它已經部署到哪些環境、發佈給哪些對象。比對要靠可重現建置才有意義(Reproducible Build:同一份原始碼在相同的建置環境下建出逐位元相同的產物);建置不可重現時,雜湊值本來就不會相同,改用逐檔比對工具(例如 diffoscope)比對重建版本與原產物:差異只落在時間戳、檔案順序、建置路徑這類已知的變動資訊時可以保留;差異落在程式內容,或比對不出結果時,撤下並改用重建的版本。

撤下產物的代價集中在已經發佈出去的產物上。入侵期間建出的行動 App 照常簽章、照常上架,因為建置流程本身沒有異常;它裝到會員的手機上之後,行為監測分不出它與正常版本,因為簽章出自正牌管線。已經安裝的舊版無法從裝置上移除:後端可以依版本號拒絕那幾個版本的 API 呼叫並要求更新,切斷依賴後端的功能,而在裝置上直接外送資料的行為擋不住。建置管線上游被植入、已簽章的產物發佈給下游的實例見 SolarWinds 2020。產物的來源與簽章關係見 Artifact Provenance 與 7.12 供應鏈完整性與 Artifact 信任,把這套處置做成演練的版本見 Supply Chain Artifact Drill。

存取憑證撤銷與輪替的先後

撤銷舊憑證與發放新憑證的先後,由「新憑證只出現在攻擊者存取不到的地方」這個條件決定。攻擊者存取得到的地方,包含網路上連得到的與手上有權限讀取的:新憑證寫進舊主機,或寫進攻擊者手上的憑證讀得到的秘密管理服務、雲端帳號,攻擊者讀到的就是新憑證。攻擊者在入侵期間若在秘密管理服務或雲端帳號裡新增了自己的金鑰,撤銷原本的憑證也擋不住他讀取那裡。由這個條件推出三件事:

  • 讀得到新憑證存放位置的那幾把憑證先撤銷:秘密管理服務與雲端帳號的存取金鑰,連同用它們換出、還沒到期的臨時 session(雲端業者多半另外提供撤銷既有 session 的操作,撤銷長期金鑰不會讓它們失效),在任何新憑證寫入之前撤銷。這把憑證若也被對客戶的正式服務用來讀取秘密,先用不經過那個秘密管理服務的管道(以檢查過的管理身分從基礎設施設定部署)把新憑證交給正式服務,再撤銷舊的;兩步之間的間隔由事故指揮決定,並寫進決策紀錄。
  • 存放新憑證的位置先檢查過:事故處理團隊逐一檢查憑證能到達的系統,包含要存放新憑證的秘密管理服務與雲端帳號,確認是否被加入新的帳號、新的金鑰或新的存取規則。攻擊者在那裡建立的存取方式不依附原本那把憑證,撤銷原本那把不會讓它消失。
  • 其餘憑證先發新、再撤舊:新的一把只要放在檢查過的位置,先發新再撤舊不會讓新的那一把外洩,還能縮短服務中斷的時間;舊的那一把在新的生效之後立刻撤銷。沒有服務依賴的憑證不必等新的一把,直接撤銷。清單上職責不需要的憑證(例如建置主機持有的正式資料庫讀取權)不發回新主機,替代做法見 7.44 多租戶平台的隔離層級〈存取層的隔離〉。能改成短期憑證的在這一次改掉(7.6 秘密管理與機器憑證治理、7.10 Workload Identity 與聯邦信任邊界):下一次入侵時,外洩的臨時憑證在設定的有效期(常見是一小時以內)過後失效。

清單上的憑證多到無法同時發新時,負責輪替的團隊依兩個軸排序:這把憑證被外洩後碰得到的資料敏感度與租戶數(決定它留著的風險),以及依賴它的服務中斷時的業務代價(決定它停著的成本)。讀得到客戶資料庫的憑證與發佈權杖風險最高,排在最前面;風險相近時,中斷代價高的先恢復。排序要先有憑證清單與擁有者的對照,見 7.6 秘密管理與機器憑證治理〈CI secrets 集中化跟 blast radius〉;輪替量與優先序的取捨見 CircleCI 2023:CI secrets 輪替壓力。7.27 Credential Rotation with Scoped Evidence 實作示範 的分批與新舊並行窗口,適用於憑證還沒確認落入攻擊者手中的輪替;主機已確認被入侵時,讀得到存放位置的憑證不留並行窗口。

多波攻擊的監看與它的結束條件

攻擊者在第一波取得的資訊,在根除完成之後仍然有效:讀過的原始碼讓他知道內部端點與驗證邏輯、其他系統的弱點。第二波攻擊用這些資訊從另一個入口進來,不需要再經過這台主機。攻擊者在環境裡停留的時間(dwell time)越長,他取得的資訊越多。

根除完成之後的監看因此要涵蓋兩類訊號,兩類都以入侵指標(Indicator of Compromise,能辨認同一個攻擊者活動的特徵)與第一波取得的資訊為對象:第一波用過的來源位址與工具特徵設成告警;第一波資訊被使用的跡象,也就是已輪替的舊金鑰被嘗試使用、被讀過的內部端點出現異常存取。前一類只認得同一組特徵,攻擊者換一個來源位址就比對不到;後一類不管他從哪個入口進來,只要用到第一波的資訊就看得到。舊金鑰被嘗試使用要靠驗證端在拒絕時記下金鑰識別碼才看得到,雲端存取金鑰多半有這筆紀錄,資料庫密碼這類共享密碼多半沒有;看不到的那幾類,可以在舊位置留一把不對應任何權限的誘餌憑證,偵測它被使用。

監看期是根除完成之後,針對同一個攻擊者加強監看的這段期間,從根除完成起算。它用兩項結束條件定義,兩項都成立才結束:

  • 第一波資訊已失效:清查清單上的憑證與寫死的金鑰都已撤銷或輪替、內部端點已加上存取控制、被讀過的原始碼裡已知的驗證缺陷已修補,並對攻擊者讀得到的程式碼裡對外開放的端點、身分驗證與授權邏輯、處理金鑰的模組做過一次安全審查。審查沒有涵蓋的模組逐項列出並寫明理由;列出之後不阻擋結束,而是留給事故後的改善追蹤。
  • 告警期間未觸發:上面兩類告警從第一波資訊全部失效那一刻起,持續一段期間沒有觸發。期間長度沒有公認的算法,由事故指揮(incident commander,負責這次事故各項決定的人,見 Incident Command System)訂定,並把採用的長度與依據寫進決策紀錄(8.19 Incident Decision Log)。能從主機外的紀錄讀出攻擊者兩次存取之間的間隔時,期間不短於這個間隔,否則告警沒觸發可能只是剛好落在攻擊者沒有動作的空檔;讀不出來(攻擊者只出現過一次、紀錄不完整)時,在決策紀錄裡寫明。

監看期新增的告警怎麼併進既有的偵測規則、避免與既有告警重複或留下沒人看的告警,見 7.13 偵測覆蓋率與訊號治理。

對外宣告已掌握狀況的條件

對外說「已掌握狀況」是一個事後會被檢驗的事實宣稱。事故指揮決定對外宣告的內容,而可以宣告的內容隨根除進度分成四個等級,依序成立、後一級以前一級為前提,每一個等級對應一組已經成立的事實:

  • 已切斷已知的入侵路徑:入口主機已斷開、已知外洩的帳號已停用。止血完成時就成立。
  • 已確認受影響範圍:這次事故實際波及哪些資料、哪些系統、哪段時間已經確認,無法確認的部分也已列出。清查清單完成時才成立。多租戶平台在這一級還要交代入口元件碰得到哪些租戶分區,見 7.44 多租戶平台的隔離層級〈事故報告應交代的隔離資訊〉。
  • 已移除攻擊者的立足點:清單上的主機全部重建、憑證全部撤銷(職責需要的才重發,不可匯出的簽章金鑰改為撤銷主機的簽章權限)、產物依處置範圍重建或撤下、被改寫的資料已復原,而且憑證能到達的每一個系統都檢查過,移除了攻擊者新增的帳號、金鑰與存取規則。根除完成時才成立。
  • 事故已解除:監看期的「第一波資訊已失效」與「告警期間未觸發」兩項結束條件都成立。攻擊者兩次存取的間隔長於事故能維持開啟的時間時,事故指揮可以先宣告解除,把剩下的監看轉成事故後的加強監看,並在決策紀錄與對外說明裡寫明監看持續到何時、觸發時重新開啟事故。有委託外部鑑識時,外部結論與內部一致;沒有時,對外說明裡寫明結論僅來自內部調查。

清查要對每一把憑證推出它能到達的系統與資料,憑證越多、能到達的系統越多,「已確認受影響範圍」成立得越晚;入侵確認後的頭幾天,通常只有「已切斷已知的入侵路徑」成立。對外訊息寫成「已切斷已知路徑,受影響範圍仍在確認,下一次更新時間為某時」,後續查出第二波攻擊或更大的受影響範圍時,這則訊息不會被推翻;寫成「已完全掌握」則會被推翻,而商家對之後每一則訊息的信任都會下降。已確認事實與未確認範圍分開寫的更新欄位見 8.4 事故通訊與狀態更新〈更新欄位與節奏〉,影響估算的信心標示見 8.20 Customer Impact Assessment〈通訊與補償〉。

法規或契約訂有通報時限時,要先確認誰負有通報義務。以歐盟 GDPR 為例,通報主管機關的是資料控制者,時限是可行時在知悉後 72 小時內,外洩不太可能對當事人的權利與自由造成風險時不必通報;平台處理商家的會員資料時多半是處理者,它的義務是在知悉後無不當延遲地通知商家,再由商家判斷是否通報並在時限內通報。平台與商家各是什麼角色,由法務依契約與適用法規確認。這個時限通常早於「已確認受影響範圍」成立的時間,所以第一次通報交付的是「已切斷已知的入侵路徑」這一級成立的事實,加上依清查清單推得的受影響範圍上限(可能外洩的資料類別、約略的會員數與筆數,標明是依權限推得的上限、不是實際讀取量),之後分次補報。平台通知商家的風險預警(歸屬未定時)、確認通知、結案通知(判定排除平台之後)與調查報告各要交付什麼,見 8.26 資料外洩時對商家的通知。通報的對象與負責人見 8.10 Stakeholder 通訊與外部狀態頁;通報內容要交付哪些事實(外洩的是什麼、何時、當事人要做什麼)的判斷方式,見密碼外洩那一篇的 7.37 密碼外洩之後〈通知門檻〉。

對外承諾賠償的時機

賠償承諾歸在根除這一篇,因為判定一筆損失是否源自這次外洩,要用本篇清查清單確定的外洩欄位與時間範圍。會員的訂單資料外洩之後,商家與會員常要求平台表態負責。兩種承諾在事後引發的個案爭議範圍不同:

  • 承諾一個處理程序:寫明認定受影響的標準(哪些資料、哪段時間)、受害者要提出的證據、由誰判定、判定與給付的時程。承諾處理程序在事故初期就做得出來,因為它不需要知道最終的受影響範圍。
  • 承諾一個結果(「所有損失由平台負責」):在認定標準與因果判斷方式還沒定出來時做出,之後每一個個案都要回頭爭執「這筆損失算不算這次外洩造成的」。

因果判斷是這類事故最難的環節。外洩的訂單資料被拿去做詐騙電話時,會員的損失與這次外洩之間的連結要靠證據建立:詐騙者引用的資訊(訂單編號、購買品項、金額)是否只存在於外洩的資料庫裡、會員的訂單是否在外洩的欄位與時段內。同一個人的資料也可能在其他外洩事件裡流出,沒有判定方式時,平台無法證明損失與這次外洩無關,會員也無法證明損失來自這次外洩。所以判定方式要先於結果承諾,而判定方式本身有依賴:哪些詐騙內容可以對回這次外洩,是用外洩的欄位與時間範圍定義的,這兩項只能從清查清單取得;給付條件又以這個對回方式為前提。清查清單完成之前公告的給付條件,裡面沒有可以判定的依據。

另一種做法是與個人損失脫鉤的固定補償(給受影響範圍內的每一位會員同一筆金額或服務):它只需要判定「是否在受影響範圍內」,不需要判定每一筆損失的成因,所以在「已確認受影響範圍」成立之後就能承諾。承諾的文字要寫明適用對象依已確認的範圍認定,無法確認的那一段與後續擴大的範圍套用同一套規則。固定補償直接給會員還是經由商家給,以及它與後續個別損失求償的關係,由平台與商家之間的契約與適用法規決定,要由法務確認。

承諾的範圍也要對得上平台與商家之間的契約:平台向商家收的是服務費,會員是平台的間接使用者,賠償的對象、上限與管道要回頭查契約與適用法規怎麼規定。所以事故初期由法務與客戶溝通負責人共同決定承諾的文字,技術團隊或公關不單方面做出與契約不一致的承諾。補償政策要事前定義的理由與補償種類見 8.10 Stakeholder 通訊與外部狀態頁,影響估算如何轉成補償的輸入見 8.20 Customer Impact Assessment。賠償的處理程序在給商家的確認通知裡要交代哪些事實,見 8.26 資料外洩時對商家的通知〈確認通知與結案通知〉。

常見風險邊界:只靠日誌的清單、清理代替重建、可能被改過的重建來源、在舊主機輪替、未處置的產物與資料、過早的宣告與承諾

  • 清查清單只列「日誌顯示被存取」的系統,或用被入侵主機上的日誌判讀起點:讀取設定檔與環境變數多半不留紀錄,主機上的日誌也可能被改過,清單會漏掉最重要的憑證。
  • 清理被入侵的主機後繼續使用:無法證明沒有遺漏的後門。
  • 用入侵期間可能被改過的設定或映像重建:新主機從一開始就帶著後門。
  • 在舊主機或沒檢查過的保管位置寫入新憑證,或只撤銷長期金鑰而沒有撤銷已換出的 session:新憑證或舊 session 留在攻擊者手中。
  • 入侵期間建置的產物沒有重建或撤下、被改寫的資料沒有比對復原:攻擊者植入的程式與帳號留在正式環境、資料庫與會員的裝置裡。
  • 止血完成就對外宣告完全掌握:第二波攻擊或更大的受影響範圍推翻宣告。
  • 賠償承諾先於認定標準:後續每個個案都進入爭議。

延伸閱讀:事前隔離、密碼外洩、決策紀錄與事後回寫