具代表性的面試主題

通用面試:如何安全使用 URI Template 產生 API 連結?

通用困難
Offer.cc 編輯團隊發佈 更新

題幹

一個 API 閘道用 URI Template 產生分頁、篩選和資源連結。請說明 RFC 6570 的變數展開規則,並設計防止路徑穿越、SSRF 和錯誤編碼的實作與測試。

題幹與適用場景

團隊希望用 URI Template 統一產生 API 文件、分頁連結和批次查詢 URL,例如 /users{?status,limit}。模板來自設定檔,變數值部分來自使用者輸入。請說明 RFC 6570 的表達式層級、保留字元與清單展開規則,並設計安全的解析、展開和驗證邊界。

面試官考察點

  • 是否能區分模板語法、變數值編碼與最終 URI 的解析驗證。
  • 能否解釋簡單展開、保留字元展開、路徑/查詢/矩陣參數展開的差異。
  • 是否處理清單、關聯陣列、explode、前綴截斷和未定義變數。
  • 能否識別不可信模板帶來的 SSRF、路徑穿越、開放重新導向和敏感資訊洩漏風險。

回答前需要釐清的問題

  1. 模板是靜態程式碼、受審核設定,還是租戶或使用者可以提交?
  2. 產生結果只用於展示,還是會被伺服器 HTTP 用戶端直接請求?
  3. 變數是字串、清單、關聯陣列,還是允許巢狀 JSON?
  4. 允許哪些 scheme、host、port 和路徑前綴,是否必須限制在目前 API origin?
  5. 需要相容 RFC 6570 的全部層級,還是只支援審核過的操作符子集?

30 秒回答框架

我會把模板解析、變數編碼和最終 URI 策略分開。先定義支援的 RFC 6570 操作符與資料型別,再按操作符執行百分比編碼、清單和關聯陣列展開;未定義變數應按規範省略。展開後把結果當作不可信 URI,解析並驗證 scheme、host、port 和規範化路徑,禁止模板決定伺服器可存取的網路目標。測試涵蓋保留字元、Unicode、空值、重複鍵、前綴和惡意路徑。

分步驟深入解答

第一步:明確 URI Template 的邊界

URI Template 是用變數表達 URI-reference 的模板語法,不是 HTTP 用戶端、URL 白名單或業務路由器。實作必須先解析字面文字和表達式,再根據變數值產生結果;不能把模板字串直接拼接到請求中,也不能把展開結果當成已安全的 URL。

第二步:按層級實作操作符

RFC 6570 從簡單變數展開開始,逐步涵蓋保留字元、路徑片段、標籤、路徑段、矩陣參數以及查詢和查詢延續。常見操作符包括 +#./;?&。操作符決定分隔符、空值表現和哪些保留字元可以保留,不能用一個通用字串替換規則代替。

第三步:處理值編碼與複合值

簡單字串中的保留字元應按表達式規則百分比編碼。清單可用逗號連接或透過 explode 變成重複參數;關聯陣列也有不同的鍵值分隔方式。前綴修飾符只取字串前綴長度,不能把它誤當成 Unicode 字元數、位元組數或安全截斷。實作應明確 UTF-8、空字串和未定義變數的行為。

第四步:隔離模板來源與變數來源

靜態、經程式碼審核的模板可以支援較完整的操作符;租戶設定應限制表達式、變數名和輸出元件。變數值可以來自請求,但模板不應允許呼叫函式、讀取環境變數或拼接任意 scheme。把模板 AST 與變數字典分離,避免透過變數名注入新的表達式語法。

第五步:驗證最終 URI

展開完成後用標準 URI 解析器讀取 scheme、authority、path、query 和 fragment。若結果用於伺服器請求,scheme、host、port 必須符合 allowlist,解析 DNS 後還要阻斷回環、鏈路本地和私有位址,並在重新導向時重新驗證。路徑規範化後再檢查根路徑,避免編碼後的 .. 繞過規則。

第六步:設計 API 連結的可維護性

分頁連結模板應明確哪些變數由伺服器產生,篩選條件應採用固定變數名和型別。不要把簽章、存取權杖或內部主機名放入可公開的模板或產生結果。記錄模板版本、變數 schema 和展開錯誤,結果需要穩定排序時由業務層保證,而不是依賴參數字串順序。

第七步:建立對照測試與監控

測試每個操作符的單變數、清單、關聯陣列、空值和未定義值,比較規範範例的預期結果。加入保留字元、Unicode、重複查詢鍵、過長前綴、雙重編碼、%2e%2e、不同 scheme、重新導向和 DNS 解析的安全用例。監控展開失敗率、拒絕原因、目標 origin 分布和異常長度,發現模板設定變化時觸發審核。

高品質示範回答

我會先限制支援的 RFC 6570 操作符,並把模板 AST、變數 schema、百分比編碼和最終 URI 驗證拆開。清單、關聯陣列、explode 和前綴修飾符按各自規則處理,未定義變數省略;不允許變數值重新解釋為表達式。展開結果始終視為不可信 URI,解析後只允許目前 API 的 scheme、host、port 和規範化路徑,伺服器請求還要阻斷私有位址並在每次重新導向時複檢。測試涵蓋 RFC 範例、Unicode、空值、重複鍵、雙重編碼、路徑穿越和 SSRF,記錄模板版本與拒絕原因。

常見錯誤

  • 用字串拼接代替操作符語意,導致查詢分隔符或百分比編碼錯誤。
  • + 保留字元展開當成「完全不編碼」,忽略表達式規則和 URI 元件邊界。
  • 把清單、關聯陣列和 explode 當成同一種逗號連接格式。
  • 只驗證模板文字,不驗證展開後的 scheme、host、port 和規範化路徑。
  • 把 URL 編碼當作 SSRF 防護,允許伺服器跟隨未經複檢的重新導向。

追問及應對

追問一:未定義變數應該怎樣處理?

按表達式規則省略未定義變數及其必要分隔符,不應把它渲染成字串 null。業務層若要求必填,應在展開前依據變數 schema 報錯。

追問二:為什麼不能只呼叫 URL encode?

編碼方式由表達式和 URI 元件決定,查詢參數、路徑段和保留字元展開的分隔符不同。單一編碼函式無法決定複合值、空值、前綴和操作符行為。

追問三:模板來自租戶時如何降低風險?

使用審核後的操作符子集、固定變數 schema 和輸出元件,不允許任意 scheme 或 authority。展開後仍執行 origin allowlist、路徑規範化、DNS/IP 檢查和重新導向複檢。

追問四:前綴修飾符能用於截斷敏感字串嗎?

它是 URI Template 的字串前綴語意,不是隱私脫敏或 Unicode 安全截斷。敏感資料應在業務層顯式遮罩,長度和字元邊界也要由業務規則定義。

追問五:如何證明實作相容 RFC 6570?

執行 RFC 6570 的規範範例和各級操作符測試,比較每個變數型別的預期展開結果;再補充專案自己的安全拒絕用例,並記錄未支援的層級和差異。

公開來源

同類題目