실제 사용 환경에서의 추가 조사와 확인을 바탕으로 후속 보고드립니다.
더 깊이 파고든 결과, 이는 Discourse나 Azure 설정의 문제라기보다는 iOS 인앱 브라우저(WKWebView)의 제한 사항으로 보입니다.
확인된 내용
nginx + Rails 로그 및 사용자 테스트를 통해 확인한 바는 다음과 같습니다:
• OAuth 플로우가 때때로 iOS 인앱 브라우저(예: Snapchat) 내에서 시작됩니다.
• Microsoft 로그인(login.microsoftonline.com)이 해당 인앱 브라우저 내에서 로드됩니다.
• OIDC 콜백은 Discourse에 정상적으로 도달합니다.
• 그러나 state 값을 포함하는 세션 쿠키가 유지되지 않습니다.
• 결국 다음과 같은 결정적인 오류가 발생합니다:
GET /auth/failure?message=csrf_detected&strategy=oidc
이 문제는 리퍼러가 Microsoft이고 리다이렉트 URI가 정확하더라도 발생합니다.
대표적인 UA(User Agent):
Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X)
Snapchat/13.76.1.0 (like Safari/..., panda)
따라서 UI에서는 Microsoft가 "원박스(onebox)"로 잘 표시되더라도, 실제 기반 브라우저는 Safari나 ASWebAuthenticationSession이 아닌 Snapchat의 WKWebView입니다.
테마 컴포넌트를 통한 인터셉트는 작동하지 않음
클라이언트 측에서 테마 컴포넌트를 사용하여 이를 완화하려 시도했습니다:
• 알려진 인앱 브라우저 UA 감지
• /auth/oidc 링크 차단
• 사용자에게 Safari/Chrome에서 열 것을 안내하는 영구 오버레이 표시
그러나 다음과 같은 이유로 이 방법은 플로우를 안정적으로 인터셉트하지 못했습니다:
• OAuth 리다이렉트는 서버 측에서 시작됩니다.
• state 쿠키는 클라이언트 JS가 실행되기 전에 이미 존재해야 합니다.
• 테마가 로드될 시점에는 이미 문제가 발생한 뒤입니다.
따라서 테마 컴포넌트로는 이러한 실패 모드를 안정적으로 방지할 수 없습니다.
안정적으로 작동하는 방법
일관되게 작동하는 유일한 완화책은 사이트 텍스트를 오버라이드하는 것입니다:
login.omniauth_error.csrf_detected
이를 통해 다음 내용을 명시적으로 설명하도록 설정했습니다:
• 로그인이 인앱 브라우저로 인해 실패했다는 점
• 사용자는 Safari 또는 Chrome에서 사이트를 열어야 한다는 점
• 그 후 로그인을 다시 시도해야 한다는 점
이 메시지는 실패 후 서버 측에서 렌더링되므로, 손상된 인앱 브라우저 컨텍스트에서도 표시됩니다.
이전에는 사용자가 로그인 페이지로 조용히 되돌려지고 무엇이 잘못되었는지 깨닫지 못하는 경우가 많았기 때문에, 이 조치로 사용자 혼란이 크게 줄었습니다.
SameSite 쿠키에 대하여
same_site_cookies를 "None"으로 변경하지 않았습니다.
이것이 WKWebView 격리 문제(Safari의 크로스 사이트 내비게이션이 아님)이기 때문에, SameSite 설정을 변경해도 근본 원인을 해결하지 못할 뿐만 아니라 불필요한 보안 트레이드오프를 초래할 수 있다고 판단했습니다.
미해결 질문
위 내용을 바탕으로 다음 사항에 대해 확인을 요청드립니다:
• OAuth가 iOS 인앱 브라우저에서 시작될 때 이러한 동작이 예상되는 동작으로 간주되는지
• Discourse가 해당 플로우를 지원할 계획인지, 아니면 로그인이 실제 브라우저에서만 이루어져야 한다고 문서화할 것인지
또한 OmniAuth 컨텍스트에서 csrf_detected에 대해 더 명확한 기본 메시지를 Discourse가 제공하면 유용할 것입니다. Snapchat/Instagram 링크를 통해 접속하는 학생 사용자들의 경우 이 실패 모드가 점점 더 흔해지고 있기 때문입니다.
필요하다면 더 많은 익명화 로그를 제공할 수 있습니다. 하지만 이 시점에서 동작은 매우 일관되고 재현 가능합니다.
확인해 주셔서 감사합니다.