웹 보안은 너무 어렵다
시작은 아무렇지도 않았다. 내가 좋아하는 회사 중 하나인 Cloudflare가 새 제품을 출시했다는 트윗을 봤다.

멋진데! 사이트를 클릭해 들어가 보니 정말 있었다.

그리고 만세! 내가 즐겨 쓰는 핸들 @ericlaw도 아직 남아 있었다. 다른 사람이 가져가기 전에 서둘러 선점해야겠다!
Cloudflare를 오래 사용해 왔으니 로그인만 하면 된다. 당연한 절차다. 달리 어떻게 이 핸들을 내 계정에 연결하겠는가?

간단하다. 로그인했다. 이제 한 단계만 더 거치면 되는 모양이다. 새 기능을 승인해야 하나?

그런데 잠깐!
이건 지난 몇 년간 유행했던 동의 피싱 공격과 완전히 똑같아 보인다!
게다가 왜 시작점이 이미 내 인증 정보를 보유한 cloudflare.com 도메인 내부(예: cloudflare.com/pay)가 아니라, 내 인증 정보가 없는 cloudflare.pay 사이트일까? a.com 도메인과 a.pay 도메인 사이에는 본질적인 기술적 연관성이 없다. .pay sTLD 아래의 도메인 이름은 더 엄격한 심사를 요구하는 .bank와 달리 누구나 $20만 내면 등록할 수 있다. 나도 몇 분이면 cloudflarepayments.pay라는 도메인 이름을 등록할 수 있으며, 이를 막을 방법은 없다.
또 Cloudflare의 권한 승인 사이트는 왜 자사 기능을 알아보지 못할까? 저 녹색 체크 표시도 몹시 수상하다. Microsoft 이메일 계정을 피싱하려는 사람들이 오해를 유도하는 앱 이름과 아이콘을 사용하는 것처럼, 공격자가 기만적인 표시 이름 안에 저 이모지를 집어넣었을 수도 있다.

가짜 Outlook OAuth 피싱 요청
Cloudflare 사람들은 보안을 제대로 아는 천재들이다. 이건 틀림없이 공격이다. 아주 교묘한 공격이었다. 원하는 핸들을 먼저 차지하는 경쟁에서 “이기고” 싶어 마음이 다급해졌기 때문이다. 정말이지 너무나 영리하다!
안타깝게도 Cloudflare 권한 승인 페이지는 모범 사례를 따르지 않는다. Cloudflare 측에 고객들이 공격받고 있다고 알릴 수 있는 “의심스러운 요청 신고” 링크가 없다.
Cloudflare 대시보드로 돌아가 사이드바에서 Wallet 기능을 찾아보자. 흠. 없다. Wallet이 “새 기능”이라고 하니 대시보드가 아직 업데이트되지 않았을 수도 있다. 문서를 검색해도 아무것도 나오지 않는다. 채팅의 AI 에이전트에게 물어보자.
채팅 에이전트가 가장 먼저 요구한 것은 내 계정에 대한 접근 권한이었다.

조금 이상하지만 페이지는 여전히 cloudflare.com에 있으니, 이미 접근할 수 있는 항목에 대한 접근 권한을 줘도 될 듯하다. 이상하게도 AI 에이전트는 처음부터 읽기 전용이 아니라 모든 권한을 달라고 제안했다. 최소 권한 원칙을 지키지 않은 듯하지만, 어차피 계정에 관한 질문을 할 필요는 없다. 읽기 권한을 부여하자 에이전트가 질문을 받았다.

이럴 수가. Cloudflare도 정말 공격이 맞다고 한다! 당장 피싱을 신고하자!

몇 분 뒤… 이런, 망했다…

세상에.
다급하게 몇 분 더 찾아본 끝에, 영리한 피싱 공격이라는 신호를 모조리 드러내고 있었음에도 이것이 실제로는 Cloudflare의 정식 신제품이자 공식 사이트라는 사실을 알아냈다.
또한 확인해 보니, 그 수상한 녹색 체크 표시는 신뢰할 수 없는 앱 표시 이름의 일부가 아니었다. 사용자가 마우스를 올려 보안 세부 정보를 확인해야 하는, 위치가 잘못 선정된 보안 UI 요소였다.

Cloudflare 측은 보안 문제를 HackerOne으로 신고하기를 바라는 모양이다. 하지만 HackerOne이 사용하는 Cloudflare CAPTCHA가 고장 난 듯해 로그인할 수 없었다…
정상적인 웹사이트조차 때때로 피싱 사이트와 몹시 비슷하게 행동한다. 매주 수백만 개의 새 사이트가 웹에 추가되는 가운데, Microsoft SmartScreen이나 Google SafeBrowsing 같은 URL 평판 서비스가 오탐 없이 악성 사이트를 차단하는 일이 얼마나 어려울지 생각해 보라.
교훈
웹 개발자 여러분, 제발 모든 모범 사례를 따라 달라. 이렇게 부탁드린다.
앱과 콘텐츠는 신뢰받는 도메인 이름 아래에서 호스팅하라. 예를 들면
cloudflare.com/pay또는pay.cloudflare.com이다. 새 도메인 이름을 반드시 추가해야 한다면 신뢰받는 도메인의 페이지에서 그 주소로 직접 링크하라.사용자에게 보안 관련 결정을 요구할 때는 관련 보안 정보를 신뢰할 수 있는 위치에 표시하라.
권한 요청 페이지처럼 관련 맥락 안에서 사기를 아주 쉽게 신고할 수 있게 하라.
보안 신고 절차가 실제로 모니터링되고 올바르게 작동하는지 테스트하라.
사용자 여러분: 안전에 유의하라. 클릭하기 전에 생각하고, 그래도 판단이 서지 않으면 기다려라.
보안 전문가 여러분: 절대로 피해자를 탓하지 말라. 사용자에게는 애초에 해내기 불가능한 일이 주어져 있다.
-Eric
source https://textslashplain.com/2026/08/04/security-is-hard-yall/
HN에서는 이번 사례를 웹 취약점보다 ‘공식 서비스임을 사용자가 어떻게 확인할 것인가’라는 신원 증명의 문제로 봤다. 낯선.pay 도메인에서 로그인과 권한 승인을 요구하는 구성은 피싱과 구별하기 어려웠다. 여러 이용자도 cloudflare.com의 공식 블로그가 해당 주소를 가리키는지 확인한 뒤에야 실제 서비스라고 판단했다.
인증서 역시 운영 주체를 입증하지 못했다. 댓글에서 확인한 인증서는 도메인 소유권만 검증할 뿐 조직 정보는 담고 있지 않았다. 지원 챗봇마저 새 제품이 문서나 대시보드에 없다며 피싱으로 취급하라고 안내했다. 출시 당일 별도 도메인에서 서비스를 열면서 공식 사이트, 권한 요청 화면, 지원 채널의 정보를 맞추지 않은 점이 불신을 키운 셈이다. 이후 공식 블로그 연결을 추가한 대응은 긍정적으로 평가됐지만, 외부 주소에서 공식 글로 연결하는 것보다 공식 도메인에서 새 주소를 확인해 주는 편이 중요하다는 지적도 나왔다.
별도 도메인을 택한 배경에는 엇갈린 실무 경험이 제시됐다. 핵심 도메인에 새 서비스를 올리려면 보안 심사와 운영 승인을 거쳐야 하므로, 출시를 서두르는 조직이 새 도메인을 사는 일이 흔하다는 설명이다. 다만 이런 우회가 반복된다면 기술보다 조직 운영을 손봐야 한다는 비판이 뒤따랐다. 하위 도메인도 쿠키 범위, 방치된 DNS, 충분히 검토하지 않은 코드 때문에 자동으로 안전해지는 것은 아니라는 경계도 있었다.
결국 개발자에게 모범 사례만 요구해서는 부족하다. 새 서비스를 내놓을 때는 사용자가 기존 공식 주소에서 진위를 확인할 수 있는지, 권한 요청 화면이 소속과 목적을 분명히 밝히는지, 지원 문서와 상담 체계가 출시 정보를 공유하는지를 함께 점검해야 한다.
