diff --git a/packages/backend/src/controller/nonceCheck.ts b/packages/backend/src/controller/nonceCheck.ts index a27a4d6..c98f44c 100644 --- a/packages/backend/src/controller/nonceCheck.ts +++ b/packages/backend/src/controller/nonceCheck.ts @@ -1,29 +1,51 @@ import type { Request, Response } from "caido:utils"; -import { TokenLeakCheck } from "./tokenLeakCheck"; -export class NonceCheckController{ - /** - * 응답이 OIDC(OpenID Connect) 플로우인지 확인하는 메서드 - */ - - public static isOidcFlow(req: Request, res:Response): boolean { - if(TokenLeakCheck.extractIdToken(req, res)) { - return true; - } - return false; +export class NonceCheckController { + /** + * OIDC 플로우 탐지 로직 (OAuth 2.0과 구분) + */ + public static isOidcFlow(req: Request, res: Response): boolean { + const url = req.getUrl(); + const query = req.getQuery(); + const location = res.getHeader("Location"); + const contentType = res.getHeader("Content-Type"); + + // 1️⃣ Authorization 요청: scope=openid 포함 + if (url.includes("/authorize") && /response_type=/.test(query) && (/scope=openid/.test(query)) ){ + return true; } - - public static isNonceCheckRequest(req: Request): boolean { - const id_token = TokenLeakCheck.decodeIdToken(req); - - // 1. nonce 파라미터가 포함된 요청인지 확인 - if (id_token && id_token.includes("nonce=")) { - return true; - } - - return false; + // 2️⃣ Token 응답: id_token 필드 포함 + if (contentType?.includes("application/json")) { + const body = res.getBody(); + const bodyStr = typeof body === "string" ? body : body?.toString?.() ?? ""; + if (bodyStr && /id_token/.test(bodyStr)) { + return true; + } } + + // 3️⃣ Redirect 응답: Location 헤더에 id_token 포함 + if ( + (res.getCode() === 302 || res.getCode() === 303) && + location && + /id_token=/.test(Array.isArray(location) ? location[0] ?? "" : location ?? "") + ) { + return true; + } + + // 4️⃣ Authorization 요청 + nonce 파라미터 포함 + if (url.includes("/authorize") && /nonce=/.test(query)) { + return true; + } + + + + return false; + } + + + + + + } - - diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index a5e9113..e2753de 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -6,7 +6,7 @@ import { CsrfCheck } from "./controller/csrfCheck"; import { PKCECheck } from "./controller/PKCECheck"; import { AccessTokenLeakController } from "./controller/accessTokenDetector"; import { ScopeDetection } from "./controller/scopeDetection"; -// import { NonceCheckController } from "./controller/nonceCheck"; +import { NonceCheckController } from "./controller/nonceCheck"; import { RedirectBypassController } from "./controller/redirect_uriBypass"; export type API = DefineAPI<{}>; @@ -26,14 +26,14 @@ export function init(sdk: SDK) { await ScopeDetectionController.scan(sdk, req.getUrl()); await redirectBypassController.testAsync(sdk, req, res); - // if (NonceCheckController.isOidcFlow(req, res)) { - // await sdk.findings.create({ - // title: "OIDC Flow Detected", - // description: "The request appears to be part of an OIDC flow.", - // request: req, - // reporter: "", - // }); - // } + if (NonceCheckController.isOidcFlow(req, res)) { + await sdk.findings.create({ + title: "OIDC Flow Detected", + description: "The request appears to be part of an OIDC flow.", + request: req, + reporter: "", + }); + } }); sdk.events.onInterceptRequest(async (sdk, req: Request) => {