비공개 보안 링크, 정말 공개 접근이 불가능할까?
(vin01.github.io)- urlscan.io, Hybrid Analysis, Cloudflare Radar URL Scanner 같은 URL/악성코드 분석 서비스는 위협 인텔리전스 공유를 위해 링크를 저장하지만, 사용자 실수나 잘못 설정된 스캐너 때문에 민감 링크가 공개 데이터로 남을 수 있음
- Dropbox, iCloud, AWS S3, Zoom, OneDrive, Airtable, 비밀번호 재설정 링크, OAuth 로그인 링크처럼 URL 자체가 접근 권한처럼 쓰이는 서비스가 특히 영향을 받을 수 있음
- 모든 링크가 곧바로 노출되는 것은 아니지만, 세금 문서, 청구서, 사진, 업무 커뮤니케이션, onetimesecret 공유 비밀, 스마트홈·회의 녹화 같은 자료가 실제로 발견됨
- urlscan Pro는 Public뿐 아니라 Unlisted 스캔도 유료 고객에게 보여주며, TheHive의 Cortex-Analyzers 설정처럼 의도치 않게 unlisted로 제출되는 경로가 있을 수 있음
- 최근 24시간 urlscan.io 스캔 수는 Public 398,563건, Unlisted 328,147건, Private 955,432건이었고, 카나리 토큰 실험에서도 제출 후 1시간 내 접근이 확인돼 스캔 가시성 관리가 필요함
URL 분석 서비스에 남는 민감 링크
- urlscan.io, Hybrid Analysis, Cloudflare Radar URL Scanner는 URL과 악성코드 분석을 위해 많은 링크를 저장함
- 문제는 이 저장소에 비공개·민감 링크도 함께 들어갈 수 있다는 점임
- 사용자가 공개 정보가 된다는 점을 모르고 민감 링크를 스캔에 제출함
- 잘못 설정된 스캐너나 확장 기능이 이메일에서 스캔한 비공개 링크를 공개 데이터로 제출함
노출될 수 있는 링크와 자료
- 발견된 링크는 여러 서비스의 공유 URL과 인증 관련 URL을 포함함
- Dropbox, iCloud, Sync, Egnyte, Ionos Hidrive, AWS S3 같은 클라우드 저장소 파일 공유
- Western Digital Mycloud 같은 클라우드 연결 NAS
- Slido, Zoom, OneDrive, Airtable 같은 기업 커뮤니케이션 도구
- 비밀번호 재설정 링크와 OAuth 로그인 링크
- 이런 서비스는 보안을 위해 랜덤 식별자를 포함한 단일 비공개 링크로 접근을 허용하는 경우가 많음
- 일부 링크는 비밀번호나 패스프레이즈로 추가 보호되므로, 링크 접근만으로 곧바로 데이터가 노출되지는 않음
- 실제로 발견된 민감 콘텐츠는 다음과 같음
- 세금 문서, 청구서, 사진, 업무 커뮤니케이션 같은 비공개 파일
- onetimesecret로 공유된 비밀
- 스마트홈 기기 녹화
- 클라우드에 저장된 회의 녹화
제출 경로와 책임의 빈틈
- urlscan.io에서 확인된 많은 제출에는 falconsandbox 태그가 있었고, 이를 계기로 Hybrid Analysis까지 분석 범위가 넓어짐
- Cloudflare Radar도 더 널리 쓰일 가능성이 있으며, 이미 일부 비공개 링크를 공개 데이터로 포함하고 있음
- Hybrid Analysis 약관은 사용자 제출 콘텐츠를 분석·공개·공유할 수 있으며, 제출물이나 자동 생성 보고서에 우연히 포함된 정보에 책임지지 않는다고 밝힘
- urlscan.io 약관도 사용자 콘텐츠나 행위에 대한 책임을 지지 않으며, 계정 아래 게시된 콘텐츠와 활동은 사용자가 책임진다고 밝힘
- 기존 콘텐츠를 검토해 민감 링크를 표시하거나 제거하는 명확한 메커니즘은 없어 보이며, 이를 자동화하기도 간단하지 않을 수 있음
- Positive Security의 분석은 urlscan.io를 대상으로 카나리 토큰을 사용해 자동화된 출처를 탐지했고, 이메일의 악성 링크를 스캔하는 보안 도구가 원인일 수 있음을 다룸
- 같은 동작은 카나리 링크로도 검증됨
Unlisted 스캔과 urlscan Pro 접근
- urlscan Pro는 유료 사용자와 기업에게 Public뿐 아니라 Unlisted 스캔까지 더 넓은 범주의 스캔 접근을 제공함
- urlscan.io에서 Unlisted는 공개 페이지나 검색 결과에는 보이지 않지만, urlscan Pro 플랫폼 고객에게는 보이는 상태임
- urlscan Pro 고객은 검증된 보안 연구자나 평판 있는 기업으로 제한된다고 안내됨
- TheHive의 Cortex-Analyzers는 의도치 않은 노출 경로를 보여주는 예시임
- urlscan.io 분석기에서
public:on설정을 명시적으로 사용함 - 이 설정 때문에 urlscan 계정 가시성이 Private이어도 링크가 unlisted로 나타날 수 있음
- 관련 코드는 Cortex-Analyzers의 urlscan.py에 있음
- urlscan.io 분석기에서
- 이 경우 데이터가 완전히 공개되지는 않더라도 urlscan Pro 사용자에게 보일 수 있어, 더 민감한 정보가 노출될 가능성이 남음
스캔 수와 카나리 토큰 결과
- 최근 24시간 기준 urlscan.io 스캔 수는 다음과 같음
Public: 398,563건Unlisted: 328,147건Private: 955,432건
- 카나리 토큰으로 확인한 접근 결과는 다음과 같음
- urlscan.io에
unlisted로 제출한 링크가 제출 후 1시간 내 12회 접근됨 - Hybrid Analysis에 브라우저가 아닌
API로 제출한 링크가 제출 후 1시간 내 10회 접근됨 - 일부 IP 주소는 두 서비스에 제출된 고유 링크를 동시에 접근했고, 출발지 IP 익명화 서비스를 사용함
- urlscan.io에
- 해당 IP 주소 목록은 별도 파일로 공개됨
민감 링크 제거와 사용 시 주의점
- urlscan.io와 Hybrid Analysis는 링크를 신고해 제거할 수 있는 절차를 제공함
- Hybrid Analysis는 제거와 공유 범위가 더 복잡함
- Public Sandbox에 제출된 모든 파일은 검색 가능하며 전 세계에 제공됨
- “Do not share my sample with the community” 체크박스를 선택해도 스크린샷과 실제 보고서는 계속 제공됨
- “do not share”는 실제 입력 샘플에만 적용됨
- 서비스를 사용할 때는 스캔 가시성을 먼저 확인해야 함
- 이런 URL 데이터베이스에서 링크나 파일에 접근할 경우 피싱 시도, 실제 악성 파일, 악성 링크를 만날 수 있음
- 접근이 필요하다면 샌드박스 환경에서 확인해야 함
댓글과 토론
Hacker News 의견들
-
근본 문제는 접근 제어 없는 링크가 공개 식별자 색인이 없다는 이유만으로 비공개라고 여겨진다는 데 있음
지난달에도 버킷을 통해 AWS 계정 ID를 찾는 이야기가 HN에서 꽤 흥했고[0], 댓글의 합의는 계정 식별자가 비공개라는 전제에 보안을 기대하는 건 잘못이라는 쪽이었음
여기에도 같은 개념이 적용되며, 새로운 보안 이슈라기보다 또 다른 검색 연산자 기반 탐색(dorking) 방법일 뿐임
[0]: https://news.ycombinator.com/item?id=39512896- 문제는 링크가 새어 나간다는 것임
이론적으로 256자리 16진수 링크, 즉 1024비트는 32자 사용자명과 32자 비밀번호보다 추측하기 훨씬 어려움
https://site.com/[256chars]는 2^1024 조합이라 무차별 대입이 사실상 불가능함
반면 https://site,com/[32chars]와 32자 비밀번호는 2^256 조합이라 이것도 불가능에 가깝지만 전자보다는 가능성이 큼
https://site,com/[32chars][32chars]처럼 보는 셈임
다만 전자가 더 맞히기 어렵더라도 URL은 비밀번호보다 훨씬 많이 유출됨 - 빠뜨린 세부가 있을 수 있지만, 근본 문제는 사람들 사이의 비공개 메시지가 비공개라고 여겨지는 반면 실제로는 메시지를 전달하는 플랫폼이 그 메시지를 읽고 링크에 접근한다는 데 있어 보임
여기서 메시지는 이메일, DM, 문서에 붙여넣은 링크까지 넓게 포함 - 약간 딴길이지만, 최근 컨설턴트에게 각 NAR 파일 이름에 거대한 해시가 있으니 비공개 Nix 클로저를 공개 접근 가능한 S3 버킷에 올려도 괜찮다는 조언을 받았음
불편해서 결국 다른 방식을 택했지만, URL 안에 “비밀”이 있는 것과 URL 요청 시 제출하는 토큰 안에 비밀이 있는 것이 실제로 얼마나 다른지 계속 생각하게 됨
내 결론은 토큰은 고객별로 발급할 수 있고, 접근 로그를 감시해 수상한 행동을 보고 폐기할 수 있다는 데 있음
또 다른 사람들이 말했듯 파일명 목록을 비밀로 유지하는 일을 얼마나 중요하게 보는지에 대한 사고방식도 다름
Amazon이 실수할 수 있는 일의 규모에서, 공개 버킷의 파일명 목록을 우연히 노출하는 건 사용자 99%가 신경 쓰지 않을 일이어서 우선순위가 낮아 보임 - 예전에 일하던 회사가 고객사와 작업하다가 S3 버킷 이름 충돌을 겪었는데, 양쪽 모두 hyphenated-company-name이 좋은 S3 버킷명이라고 생각했던 것으로 드러남
당연히 우리 회사가 그 경쟁에서 졌음
그 뒤로 AWS를 할 때마다 버킷 이름은 보통 - 형태로 짓게 되는 작은 교훈이 됨
정말 비공개여야 한다면 프로젝트명도 암호화하고, “친숙한” 이름으로 버킷을 나열하는 스크립트를 제공하면 됨
호스팅 서비스에는 늘 이상한 절충이 있어서, 기술적으로 완벽한 방식인 완전 무작위 식별자는 불완전한 방식인 설명적 이름보다 운영 부담이 훨씬 커질 가능성이 높음 - 비밀번호가 들어간 비공개 링크와, 링크로 이동한 뒤 비밀번호를 입력하는 사이트 사이에 차이가 있는지 궁금함
Bitwarden Send는 다른 사람에게 전달할 수 있는 링크를 만들고,#뒤에 긴 무작위 문자열이 붙음
정기적으로 쓰고 있어서 보안 문제가 있는지 알고 싶음
적어도 링크는 폐기할 수 있고 며칠 뒤 자동 만료도 가능한데, 일반적인 비밀번호는 보통 그렇게 동작하지 않음
- 문제는 링크가 새어 나간다는 것임
-
비공개 공유 링크를 만들려면 URL의 해시 부분에 비공개 값을 저장하면 됨
해시는 DNS 질의나 HTTP 요청으로 전송되지 않음
예를 들어 links.com?token=에 방문하면 그 링크는 검색 매개변수까지 포함해 전송되고 Cloudflare 같은 중간자에 저장될 수 있음
반면 links.com#에 방문하면 해시 부분은 브라우저 밖으로 나가지 않음
해시 부분의 데이터를 다룰 때는 URL Safe Base64 문자열로 인코딩하면 편리함
즉 JS Object ↔ JSON String ↔ URL Safe Base 64 String 흐름임- HTTPS를 쓴다면 매개변수 문자열과 경로도 암호화되므로, 그 비밀을 읽으려면 해당 중간자가 트래픽을 복호화할 수 있어야 함
나머지는 맞고, 다만 이 HTTPS 암호화 nuance를 덧붙이고 싶었음 - 큰 단서가 있음: 그 페이지에서 실행되는, 겉보기엔 무해한 JavaScript도 프래그먼트를 인터넷 어디로든 보낼 수 있음
프래그먼트에 넣는 건 도움이 되지만 완벽하지 않음
이상론으로만 하는 말이 아니라, 실제로 프래그먼트에서 비공개 토큰이 이런 식으로 유출되는 걸 여러 번 봄 - 내가 모르는 DNS 기능이 있어서 도메인 부분보다 더 많이 질의하는 건가?
[https://example.com?token=](<https://example.com?token=<secret>>)는 “example.com”만으로 DNS 질의가 나가야 함 - 이 문제를 해결하는 방법을 생각해보면, 특히 이메일 기반 로그인이나 계정 재설정이 떠오름
이메일 안의 링크를 따라가는 봇들이 JavaScript를 실행하나? JavaScript가 유도한 POST로 실제 동작을 활성화할 위험이 있나? - 참고로 그건 fragment라고 부름
- HTTPS를 쓴다면 매개변수 문자열과 경로도 암호화되므로, 그 비밀을 읽으려면 해당 중간자가 트래픽을 복호화할 수 있어야 함
-
빠른 리다이렉트 루프 일부가 아닌 링크는 공유를 위해 복사·붙여넣기될 수밖에 없음
URL은 원래 그런 용도이고, 보편적이며, 어떤 프로토콜에서 제공되는 리소스에 접근하기 쉽게 해줌
수명이 짧지 않은 것에 대한 접근 제어는 URL 바깥에서 해야 함
종단 간 암호화가 아닌 채널에서 링크를 공유하면, 그 URL에 처음 접근하는 주체는 받는 사람이 아니라 채널 서비스임
Bitwarden이 사용자 경험을 위해 파비콘을 찾는 것처럼 정당할 수도 있고, Facebook Messenger 크롤러가 비공개 메시지에서 무엇을 공유하는지 더 알고 싶어 하는 것처럼 악의적일 수도 있음
이런 스캐너 도구들은 사용자 경험이 더 좋아지지 않을 것임
스캔 결과가 공개된다고 명시하면 일부 사용자는 서비스를 쓰기 전에 다시 생각할 테고, 무료 사용자든 프로 라이선스 사용자든 사업에는 나쁘기 때문임 -
무제한 사용 가능한 “비공개” 링크는 늘 좀 의심스러웠음
결국 모호성에 의존하는 보안임
Google 문서 같은 걸 공유할 때는 적어도 “URL이 있는 모든 사람이 접근 가능”이라고 명시하는 옵션이 있음
내가 만든 시스템에서 이런 유형이 필요할 때는 보통 수명이 몇 분뿐인 서명된 URL을 썼음
URL은 대체로 구현 세부사항이고 사용자에게 직접 보여주지 않지만, 브라우저 디버그 화면에서는 볼 수 있을 가능성이 있음- 키 공간이 충분히 크다면 비공개 링크와 사용자명·비밀번호 또는 API 키로 보호된 링크 사이에는 기능적으로 차이가 없음
- Google 문서 공유는 아쉽게도 문서 ID 기반이라, 새 URL로 접근 권한을 다시 활성화할 수 없음
-
인터넷에서 이런 것이 URL 안의 무작위 문자열 말고는 보호되지 않는다면, 실제로는 비공개가 아님
찾아보면 나오는 인터넷 연결 웹캠들과 같은 이야기임
이건 이미 알고 있던 것 아닌가? 왜 “누가 책임자인가” 섹션에서 이 점을 전혀 다루지 않는지 모르겠음- 이런 링크는 “사용 사례에 맞는 보안이면 충분하다”는 맥락에서 매우 유용함
모든 것에 최고 수준의 보안이 필요한 건 아니고, 어떤 경우에는 광범위한 공유를 막는 장벽만 있으면 됨
예를 들어 사진 갤러리에서 “링크 공유 만들기”를 눌러 사진 링크를 누군가에게 보내면, 그 사람이 비밀번호를 입력하길 원하지 않음
링크를 열면 사진이 보여야 하고, 그 용도라면 괜찮음
여기 예시 중 하나가 정확히 그런 경우이며, 그 사용 사례에는 맞음
프라이버시 우려 측면에서도 로그인 절차가 있더라도 최종 사용자는 그 시점에서 스크린샷을 다시 공유할 수 있음
보안이 사용 사례에 맞는 셈임
사용자가 이제 사진 링크를 갖고 있고 다시 공유할 수도 있지만, 의도적으로 그러지 않을 것이라고 믿는 상황임
여기서 큰 문제는 링크 자체라기보다, 보안 분석 도구가 사용자가 이메일로 받은 모든 링크를 스캔하고 그 커뮤니티의 다른 사용자에게도 접근 가능하게 만든다는 점임
내가 누군가에게 사진을 보낼 때 의도한 것보다 훨씬 더 큰 재공유임
- 이런 링크는 “사용 사례에 맞는 보안이면 충분하다”는 맥락에서 매우 유용함
-
이 이메일 기반 인증 문제의 우회책은, 비밀번호 계정 생성까지 가지 않고 임시 일회용 코드를 쓰는 것임
그러면 URL이 실수로 공유되어도 크게 문제가 되지 않음- 사용자가 “비공개” 링크를 방문함, 또는 이메일을 다시 입력하는 공개 링크여도 됨
- 사이트가 시간 제한이 있는 일회용 코드를 사용자에게 다시 이메일로 보냄
- 사용자가 임시 코드를 입력해 이메일 소유권을 확인함
- HTTP 쿠키나 세션 데이터로 흐름을 이어가며, 이메일 계정 소유자가 관여했다는 합리적 확신을 얻음
-
주제에서 벗어나지만, 링크가 Cloudflare Radar로 이어지는데 이 서비스는 apparently 1.1.1.1 데이터를 채굴하는 것처럼 보임
1.1.1.1은 사용자 데이터를 어떤 목적으로도 쓰지 않는다고 알고 있었음- Cloudflare가 그 데이터를 판매하거나 마케팅에 쓰지는 않지만, 애초에 그 주소를 얻은 방식 자체가 APNIC이 1.1.1.1로 들어오는 잡음 트래픽을 연구하고 싶어 했기 때문임
-
더 똑똑한 사람이 설명해주면 좋겠음. 다음 둘은 무엇이 다른가?
- domain.com/login user: John password: 5 char random password
- domain.com/12 char random url
둘 다 같은 무차별 대입 방지나 속도 제한이 있거나, 둘 다 없다고 가정하면 왜 1이 2보다 더 안전한가?
- 정보 이론 관점에서는 차이가 없음
실제로는 차이가 있음
소유 기반 비밀과 지식 기반 비밀은 다름
URL은 가진 것이라 접근 가능한 곳에 남겨두면 빼앗길 수 있음
비밀번호는 알고 있는 것이고, 잘 관리하면 빼앗기지 않음. 단, 납 파이프 공격은 예외임
또 하나는 생체 기반으로, 망막이나 지문 스캔이 여기에 들어감 - 이 글 자체가 그 이유임
(1)은 인증을 위해 별도 경로의 정보가 필요하고, 사람들이 안전하게 보관하는 데 익숙한 정보임
반면 (2)의 URL은 URL로 취급됨
URL은 자주 로그로 남고, 기록되고, 공유되고, 여기저기 전달됨
예를 들어 회사 방화벽이 어떤 서비스에 로그인할 때 쓴 사용자명과 비밀번호를 기록한다면 명백히 나쁘지만, 접근한 URL을 기록하는 건 괜찮아 보일 가능성이 큼
후자는 예시일 뿐이며, TLS의 종단 간 보장 때문에 둘 다 접근 가능하면 안 됨 - 두 가지가 있음
- “비밀번호”라는 단어는 사람들이 아무 데나 붙여넣을 가능성을 낮추는 마법 같은 단어임
- 사용자명과 비밀번호는 보통 동시에 복사·붙여넣기되지 않고, 서로 나란히 저장되는 표준적인 방식도 없는 두 개의 분리된 정보임
- 이 글의 맥락에서는, 회사나 사용자가 쓰는 보안 스캔 소프트웨어가 이메일 안의 12자 링크 일부를 색인하고, 경우에 따라 공개 스캔 결과에 올려버린다는 점이 다름
추가로 domain.com/12-char-password가 HTTPS 없이 요청되면 리다이렉트가 있더라도 최초 요청은 암호화되지 않은 채 전송되어 중간자 공격이 가능함
반면 로그인 페이지는 비밀번호 제출이 반드시 HTTPS에서만 일어나도록 보장할 방법이 더 많음 - 예전에 인증 토큰을 질의 매개변수로 넣어도 되는지 궁금해서 조사한 적이 있음
큰 문제 중 하나는 많은 로깅 애플리케이션이 전체 URL을 어딘가에 기록한다는 점이고, 그러면 사실상 “비밀번호”를 로그에 남기게 됨
-
비공개 airtable.com 앱에 올리는 모든 미디어와 사진은 공개 링크임
URL을 알면 인증 없이 접근 가능함- CDN이나 API에서 이미지를 불러오는 웹 개발자에게는 딜레마가 있음
일반 이미지 태그는 API 요청에서 fetch()로 하듯 요청에 토큰이 든 Authorization 헤더를 설정할 수 없음
가능한 선택지는 URL에 토큰을 추가하거나 쿠키 인증을 쓰는 것뿐임
쿠키 인증은 CDN이 같은 도메인에 있을 때만 동작하고, 서브도메인조차 많은 경우 문제가 될 수 있음 - CDN을 쓰는 앱에서는 airtable만이 아니라 꽤 흔한 방식임
잠재적으로 문제가 될 수 있다는 데 동의함
- CDN이나 API에서 이미지를 불러오는 웹 개발자에게는 딜레마가 있음
-
Zoom 회의 링크는 비밀번호를 질의 매개변수로 붙이는 경우가 많음
이 링크는 “비공개 보안” 링크인가? 비밀번호가 빠진 링크는 “비공개 보안” 링크인가?- 비밀번호가 회의마다 무작위라면 URL 링크도 그리 나쁘지 않음
URL이 다른 곳에 나타날 즈음이면 그 회의는 이미 끝나고 사라졌을 것이기 때문임
하지만 현실에서는 아무도 신경 쓰지 않고, 이것저것 입력하지 않아도 되는 “클릭해서 참여”를 원함
이전의 “회의 ID만 쓰기” 방식은 너무 쉽게 추측 가능했음
- 비밀번호가 회의마다 무작위라면 URL 링크도 그리 나쁘지 않음