資訊處理安全確保支援士(情報処理安全確保支援士) 2024年春季(令和6年) 下午問1解說 ── JWT的alg=none與API授權、WAF的暫定對策
· Go Komura · 資訊處理安全確保支援士, 登錄資訊處理安全確保支援士, API, API安全, JWT, 認證, 授權, WAF, Log4Shell, 資訊安全, 漏洞, IPA
「因為驗證了JWT的簽章,所以使用者ID值得信任」
這種說法只對了一半。
資訊處理安全確保支援士考試 令和6年度(2024年度)春季 下午 問1,以智慧型手機呼叫的API為題材1。認證成功後會發出JWT,之後呼叫端會附上這個JWT,呼叫使用者資訊的取得・更新API。乍看之下,是很常見的架構。
然而,在診斷中發現了以下四項問題。
- 將JWT標頭的
alg改成none,未簽章的JWT就能通過 - 保持使用正確的JWT,只把
mid改成其他使用者ID,就能取得・更新他人的資訊 - 加上規格外的
status=paid,免費使用者就會變成付費使用者 - 對電子郵件送達的4位數認證碼,可以不受限制地暴力破解
這四項看起來都是「認證周邊的漏洞」,但成因並不相同。權杖的完整性、物件層級授權、屬性層級授權、嘗試次數限制——這幾個各自獨立的邊界都被突破了。
後半還會加入另一個論點。一套廣泛使用的開放原始碼函式庫,被公開了一項可利用JNDI Lookup從外部執行程式碼的重大漏洞。當時既沒有修正版,也還沒有完整的WAF規則。在這段空窗期間,題目要問的是:該如何確認影響範圍、WAF該檢查哪裡、以及為什麼一開始要選「偵測」而不是「阻斷」。
本文將以官方公布的解答範例2與評分講評3為基礎,不只整理各設問的答案,還會進一步整理為什麼答案會是這樣,以及在實務上該把設計做到多嚴謹。
flowchart TB
accTitle: 問題全貌
accDescr: 顯示認證碼、JWT、API授權、函式庫漏洞各階段被突破的信任邊界
user[使用者應用程式]
auth[4位數認證碼]
jwt[發出JWT]
api[使用者API]
log[記錄日誌]
vuln[有漏洞的函式庫]
ext[外部程式碼執行]
user --> auth
auth -->|無嘗試次數限制| jwt
jwt -->|允許alg=none| api
api -->|信任mid| db1[取得/更新他人資料]
api -->|status=paid| db2[變更付費狀態]
api --> log
log --> vuln
vuln -->|JNDI/LDAP/HTTP| ext
圖1:問題全貌。各階段各自被突破了不同的信任邊界。
1. 先講結論
- RESTful API不具工作階段的特性稱為無狀態。但這不代表伺服器完全不保存資料庫或使用者狀態
- 4位數認證碼共有1萬種。若每秒可嘗試10次,平均500秒就能成功。由於比有效期間10分鐘還短,光靠失效時間無法防範
- 對
alg=none的最低限度對策,是確認JWT標頭的alg不是NONE。不過在實務上,應在伺服器端固定允許使用的演算法 - 即使JWT正確,也不能信任請求中的
mid。應核對JWT內的使用者ID與mid是否一致,或是更安全地不接收mid、改由JWT決定目標對象 - 新增
status=paid,是把規格外的屬性也綁定到內部物件上的Mass Assignment問題。應把更新用DTO做成許可清單,不讓使用者變更付費狀態 - 暴力破解對策的解答是,連續失敗次數超過門檻值就鎖定帳號的處理。實務上還應搭配階段性延遲與依來源做的控制
- 在確認新的重大漏洞影響範圍時,不使用破壞性命令,而是靠記錄是否有人存取測試伺服器的
index.html,來確認外部程式碼執行是否成立 - 由於攻擊字串放在HTTP標頭中,WAF的檢查對象是
Header。因應大小寫互換的正規表示式,例如可用\W[jJ][nN][dD][iI]\W - 一開始把WAF設為「偵測」的優點是,能避免因誤判而中斷業務通訊。收到警示後查明是否為攻擊,調整完成後再轉為阻斷
- WAF是暫定對策,根本對策則是把受影響的函式庫更新到修正版
2. 題材與設問對應
題目的背景是正準備新推出健康照護服務的G公司。使用者透過智慧型手機應用程式輸入飲食、體重等資料,取得健康風險判定與飲食菜單建議。系統建置在雲端上,結合了API閘道、事件驅動處理、代管資料庫。
題目原文中的產品名稱與服務名稱都經過抽象化處理。本文同樣不轉載IPA的圖表與文字,只改寫理解設問所需的結構。
| 設問 | 主題 | 本文對應章節 |
|---|---|---|
| 設問1 | RESTful API的性質 | 第4章 |
| 設問2(1) | 4位數認證碼的暴力破解時間 | 第5章 |
| 設問2(2) | JWT的alg=none |
第6章 |
| 設問2(3) | 利用mid存取他人資料 |
第7章 |
| 設問2(4) | 接受規格外status的缺失 |
第8章 |
| 設問2(5) | 暴力破解對策 | 第9章 |
| 設問3(1) | 以安全的方式確認漏洞是否存在 | 第11章 |
| 設問3(2)(3) | WAF的檢查位置與正規表示式 | 第12章 |
| 設問3(4) | 偵測模式的優點與運用 | 第13章 |
評分講評指出,整體的正確率算是中等水準。另一方面,設問2(2)的JWT竄改對策,以及設問3(1)驗證用伺服器所需機制,則被指出正確率偏低。這兩題光是知道專有名詞並不能作答,必須追蹤攻擊者變更了哪個值、這個值流向了哪個處理、又在何處被錯誤地信任了。
3. 這道題目不只是「認證的問題」
把整個問題依信任邊界排列,會呈現如下的結果。
[使用者ID・密碼]
|
v
[確認4位數認證碼] ---- 無嘗試次數限制 ----> 暴力破解
|
v
[發出JWT]
|
v
[JWT函式庫] ------- 允許alg=none ------> 竄改使用者ID
|
v
[使用者API]
| |
| +-- 整包傳遞status ----> 屬性層級授權缺失
|
+-- 信任mid ------------------------> 物件層級授權缺失
[將外部輸入記錄到日誌]
|
v
[有漏洞的函式庫] ---- JNDI/LDAP/HTTP ------> 外部程式碼執行
這裡最重要的是以下的區別。
| 確認項目 | 要問的問題 | 本題中被突破的例子 |
|---|---|---|
| 認證 | 你是誰 | 4位數認證碼的暴力破解 |
| 權杖驗證 | 該身分資訊是否遭到竄改 | alg=none |
| 物件層級授權 | 是否可以存取該使用者的資料 | 替換mid |
| 屬性層級授權 | 是否可以變更該項目 | status=paid |
| 輸入到執行的邊界 | 外部輸入是否會被解讀成命令 | JNDI Lookup |
前一項確認成功,不代表可以省略下一項確認。 就算是持有正確JWT的使用者,也不代表可以讀取他人的資料。就算是能更新自己資料的使用者,也不代表可以連付費狀態都一併變更。
只要能做出這樣的分層,各設問的答案就不再只是死記硬背。
flowchart LR
accTitle: 認證與授權的差異
accDescr: 認證用來確認主體身分,授權用來確認該主體被允許執行的操作
auth[認證<br/>是誰]
authz[授權<br/>可以做什麼]
auth --> authz
圖2:認證與授權的差異。認證在先,授權則是另一項獨立的確認。
4. 設問1 ── 什麼是無狀態(Stateless)
設問1問的是RESTful API設計原則之一,也就是不進行工作階段管理的特性。
解答是 無狀態(Stateless)。
所謂無狀態,是指伺服器即使不記得上一個請求的對話狀態,每個請求本身也具備處理所需的全部資訊。在本題中,智慧型手機應用程式會在每個請求的Authorization標頭中附上JWT。伺服器驗證這個JWT,藉此識別該請求的使用者。
容易產生的誤解,是把無狀態理解成「伺服器完全不保存任何狀態」。實際上,以下這些狀態通常都會保存。
- 儲存使用者資訊與健康資料的資料庫
- 付費狀態
- 認證碼的值、有效期限、失敗次數
- JWT的簽章金鑰
- 若採用失效清單的設計,則包含該失效資訊
- 日誌與稽核記錄
不保存的是,不把「僅為了延續對話而存在的伺服器端工作階段狀態」當作每次API呼叫的前提。
此外,無狀態並不會自動提升安全性。每次都傳送JWT確實有助於水平擴展,但只要JWT的驗證出錯,錯誤也會平均擴散到所有節點。架構上的特性,與安全性上的正確與否,是兩回事。
5. 設問2(1) ── 4位數認證碼平均500秒就會被猜中
認證API只要使用者ID與密碼相符,就會將4位數的數字寄送到電子郵件。之後,只要使用者ID與4位數認證碼一致,就會發出JWT。認證碼從產生起10分鐘內有效。
在診斷中,每秒可以嘗試10次。題目要求的是平均需要幾秒才能被突破。
計算方式是「候選數的一半」
4位數的數字,含開頭為0的情況在內,共有以下1萬種。
0000, 0001, 0002, ... , 9999
若正確答案是均勻隨機選出,依序不重複嘗試的攻擊者,平均要花候選數的一半次數才能命中正確答案。
平均嘗試次數 = 10,000 ÷ 2 = 5,000次
平均所需時間 = 5,000 ÷ 10次/秒 = 500秒
因此,空格b的答案是 500。
最壞情況下需要1,000秒,但題目問的是平均值。而認證碼的有效期間是600秒,比平均突破時間500秒還長,這就是被判定為「很有可能被突破」的原因。
flowchart LR
accTitle: 4位數認證碼的時間感受
accDescr: 對1萬種候選以每秒10次的速度嘗試,平均5,000次、500秒就會命中,短於有效期間600秒
A[候選數 10,000種] -->|平均 10,000 / 2 = 5,000次| B[平均突破時間 500秒]
C[有效期間 600秒] -->|500秒 小於 600秒| D[有效期間內可被突破]
圖9:4位數認證碼的時間感受。平均只需嘗試候選數的一半,就會在有效期間內命中。
光縮短失效時間,若候選數量太少仍然沒有意義
認證碼的強度,並非只由位數或只由有效期間決定。
有效期間內可嘗試的次數
= 每秒可嘗試次數 × 有效期間
= 10 × 600
= 6,000次
若依序嘗試不重複的數值,就能在有效期間內驗證1萬種組合中的60%。就算設有失效時間,只要沒有限制嘗試次數,防護就不夠充分。
現行的NIST SP 800-63B要求頻外驗證(out-of-band authentication)所使用的短期密碼至少要有6位數,若熵值低於64位元則必須有嘗試次數限制。此外也要求不要用電子郵件做為頻外驗證的管道4。考試是在題目給定的4位數・郵件寄送這項規格前提下作答,但在實務上進行新設計時,連這個前提本身都應該重新檢討。
6. 設問2(2) ── alg=none是「讓攻擊者自行選擇驗證方式」的問題
題目中的JWT由標頭、酬載、簽章三個部分組成。
base64url(header).base64url(payload).base64url(signature)
標頭中記錄了簽章所使用的演算法RS256。酬載中則放有使用者ID、發行時間、有效期限等資訊。
診斷人員變更了以下兩處。
- 把標頭的
alg從RS256改成NONE - 把酬載中的使用者ID改成另一名使用者
送出這個JWT後,驗證竟然成功,因而能冒充他人。
flowchart LR
accTitle: JWT alg=none 攻擊流程
accDescr: 從正確的JWT把alg改成none,並改寫使用者ID後成功通過驗證的流程
A[正確的JWT<br/>alg=RS256<br/>user=user01] -->|把標頭的alg改成none| B[遭竄改的JWT<br/>alg=none<br/>user=user02]
B -->|略過簽章驗證| C[伺服器<br/>接受為user02]
圖3:JWT alg=none 攻擊流程。攻擊者自行選擇了驗證演算法。
none並不是拼字錯誤
RFC 7519中定義了alg為none、既無簽章也無加密的「Unsecured JWT」5。因此,none這個值在規格上並非完全不存在。
問題在於,原本應該只接受有簽章JWT的API,卻接受了攻擊者指定的none。
若用概念性的方式描述這段有漏洞的處理,會是下面這樣。
1. 讀取JWT標頭
2. 依標頭中記載的alg選擇驗證方式
3. 若alg為none,就不進行簽章驗證
4. 信任酬載中的使用者ID
這等於是讓攻擊者能透過自己能控制的輸入,來選擇安全強度本身。
考試的解答
設問要求分別以20字以內回答,修正後的函式庫Q「針對哪個資料、進行什麼樣的驗證」。
解答範例如下。
| 項目 | 解答要點 |
|---|---|
| 驗證對象的資料 | JWT標頭中alg所指定的值 |
| 驗證內容 | 驗證其值不是NONE |
就題目原文中漏洞的直接修正而言,這樣的答案是正確的。
實務上不能只做到「不是NONE就好」
這裡必須把考試的解答與實務上建議的做法區分開來。
RFC 8725要求JWT函式庫要讓呼叫端指定一組允許使用的演算法集合,並且不得使用集合以外的演算法6。也就是以下這種思維方式。
不好的思維方式:
只要 token.header.alg != "none" 就接受
好的思維方式:
只有包含在 serverConfig.allowedAlgorithms 中時才接受
例如: allowedAlgorithms = ["RS256"]
就算只拒絕none,仍可能殘留其他較弱的演算法,或是把公開金鑰方式與共用金鑰方式搞混的演算法混淆問題。原則應該是不要一直用否定條件去增加拒絕清單,而是把允許的條件收窄並固定下來。
JWT的驗證不只是演算法,還應視用途至少確認以下項目。
| 項目 | 確認內容 |
|---|---|
| 簽章 | 是否能用預期的金鑰與演算法完成驗證 |
iss |
是否為信任的發行者 |
aud |
是否為針對這個API所發出的權杖 |
exp |
是否在有效期限內 |
nbf |
是否還沒到可使用的起始時間 |
sub或使用者ID |
是否為應用程式上有效的主體 |
| 權杖種類 | 是否把ID權杖與存取權杖等搞混 |
本題中酬載的鍵值名稱是user,但實務上應使用標準的sub,或明確定義自訂宣告(claim)的意義。
flowchart TB
accTitle: 安全的JWT驗證與危險的JWT驗證
accDescr: 危險的驗證方式依賴alg,安全的驗證方式則使用伺服器端的許可清單
subgraph "危險的驗證"
D1[讀取JWT標頭的alg]
D2[alg為none就接受]
D1 --> D2
end
subgraph "安全的驗證"
S1[伺服器設定的許可演算法<br/>例如 RS256]
S2[確認JWT標頭的alg<br/>是否包含在許可清單中]
S3[驗證簽章・iss・aud・exp]
S1 --> S2 --> S3
end
圖4:安全的驗證與危險的驗證。實務上應把允許的演算法收窄並固定下來。
Base64url不是加密
還有一個JWT常見的誤解。標頭與酬載雖然是以base64url編碼表示,但這並不是加密,任何人都可以解碼並讀取內容。
簽章所保證的,僅限於「在能正確驗證通過的前提下,內容自發行後未遭竄改」。這並不代表可以把想要保密的個人資訊放進有簽章的JWT酬載中。
7. 設問2(3) ── 即使JWT正確,只要改變mid就能讀到他人資料
接下來是一種不竄改JWT本身的攻擊。
使用者API會透過GET或PUT接收名為mid的使用者ID。共用模組P會從資料庫中取得・更新與該mid綁定的使用者資訊。
攻擊的架構很單純。
JWT的使用者ID: user01 ← 簽章正確的JWT
請求中的mid: user02 ← 攻擊者變更後的值
由於JWT的簽章正確,認證會成功。然而,API卻直接信任mid=user02,把user02的資訊回傳出去。
這正是OWASP API Security Top 10 2023中所說的 Broken Object Level Authorization(BOLA,物件層級授權缺失) 的典型案例。當使用者以自行指定的物件ID來存取資料時,每一次都必須確認是否具備該物件的授權7。
flowchart LR
accTitle: BOLA攻擊
accDescr: 使用正確的JWT,同時把請求中的mid改成另一個使用者ID
A[攻擊者] -->|JWT: user01<br/>mid: user02| B[使用者API]
B -->|信任mid| C[從資料庫回傳user02的資訊]
圖5:BOLA攻擊。認證通過了,卻沒有確認授權。
設問的解答
表5中的底線②,要求以40字以內回答應在共用模組P的呼叫處理中新增的處理內容。
解答範例如下。
驗證JWT中所含使用者ID是否與mid的值一致的處理
在共用模組P中進行驗證的好處是,GET與PUT兩者、以及日後其他呼叫P的API,都能輕鬆套用相同的授權機制。若把相同的比對處理複製到各個畫面或端點,總會有某處遺漏。
更安全的設計是不接收mid
如果API只需要取得・更新使用者自己的資訊,其實不需要從用戶端接收使用者ID。
GET /users/me
Authorization: Bearer <JWT>
在伺服器端,則從驗證過的JWT中取出主體。
principal = validateJwt(request.authorization)
userId = principal.subject
return repository.getUser(userId)
更新處理也是一樣。
principal = validateJwt(request.authorization)
input = validateProfileUpdate(request.body)
repository.updateProfile(
userId = principal.subject,
name = input.name,
age = input.age
)
比對處理只要寫了就能防護。但如果採用不從外部接收目標ID的設計,就能從根本上減少「忘了寫比對處理」這類臭蟲本身的發生機率。
若管理者需要操作他人的使用者資訊,則應如下方式區分開來。
PUT /users/me 一般使用者用
PUT /admin/users/{userId} 管理者用
管理者用的端點應要求不同的權限、稽核日誌,必要時還要求重新認證。相較於「在一般使用者API上,只為管理者情境加一段例外處理」,這種做法能讓授權原則的邊界更清楚可見。
flowchart LR
accTitle: BOLA的防範方式
accDescr: 不使用請求中的mid,改由JWT的主體決定或核對目標對象
A[使用者] -->|GET /users/me + JWT| B[API]
B -->|取得JWT的sub| C{若有mid<br/>是否與sub一致}
C -->|一致| D[回傳自己的資料]
C -->|不一致| E[拒絕並回傳403]
B -->|沒有mid| F[以JWT的sub查詢資料庫]
圖6:BOLA的防範方式。不接收mid,或是與JWT的主體核對。
用一句話區分認證與授權
無論是考試還是實務,以下的說法都很有幫助。
- 認證: 是誰
- 授權: 這個人可以做什麼
JWT的簽章驗證成功,只代表「可以信任這個權杖所代表的主體」而已。「這個主體是否可以讀取user02」,必須另外確認。
8. 設問2(4) ── status=paid是屬性層級的授權缺失
使用者API的規格中,定義了以下這些做為更新用的參數。
mid 使用者ID
name 姓名
age 年齡
然而,診斷人員新增了規格中沒有的以下數值。
status=paid
結果,免費使用者的狀態就變成了付費使用者。
依題目原文所述,服務L並未驗證收到的參數,而是把全部參數都直接傳給共用模組P。P的設計是可以直接以此更新資料庫。
空格c的答案是 共用模組P。
flowchart TB
accTitle: Mass Assignment
accDescr: 新增了規格外的status=paid,並整個反映到內部物件上
A[API規格<br/>mid / name / age] -->|攻擊者新增status=paid| B[請求主體]
B -->|自動綁定| C[共用模組P]
C -->|寫入資料庫| D[付費狀態變更為paid]
圖7:Mass Assignment。規格外的屬性被整個反映到內部物件上。
與BOLA的差異
前一章的mid替換,與這次的status新增看似相似,但要守護的粒度不同。
| 漏洞 | 攻擊者變更的項目 | 原本應確認的事項 |
|---|---|---|
替換mid |
目標物件 | 這名使用者是否可以存取這筆使用者紀錄 |
新增status |
物件內的屬性 | 這名使用者是否可以變更這個項目 |
在OWASP API Security Top 10 2023中,後者被歸類為 Broken Object Property Level Authorization(物件屬性層級授權缺失),先前的Mass Assignment也被納入這項分類中8。
「把JSON原封不動放進實體」很危險
有漏洞的實作,概念上大致如下。
entity = repository.find(body.mid)
bindAllProperties(entity, body)
repository.save(entity)
就算畫面上只有name與age的輸入欄位,攻擊者仍然可以直接自行組出HTTP請求。UI上沒有的項目,並不是安全邊界。
安全的實作,會明確標示出可更新的項目。
input = parseExactSchema(body, fields = ["name", "age"])
entity = repository.find(authenticatedUserId)
entity.name = input.name
entity.age = input.age
repository.save(entity)
這裡有兩個重點。
- 更新用的輸入型別中,只放入使用者可以變更的項目
- 對於規格外的未知項目,不要選擇忽略,盡量以錯誤方式予以拒絕
若默默忽略未知項目,雖然能掩蓋攻擊失敗的痕跡,卻也會漏看用戶端的實作錯誤或攻擊的徵兆。若沒有相容性上的理由,採用嚴格結構(schema)予以拒絕,反而更方便日後調查。
flowchart TB
accTitle: 屬性層級授權
accDescr: 更新用DTO只保留許可清單,未知的屬性一律拒絕
subgraph "更新用DTO(許可清單)"
D1["name"]
D2["age"]
end
A[請求主體] -->|結構驗證| B{是否僅包含<br/>許可的項目}
B -->|是| C[更新實體的name/age]
B -->|否| D[回傳錯誤]
E[支付服務<br/>驗證過的通知] -->|專用路徑| F[更新status=paid]
圖8:屬性層級授權。以許可清單限制可更新的項目,付費狀態則透過另一條路徑變更。
status只能由支付結果來變更
status=paid並不是使用者個人資料的一部分,而是從「伺服器端已確認支付成功」這項事實所導出的狀態。
使用者的個人資料更新
-> 只能變更name / age
來自支付服務的驗證過通知
-> 核對paymentId
-> 防止重複處理
-> 把status變更為paid
就算儲存在同一個資料庫欄位中,能變更它的權限與路徑仍然是分開的。若把內部實體直接拿來當作外部API的輸入型別,這條邊界就會消失。
9. 設問2(5) ── 暴力破解對策要把失敗次數當成狀態來保存
針對4位數認證碼的暴力破解,要以30字以內回答表5空格d應填入的處理。門檻值為10。
解答範例如下。
連續失敗次數超過門檻值就鎖定帳號的處理
這一點與設問1的無狀態並不矛盾。「不把API呼叫的對話狀態當成伺服器工作階段來保存」,與「把安全性判斷所需的失敗次數持久化保存」是兩回事。
flowchart LR
accTitle: 有無嘗試次數限制的差異
accDescr: 沒有限制的話平均500秒就會被突破,加上失敗次數限制可以壓低攻擊速度
subgraph "無限制"
A1[每秒嘗試10次] -->|約500秒| B1[認證成功]
end
subgraph "有限制"
A2[失敗10次就鎖定] -->|攻擊速度大幅下降| B2[帳號遭鎖定]
C2[階段性延遲] --> B2
end
圖10:有無次數限制。失敗次數限制能在實務上有效阻止暴力破解。
實務上不能只靠「永久鎖定」
帳號單位的次數限制雖然必要,但如果攻擊者知道他人的使用者ID,就能故意連續失敗10次,把正常使用者鎖在外面。因此,實務上應結合以下做法。
| 控制項目 | 作用 |
|---|---|
| 帳號單位的失敗次數 | 阻止對單一帳號的暴力破解 |
| 階段性等待時間 | 容忍正常使用者的輸入失誤,同時拖慢攻擊速度 |
| 來源IP・裝置・ASN等控制 | 抑制對大量帳號各嘗試少數幾次的攻擊 |
| 風險基礎判斷 | 對異於平常的地區・裝置・速度加強限制 |
| 通知使用者 | 讓使用者能察覺攻擊或誤操作 |
| 安全的復原程序 | 避免解鎖管道本身成為攻擊路徑 |
此外,重新寄送認證碼時,不應把失敗次數歸零。因為攻擊者只要每次呼叫重寄API,就能讓嘗試額度重新恢復。現行的NIST SP 800-63B也要求,即使產生了新的認證密碼,也不應重設失敗次數4。
讓認證碼只能使用一次
題目原文以有效期限為主軸,但實務上還需要以下這些做法。
- 驗證成功的認證碼要立即失效
- 拒絕重複使用同一組認證碼
- 不把認證碼本身留在日誌中
- 讓回應內容無法從認證碼核對的成敗推斷出使用者是否存在
- 認證碼寄送API也要設有次數限制
既然使用的是位數較短的密碼,就不能只靠隨機產生來確保安全性。
flowchart TB
accTitle: 認證碼對策
accDescr: 除了位數與失效時間之外,再加上嘗試次數限制、拒絕重複使用、通知等機制加以防護
A[認證碼] --> B[增加位數]
A --> C[縮短有效期限]
A --> D[嘗試次數限制]
A --> E[成功後立即失效]
A --> F[重寄不重設失敗次數]
A --> G[不把認證碼留在日誌中]
A --> H[依來源做控制]
圖11:認證碼對策。除了位數與失效時間,還要結合嘗試控制與營運機制。
10. 用一張表區分設問2的四個問題
以下依攻擊者所控制的值,整理設問2中容易混淆的論點。
| 攻擊 | 攻擊者變更的值 | 不該信任的地方 | 根本對策 |
|---|---|---|---|
| JWT竄改 | JWT標頭的alg、酬載的使用者ID |
權杖自行申報的驗證演算法 | 在伺服器端固定允許使用的演算法 |
| 取得他人資訊 | 請求中的mid |
用戶端指定的目標ID | 與JWT的主體核對,或由JWT決定目標ID |
| 變更為付費使用者 | 規格外的status |
自動綁定的所有屬性 | 把可更新的屬性做成許可清單 |
| 4位數認證碼被突破 | otp的候選值 |
無限制的認證嘗試 | 加入失敗次數限制、延遲、風險判斷 |
重要的是,不要用「驗證輸入值」一句話把這些全部混為一談。
alg關係到加密處理的政策mid關係到物件層級授權status關係到屬性層級授權otp關係到對線上猜測的抵抗力
即使同樣出現在一個HTTP請求中,要守護的理由並不相同。
11. 設問3(1) ── 在不造成破壞的前提下確認外部程式碼執行
服務上線後,一套廣泛使用的開放原始碼函式庫H被公開了一項重大漏洞V。題目原文中的流程如下。
- 攻擊者把含有JNDI Lookup的字串放進HTTP標頭中送出
- 目標伺服器把這個值輸出到日誌
- 有漏洞的函式庫解析JNDI Lookup,向攻擊用的LDAP伺服器發出查詢
- LDAP的回應中回傳攻擊用HTTP伺服器的URL
- 目標伺服器取得類別檔案,並執行命令
這可以視為隱去了具體產品名稱的 Log4Shell(CVE-2021-44228)型攻擊。Apache的官方說明中也提到,若攻擊者能控制日誌訊息或參數,就能利用這項漏洞執行從LDAP伺服器載入的任意程式碼9。
flowchart LR
accTitle: Log4Shell型漏洞確認流程
accDescr: 以無害的回呼確認從JNDI到外部程式碼執行的連鎖是否成立
A[攻擊者] -->|在x-api-version中<br/>注入jndi:ldap://...| B[有漏洞的伺服器]
B --> C[日誌處理]
C -->|JNDI Lookup| D[惡意LDAP伺服器]
D -->|回應HTTP URL| E[惡意HTTP伺服器<br/>index.html]
E -->|記錄GET請求| F[測試伺服器<br/>存取日誌]
F -->|確認到達| G[確認漏洞]
圖12:Log4Shell型漏洞確認流程。不使用破壞性命令,而是靠HTTP存取記錄來確認是否到達。
驗證程式碼只會產生無害的HTTP存取
G公司執行不會對系統造成影響的驗證程式碼,確認是否能從外部利用漏洞V。驗證程式碼所執行的命令,僅僅是取得測試伺服器的index.html而已。
設問3(1)問的是,要在測試伺服器上實作什麼,才能確認命令已經被執行。
解答範例如下。
記錄並確認是否有人存取測試伺服器index.html的機制
只要Web伺服器的存取日誌中留下來自目標伺服器的GET紀錄,至少就能確認以下這一連串連鎖成立了。
外部HTTP請求
-> 日誌處理
-> JNDI Lookup
-> LDAP回應
-> 取得類別檔案
-> 執行驗證命令
-> 存取測試伺服器
為什麼「在畫面上顯示文字」還不夠
攻擊目標是伺服器。使用者瀏覽器畫面不一定會出現變化。此外,即使漏洞確實存在,途中的對外連線也可能被防火牆擋下。
只要在測試伺服器端記錄存取情形,就能成為「目標伺服器已對外連線到達」這項可觀測的證據。
在實務上進行同類驗證時,務必遵守以下事項。
- 取得目標系統擁有者的明確同意
- 採用不會影響正式環境、或影響程度可接受的驗證方式
- 不使用寫入・刪除・變更設定等破壞性命令
- 驗證用的網域與伺服器由自己公司管理
- 記錄驗證時間、來源、目標、預期的回呼
- 驗證結束後撤除臨時建立的LDAP・HTTP伺服器與憑證
「確認任意程式碼執行(是否可行)」與「實際執行任意危險的程式碼」並不相同。應以能達成目的的最小副作用來進行。
12. 設問3(2)(3) ── WAF要檢查的是HTTP標頭
服務N的WAF,可以從GET、POST、PUT、ANY、Header、COOKIE、Multipart之中選擇檢查對象。
攻擊程式碼放在名為x-api-version的HTTP標頭值中。因此,表6的空格e與f,答案都是 Header。
直接把題目原文中寫明的位置,對應到WAF的檢查對象
這一題與其說是考一般知識,不如說是考能否讀懂題目原文中的資料流程。
攻擊字串放置的位置:
x-api-version標頭
|
v
WAF的檢查對象:
Header
既不是GET參數,也不是POST主體。不要看著WAF的功能清單,憑「感覺像攻擊所以選ANY」來作答,而要回答題目原文中攻擊者放入數值的實際位置。
因應大小寫互換
最初的方案,概念上是以下這樣的規則。
Header \Wjndi\W 阻斷
Header \Wldap\W 阻斷
但是,像jNdI這樣調換大小寫,就能規避只比對小寫的簡單模式。
設問3(3)的解答範例,是以下其中一種。
\W[jJ][nN][dD][iI]\W
\W(j|J)(n|N)(d|D)(i|I)\W
在題目冊子中,反斜線在日文環境的字型下有時會顯示成日圓符號,但就正規表示式而言指的是\W。\W比對的是除了英數字與底線以外的字元。在JNDI Lookup的語法中,jndi的前後會出現${或:等非單詞字元,所以連同這些一併納入比對範圍。
用同樣的思路,ldap那一側也可以做成忽略大小寫的形式。
\W[lL][dD][aA][pP]\W
不要把這條正規表示式當成「完整的Log4Shell對策」
考試問的是,針對題目原文中出現的規避手法,寫出對應的正規表示式。但在實際攻擊中,可能存在字串分割、其他Lookup、編碼、其他通訊協定等變形手法,光靠特徵碼很難完全涵蓋。
因此,在實務上的定位如下。
- 用WAF暫時擋下目前已知的攻擊模式
- 調查是否真的含有受影響的函式庫
- 限制對外的LDAP・RMI・不必要的HTTP通訊
- 更新到修正版
- 更新後仍要確認日誌,調查是否已遭入侵
WAF是在修正版推出之前,用來爭取時間的一層防護。
flowchart TB
accTitle: WAF的定位
accDescr: WAF是暫定緩解的層級,根本對策是更新到函式庫的修正版
A[公開重大漏洞] --> B[確認影響]
B --> C[暫定緩解]
C -->|WAF規則<br/>偵測/阻斷| D[暫時阻止攻擊模式]
C -->|限制對外通訊| E[封鎖濫用路徑]
D --> F[更新到修正版函式庫]
E --> F
F --> G[事後確認與再發防止]
圖13:WAF的定位。WAF是在修正版推出前爭取時間的手段,根本對策仍是更新。
13. 設問3(4) ── 一開始使用「偵測」的理由
關於變更後的WAF規則,身為登錄資訊處理安全確保支援士的Z先生建議,在正式上線運作後的一段期間內,動作模式應設為「偵測」而不是「阻斷」。
設問要求分別以25字以內回答,選擇偵測模式的優點,以及為了將損害降到最低所應執行的內容。
解答範例如下。
| 項目 | 解答要點 |
|---|---|
| 優點 | 可以避免因誤判而遭到阻斷 |
| 應執行的內容 | 收到警示後,查明是否真的是攻擊 |
偵測模式不是「什麼都不做的模式」
在偵測模式下,符合規則的通訊仍會放行,但會記錄到日誌並發出警示。即使正常的API呼叫中偶然出現jndi或ldap這樣的字串,也不會立刻中斷業務。
相對地,營運方需要做到以下事項。
收到警示
|
v
確認目標請求
|
+-- 正常通訊 -> 收窄規則、檢討例外條件
|
+-- 攻擊 -> 隔離目標、保全日誌、調查影響、轉為阻斷
如果沒有人查看警示,偵測模式就不會有任何防禦效果。偵測必須與觀察後再判斷的營運方式搭配成一組才有意義。
從偵測轉為阻斷的流程
一般的導入步驟如下。
- 以偵測模式套用到實際流量上
- 把誤判與正確偵測分類
- 調整目標標頭、路徑、API、字元邊界等
- 確認對正常通訊的影響在可接受範圍內
- 轉為阻斷模式
- 監控阻斷件數與業務影響
不過,這是平時的原則。若漏洞十分嚴重、正遭到實際濫用,又沒有替代手段時,也可能判斷入侵造成的損害會大於誤判導致的停擺,因而從一開始就選擇阻斷。在考試所設定的情境中,則是為了確認服務能否維持以往的可用性,才先選擇偵測模式。
flowchart LR
accTitle: WAF從偵測轉為阻斷
accDescr: 在偵測模式下觀察警示,調整誤判之後再轉移到阻斷模式
A[偵測模式] -->|實際流量| B[產生警示]
B --> C{是攻擊<br/>還是誤判}
C -->|誤判| D[調整規則]
D --> A
C -->|攻擊| E[轉為阻斷模式]
E --> F[監控阻斷件數與業務影響]
圖14:從偵測轉為阻斷。先觀察・調整,確認影響在可接受範圍後再轉為阻斷。
14. WAF是暫定對策,更新才是根本對策
依題目原文所述,函式庫H的官方網站當時既沒有修正版,也沒有暫定對策,雲端業者要提供涵蓋範圍完整的WAF規則,最長也要72小時。因此G公司自行確認影響範圍,先針對已知的攻擊模式做暫時性的防護。
這樣的順序,正是事故應變的基本型態。
| 階段 | 目的 | 本題中的對應做法 |
|---|---|---|
| 確認影響 | 判斷自家公司是否真的處於危險之中 | 用無害的回呼確認是否能從外部濫用 |
| 暫定緩解 | 為修正爭取時間 | WAF規則、偵測・阻斷、限制對外通訊 |
| 根本修正 | 消除有漏洞的原因 | 更新到修正版函式庫 |
| 事後確認 | 調查是否已經遭到濫用 | 調查WAF・應用程式・DNS・代理伺服器等日誌 |
| 再發防止 | 加快下一次的判斷速度 | 盤點相依關係、SBOM、更新程序、聯絡管道 |
「不知道自己有沒有用到」是最大的延遲來源
依題目原文所述,即使G公司向F公司詢問是否有使用函式庫H,由於需要詳細的組態分析,回覆也要花上不少時間。
在實務上,若是等到重大漏洞公布之後才開始尋找JAR檔案,應變就會來不及。至少應在平時就準備好以下事項。
- 直接相依與遞移相依的清單
- 發布物中實際包含的元件與版本
- 部署到哪些服務・容器・裝置上
- 更新相依函式庫並重新建置・重新發布的程序
- 核准緊急變更的聯絡管道
- 對外通訊的允許目的地,以及停用時的影響
- 日誌的保存位置與搜尋方法
SBOM本身不是目的,而是用來在短時間內回答「這個漏洞會影響哪些正在執行的系統」的索引。
不能只做完更新就結束調查
在漏洞公布前後,系統有可能早已遭受攻擊。就算更新到修正版、阻止了今後的濫用,已經外洩的憑證或已被植入的後門並不會因此消失。
若是Log4Shell型漏洞,至少應調查以下這些面向。
- 包含JNDI或LDAP等可疑字串的HTTP請求
- 從應用程式伺服器發往外部LDAP・RMI・HTTP的通訊
- 異於平常的子處理程序啟動
- 建立可疑的JAR、class、指令碼、執行檔
- 存取雲端憑證或環境變數
- 更新前後的認證・權限變更・對外傳送
重要的是,不能只憑WAF日誌就斷定「沒有遭受攻擊」。因為還存在不經過WAF的內部路徑,以及過去未曾保存下來的日誌。
15. 有助於在考試中拿分的閱讀方式
這道題目與其說是知識題,不如說是考驗能否讀出規格與實作之間差異的題目。
15.1 把表中的「規格」與「實作」分開來看
在status的問題中,API規格中沒有的值,卻在實作中被放行了。
規格:
mid / name / age
實作:
把收到的參數全部送進P
只要能看出這個落差,就能明白空格c的答案是共用模組P。
15.2 在攻擊者變更的值上劃線標記
各項攻擊中被變更的值如下。
- JWT標頭的
alg - JWT酬載的使用者ID
- API參數的
mid - 規格外的
status - 認證API的
otp - HTTP標頭的
x-api-version
幾乎每一道設問,問的都是「這個值應該在哪裡被驗證」。
15.3 把解答還原成題目原文的用語
在實務上,可以直接稱之為「BOLA」「Mass Assignment」「rate limiting」。但設問要求的,是配合題目原文架構所寫出的具體處理內容。
不好的例子:
妥善進行授權。
好的例子:
驗證JWT中所含的使用者ID是否與mid的值一致。
不好的例子:
做好暴力破解對策。
好的例子:
連續失敗次數超過門檻值就鎖定帳號。
光是知道抽象名稱,並不能寫出符合字數限制、可供評分的答案。
15.4 WAF要追蹤的是「攻擊字串放進了哪裡」
WAF的檢查對象,不是從攻擊種類去猜測,而是要依攻擊字串存放的位置來決定。
放進了x-api-version標頭
↓
檢查對象是Header
評分講評中提到設問3(1)正確率偏低,原因也在於很多答案不符合圖6的攻擊流程。只要試著把攻擊步驟用箭頭重新畫出來,就能看清該觀察的重點是什麼。
16. 實務API審查中可用的檢查清單
以下是能把這道題目應用到實際設計・程式碼審查中的檢查清單。
JWT驗證
- 允許使用的簽章演算法已在伺服器設定中固定下來
- 拒絕
none或非預期的演算法 - 視用途驗證簽章、
iss、aud、exp、nbf - 不會把ID權杖、存取權杖、更新權杖搞混
- 有金鑰輪替與失效時的處理程序
- 沒有把應保密的資訊放進JWT酬載
物件層級授權
- 就算變更請求中的ID,也無法到達他人的資料
- 清單、詳細資訊、更新、刪除、下載,每一項都有做授權檢查
- 授權是在存取資料的共用層執行,而不是在畫面層
- 對於本人專用的API,已考慮是否能從權杖導出目標ID
- 管理者用的操作與一般使用者用的API,授權原則已分開
屬性層級授權
- 外部輸入型別與資料庫實體已經分開
- 可更新的項目已用許可清單列舉出來
- 規格外的屬性會被拒絕或被記錄稽核
- 權限、付費、核准、擁有者等狀態,無法透過使用者輸入來變更
- 回應內容中也沒有包含不必要的機密屬性
認證嘗試
- 有帳號單位的失敗次數限制
- 有階段性延遲或依來源做的控制
- 重新發出認證碼時不會重設失敗次數
- 認證碼只能使用一次
- 不會把認證碼或密碼留在日誌中
- 解鎖・復原程序不會變成另一條較弱的認證路徑
重大的相依函式庫漏洞
- 能將正在執行的服務與相依版本互相對應
- 有以無害方式驗證影響範圍的程序
- 能套用WAF或限制對外通訊等暫定對策
- 有負責人確認偵測警示的營運機制
- 有能緊急發布修正版更新的路徑
- 會在更新前透過日誌調查是否已遭濫用
17. 從這道題目看見共用元件的兩面性
這道題目中出現了JWT管理函式庫Q與共用模組P這兩個共用元件。
共用元件有很大的優點。
- 只要修正一個地方,就能把修正套用到所有使用它的API上
- 不必在各個功能中重複實作授權或驗證邏輯
- 能夠集中測試對象
- 能統一日誌與稽核的格式
但另一方面,錯誤也會擴散到整體。
- 只要函式庫Q接受
alg=none,所有使用JWT的API都會陷入危險 - 只要共用模組P接受任意的
mid或status,GET與PUT兩者都會陷入危險 - 只要基礎架構中使用了有漏洞的函式庫H,所有把HTTP標頭輸出到日誌的路徑都會變成攻擊面
因此,應該共用化的並不只是單純的資料存取。必須把安全性不變條件也共用化,並對這個共用元件單獨進行嚴格驗證。
例如,可以把P的介面約定設計成以下這樣。
P.getOwnUser(authenticatedSubject)
P.updateOwnProfile(authenticatedSubject, ProfileUpdate{name, age})
像下面這種低階API,不要直接公開給一般呼叫端使用,會比較安全。
P.getUser(arbitraryMid)
P.updateUser(arbitraryMap)
真正需要用到後者的,只有管理處理等有限的路徑。若把這種低階的自由度分配給所有API,就等於是一種「每次都寄望呼叫端能正確使用」的設計。
18. 總結
令和6年度春季下午問1,是一道要求把API安全的各項論點一一分離來解讀的題目。
使用JWT,不代表就是安全的認證。只要讓攻擊者選擇簽章演算法,使用者ID就可能被竄改。
JWT的簽章正確,不代表授權也是正確的。只要信任請求中的mid,正常使用者就能存取他人的資訊。
能更新自己的物件,不代表所有屬性都可以任意變更。只要像status這樣的內部狀態被自動綁定,權限或付費狀態就可能被竄改。
認證碼有有效期限,不代表能抵禦暴力破解。必須計算候選數量與嘗試速度,並限制失敗次數。
在WAF中加入規則,不代表漏洞已經修正。應透過偵測與阻斷爭取時間、確認影響範圍,最終仍要更新函式庫。
flowchart TB
accTitle: 漏洞與對策對應表
accDescr: 把各項漏洞對應到相應的信任邊界與對策
A[JWT竄改] -->|權杖驗證| B[固定允許的演算法]
C[替換mid] -->|物件層級授權| D[核對JWT主體/mid非必要]
E[status=paid] -->|屬性層級授權| F[把更新DTO做成許可清單]
G[4位數認證碼暴力破解] -->|認證嘗試控制| H[失敗次數限制・延遲]
I[Log4Shell型漏洞] -->|輸入到執行| J[更新函式庫/WAF]
圖15:漏洞與對策對應表。依被突破的邊界分別列出對策。
貫穿這道題目的原則只有一個。
不要因為前一項驗證成功,就把它當成省略下一道信任邊界的理由。
本系列的前兩篇文章,解說了令和5年秋 下午問1的儲存型XSS,以及令和5年秋 下午問2從訪客用Wi-Fi外洩資料的案例。若想確認整個網站的檢查觀點,也請參考把IPA《安全的網站製作方式》當作檢查清單來用。
flowchart TB
accTitle: 最終總結
accDescr: 顯示即使前一項驗證成功,也不能省略下一道信任邊界
A[認證成功] --> B[JWT簽章驗證]
B --> C[物件層級授權]
C --> D[屬性層級授權]
D --> E[嘗試次數限制]
E --> F[輸入到執行的邊界]
F --> G[WAF/函式庫更新]
圖16:最終總結。信任邊界應逐階段確認,不可省略任何一個。
參考連結
</content>
-
IPA, 令和6年度春季 資訊處理安全確保支援士考試 下午 試題冊。本文所討論的即為此份題目。 ↩
-
IPA, 令和6年度春季 資訊處理安全確保支援士考試 下午 解答範例。各設問的官方解答範例。 ↩
-
IPA, 令和6年度春季 資訊處理安全確保支援士考試 下午 評分講評。說明正確率與常見錯誤答案的傾向。 ↩
-
NIST, SP 800-63B: Authentication and Authenticator Management。說明了短期密碼的位數、嘗試次數限制、重新發行時的失敗次數、不將電子郵件用於頻外驗證等規範。 ↩ ↩2
-
RFC Editor, RFC 7519: JSON Web Token (JWT)。定義JWT規格,其中包含Unsecured JWT與
alg=none。 ↩ -
RFC Editor, RFC 8725: JSON Web Token Best Current Practices。規範了固定允許演算法、驗證發行者・主體・audience等做法的最佳實務(BCP)文件。 ↩
-
OWASP, API1:2023 Broken Object Level Authorization。說明了必須針對使用者指定的每一個物件ID分別確認授權的必要性。 ↩
-
OWASP, API3:2023 Broken Object Property Level Authorization。說明了包含Mass Assignment在內的屬性層級授權缺失與對策。 ↩
-
Apache Logging Services, Security。說明了CVE-2021-44228的影響範圍、透過JNDI與LDAP執行程式碼的方式,以及修正版本。 ↩
相關文章
共用相同標籤的最新文章。能以相近的主題延伸理解。
資訊處理安全確保支援士(情報処理安全確保支援士) 2023年秋季(令和5年)午後問1解說 ── 16則評論卻只顯示2則的儲存型XSS
以資訊處理安全確保支援士考試2023年秋季(令和5年)午後問1為題材,解說儲存型XSS的攻擊流程。整理輸入字數限制被分段投稿突破的原因、工作階段 ID 在未經外部通訊的情況下以圖片形式被取出的路徑,以及當中真正發揮作用的因應對策。
資訊處理安全確保支援士(情報処理安全確保支援士) 2023年秋季(令和5年) 下午問2解說 ── 從來賓用Wi-Fi被帶出的檔案
以資訊處理安全確保支援士考試 2023年秋季(令和5年) 下午問2為題材,解說堵住USB隨身碟的公司如何被人從來賓用Wi-Fi帶出檔案的路徑。整理伺服器憑證驗證與HSTS、MAC位址過濾的侷限性,以及EAP-TLS和TPM帶來的因應對策。
網站發包方也該了解 ── 把 IPA《安全的網站製作方式》當作檢查清單來用
公司網站的資訊安全該用什麼基準來確認?本文以發包方、營運方也能理解的說法,解說 IPA《安全的網站製作方式》所列出的 11 項漏洞與對策,並介紹在發包、驗收、營運各階段的用法。
資訊安全10大威脅 2026 ── 排行榜的正確解讀方式,以及中小企業真正該做的對策
IPA「資訊安全10大威脅2026」中,勒索軟體攻擊連續11年蟬聯第1名,供應鏈攻擊位居第2,首度入選的「AI使用相關的網路風險」則排名第3。本文將解說組織篇前10名的內容,以及中小企業應將哪些威脅視為自身課題並加以對策。
中小企業的資安對策,該從何開始 ── IPA「中小企業資訊安全對策指南」第4.0版導覽
中小企業的資安對策該從何開始?本文以IPA「中小企業資訊安全對策指南」第4.0版為基礎,從資訊安全六條款、5分鐘自我診斷,到SECURITY ACTION,依序分階段解說。
相關主題
與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。
Windows 技術主題
彙整 KomuraSoft LLC 關於 Windows 開發、故障調查與既有資產活用文章的主題中心。
與本主題相關的服務
本文連結到以下服務頁面,歡迎從最接近的入口查看。
網站製作
會員API與智慧型手機聯動時,JWT驗證、物件層級授權、可更新屬性的限制,直接關係到Web系統的安全性。
技術諮詢 & 設計審查
透過設計審查找出既有API的授權缺口、相依函式庫的影響範圍、WAF暫定規則,屬於技術諮詢的範疇。
常見問題
整理諮詢這個主題時常見的問題。
- 為什麼JWT的簽章驗證明明成功,卻還能冒充他人?
- 在本題中,JWT管理函式庫會依攻擊者指定的方式接受JWT標頭中的alg,把alg=none的JWT當成未簽章卻仍屬正確的權杖來處理。因此,即使改寫酬載中的使用者ID,驗證依然會成功。考試的解答是,將驗證對象設為JWT標頭中的alg,並確認其值不是NONE。不過在實務上,只拒絕NONE並不夠。應在伺服器端的設定中,把允許使用的演算法固定為RS256等,不讓權杖自行申報的演算法直接用於選擇。此外還要視用途驗證issuer、audience、有效期限、subject等項目。
- 只要核對JWT內的使用者ID與請求中的mid,作為授權對策就足夠了嗎?
- 作為本題的解答已經足夠。在共用模組P中驗證JWT內含的使用者ID與mid是否一致,就能擋下指定他人mid的攻擊。不過,如果API只處理使用者本人的資訊,實務上更安全的做法是不從用戶端接收mid,而是依驗證過的JWT的subject來決定使用者ID。例如設計成GET /users/me或PUT /users/me,就能從根本上降低漏寫比對處理這類實作疏失發生的機率。管理者操作他人資料的API,則應拆分成不同的端點與授權原則。
- 新增status的攻擊,為什麼光靠一般的輸入值驗證無法防範?
- 因為即使驗證了name的長度或age的範圍,只要原本就不該接收的status被自動綁定並傳給內部物件,就無法防範這種攻擊。問題不在於值的格式,而在於該屬性是否允許由使用者變更,這是屬性層級的授權問題。更新用的輸入型別應只定義name與age,並拒絕未知的屬性。付費狀態則必須只能透過伺服器可信任的事件(例如支付服務回傳的成功結果)來變更。
- 4位數的認證碼10分鐘就會失效,為什麼還是很危險?
- 因為從0000到9999的候選只有1萬種,若每秒能嘗試10次,平均5,000次、也就是500秒就會命中。有效期間10分鐘等於600秒,如果依序嘗試不重複的候選,就能在有效期間內驗證6,000種組合。只靠失效時間無法阻止暴力破解,必須把候選數量、嘗試速度、嘗試次數上限一併納入設計。
- 設問的對策是鎖定帳號,但實務上只做即時鎖定就夠了嗎?
- 不夠。題目空格中應填入的是「連續失敗次數超過門檻就鎖定帳號的處理」,但如果只做固定式的永久鎖定,攻擊者就能刻意鎖定他人帳號,造成服務妨害。實務上應結合帳號單位的失敗次數、階段性等待時間、對來源與裝置的風險判斷、通知、復原程序。即使發出新的驗證碼,也不能把失敗次數歸零,這一點同樣重要。
- 把WAF設為偵測而非阻斷,意義何在?
- 意義在於,即使把正常字串誤判為攻擊,也不會因此中斷業務通訊。題目的解答中,好處是可以避免因誤判而遭到阻斷,應執行的內容則是收到警示後,查明是否真的是攻擊。偵測模式並不是放著不管的設定,而應把它當成一段觀察期間:確認日誌、排除誤判、調整規則,再轉為阻斷。若已知的重大漏洞正遭到實際濫用而情況緊急,也可能權衡可用性風險後,判斷應優先阻斷。
- 本題中的函式庫H是Log4j嗎?
- 題目原文隱去了具體產品名稱,不過JNDI Lookup、LDAP伺服器、從HTTP伺服器取得類別檔案、嵌入HTTP標頭的字串、CVSS v3.1偏高的基本分數——這一整套攻擊流程,很自然地可以視為對外界熟知的Log4Shell(CVE-2021-44228)所做的抽象化描述。本文會說明這層對應關係,但考試中不需要回答具體的產品名稱,僅憑題目給出的攻擊步驟與WAF規格就能作答。
- 從這道題目應該帶回實務的重點是什麼?
- 重點在於,認證成功、JWT未遭竄改、可以存取目標物件、可以變更目標屬性,這些全都是各自獨立的確認。此外,短位數的認證碼必須搭配嘗試次數限制,而重大的函式庫漏洞則需要同時推進影響確認、暫定防禦與根本修正。把授權集中到共用元件、把輸入結構做成許可清單、在伺服器端固定JWT的驗證條件、掌握相依函式庫並隨時保持可更新的狀態,是實務上的核心所在。