Skip to content

SAML POST 서명 AuthnRequest 검증 + 이메일 Workers/Node 추상화(B6) - #76

Merged
mack-erel merged 4 commits into
mainfrom
feat/saml-email-followup
Jul 5, 2026
Merged

SAML POST 서명 AuthnRequest 검증 + 이메일 Workers/Node 추상화(B6)#76
mack-erel merged 4 commits into
mainfrom
feat/saml-email-followup

Conversation

@mack-erel

Copy link
Copy Markdown
Owner

개요

PR #75 이후 남았던 두 항목을 처리합니다. 둘 다 독립 에이전트 구현 + 게이트 검증.

검증: vitest 62 passed(10 files) · svelte-check 0 errors(1359 files) · eslint 통과 · adapter-cloudflare·adapter-node 빌드 성공.

1. SAML POST 바인딩 서명 AuthnRequest 검증

이전엔 서명된 POST AuthnRequest를 "검증기 없음"으로 거부했습니다. 이제 enveloped XML 서명을 검증해 수용합니다.

  • verify-xml-signature.ts: verifyEnvelopedXmlSignature(xml, certPem) — xmldsigjs Verify우리가 신뢰하는 sp.cert 공개키를 명시 주입(KeyInfo 내부 인증서 불신 → 자기서명+자기cert 위조 차단).
  • XSW(서명 래핑) 다층 방어: ds:Signature는 루트 직계 자식 1개 · Reference URI==루트 ID · enveloped transform 필수 · 중복 ID 거부 · SignatureMethod/DigestMethod SHA-256+ 화이트리스트(SHA-1은 opt-in).
  • saml/sso POST: 서명 존재 또는 wantAuthnRequestsSignedsp.cert로 검증(없거나 실패 → 400). 미서명+미요구는 통과. GET(Redirect) 흐름 무변경.
  • 유닛 테스트 8건(정상/타 키/본문·서명 변조/무서명/XSW 루트불일치·중복ID/빈 cert).
  • ⚠️ 자체 검증만 보장 — 실제 SP interop 별도 테스트 권장. 로그아웃+wantSigned resume 완성은 서버측 pending-request 보관이 필요한 후속(현재 fail-closed=거부).

2. 이메일 발송 Workers/Node 추상화 (B6, 프로덕션 결함)

nodemailer(raw TCP SMTP)는 Cloudflare Workers에서 동작하지 않아, Workers 배포에서 비밀번호 재설정/아이디 찾기 메일이 런타임 실패했습니다.

  • email.ts 런타임 분기: platform.env.EMAIL(Cloudflare send_email 바인딩) 있으면 Cloudflare Email Sending, 없으면 nodemailer. nodemailer는 동적 import → Workers 번들에 net/tls 미유입(빌드로 실증).
  • 발송 함수에 platform 스레딩. 기존 보안(HTML escape/URL scheme 검증/waitUntil 타이밍 분리/응답 균일성) 100% 보존.
  • app.d.tsPlatform.env.EMAIL?: SendEmail. wrangler.example.jsoncsend_email 바인딩 + EMAIL_FROM 예시·온보딩 주석.

사용자 조치 (Cloudflare Email 활성화 — 이거 해야 Workers에서 메일 발송됨)

  1. sender 도메인 온보딩: wrangler email sending enable <yourdomain.com> (SPF/DKIM/DMARC DNS 설정 동반).
  2. 실사용 wrangler.jsonc(및 wrangler.prod.jsonc)에 send_email: [{ "name": "EMAIL" }] 추가.
  3. EMAIL_FROM(온보딩 도메인 주소) 설정, 선택적으로 EMAIL_FROM_NAME.
  • 온보딩된 sender 도메인만 있으면 임의 외부 수신자에게 발송 가능(트랜잭션 메일 적합). Node 배포는 종전 SMTP_* 그대로.

🤖 Generated with Claude Code

mack-erel and others added 2 commits July 5, 2026 20:28
- verify-xml-signature.ts: verifyEnvelopedXmlSignature(xml, certPem). xmldsigjs SignedXml.Verify 에
  **sp.cert 공개키를 명시 주입**해 검증 — KeyInfo 내부 인증서를 신뢰하지 않음(자기서명+자기cert 위조 차단).
- XSW(서명 래핑) 다층 방어: ds:Signature 는 루트 직계 자식 1개, Reference URI==루트 ID, enveloped
  transform 필수, 중복 ID 거부, SignatureMethod/DigestMethod SHA-256+ 화이트리스트(SHA-1 은 opt-in).
- saml/sso POST: 기존 "서명 있으면 무조건 거부"를 실제 검증으로 교체. wantAuthnRequestsSigned 또는
  서명 존재 시 sp.cert 로 검증(cert 없거나 검증 실패 → 400). 미서명+미요구는 통과. XML 은 상단에서 1회
  디코드해 파서·검증기가 동일 원본을 보게 함.
- 유닛 테스트 8건(정상 통과/타 키 실패/본문·서명 변조 실패/무서명/XSW 루트 불일치·중복ID/빈 cert).
- ※ 자체 검증만 보장 — 실제 SP interop 은 별도 테스트 권장. 로그아웃+wantSigned resume 완성은
  서버측 pending-request 보관이 필요한 후속 과제(현재 fail-closed=거부).

vitest 62 passed(10 files), svelte-check 0 errors, eslint·build 통과.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
- 문제: nodemailer(raw TCP SMTP)가 Cloudflare Workers 에서 미동작 → Workers 배포에서 비밀번호
  재설정/아이디 찾기 메일이 런타임 실패(실제 프로덕션 결함).
- email.ts send(to,subject,html,platform) 런타임 분기: platform.env.EMAIL(send_email 바인딩)
  있으면 Cloudflare Email Sending(EMAIL.send, text+html), 없으면 nodemailer.
  nodemailer 는 동적 import 로 전환 → Workers 번들에 net/tls 미유입(빌드로 실증).
- sendFindIdEmail/sendPasswordResetEmail 에 platform 스레딩(find-id/find-password 호출부).
  기존 보안(escapeHtml/safeAbsoluteUrl/waitUntil 타이밍 분리/응답 균일성) 100% 보존.
- app.d.ts 에 Platform.env.EMAIL?: SendEmail. wrangler.example.jsonc 에 send_email 바인딩 +
  EMAIL_FROM 예시·온보딩 주석. 실사용 wrangler.jsonc 는 사용자 관리(미변경).
- 사용자 조치: `wrangler email sending enable <domain>` + 실사용 wrangler 에 바인딩/EMAIL_FROM 추가.

adapter-cloudflare·adapter-node 빌드 성공, vitest 62 passed, svelte-check 0 errors, eslint 통과.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Comment thread src/lib/server/email.ts Fixed
Comment thread src/lib/server/email.ts Fixed
mack-erel and others added 2 commits July 5, 2026 20:45
- CodeQL js/incomplete-multi-character-sanitization·js/double-escaping (email.ts htmlToText) 해소.
- HTML 을 정규식으로 역파싱(<[^>]+> 태그 제거 + 엔티티 언이스케이프)하던 방식을 제거하고,
  각 발송 함수(findId/passwordReset)가 text/plain 본문을 명시적으로 작성해 send() 에 넘긴다.
  실제 취약점은 아니었으나(우리가 생성한 escape된 HTML → text/plain, 미실행) 더 정확·안전.

svelte-check 0 errors, eslint·build 통과.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@mack-erel
mack-erel merged commit fcd754d into main Jul 5, 2026
6 checks passed
@mack-erel
mack-erel deleted the feat/saml-email-followup branch July 5, 2026 11:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants