운영이 Slack 채널에 일회용 링크를 붙입니다. 카드가 먼저 뜨고, 제목은 사이트 이름입니다. 십 분 뒤 받는 사람이 열면 페이지는 「이 비밀은 삭제되었습니다」로 바뀝니다. 양쪽 모두 평문을 읽지 않았다고 생각합니다. 서버에 먼저 도착한 것은 동료의 손가락이 아니라, 메신저가 미리보기용으로 보낸 GET인 경우가 많습니다.

앞글 동료에게 비밀번호를 한 번만 넘길 때 복호화 키를 왜 # 뒤에 두는가는 「암호문을 맡긴 HTTP 서비스가 키를 보느냐」였습니다. 이번 질문은 바꿉니다. 사람이 아직 누르지 않았는데, 미리보기가 읽기 한 번을 먼저 쓰느냐. 키는 여전히 # 뒤에 있습니다. 만들기와 읽기 모두 가입이 없습니다. MyPassGen 일회용 링크는 열면 바로 쓰고, 읽기 횟수 기본값은 1, 상한은 10입니다. 버튼을 어떻게 누르는지는 적지 않습니다. Network, 주소창, 채팅창에서 보이는 것만 대조합니다.

먼저 두 가지를 나누세요

미리보기가 암호문을 태우는지와, 채팅 기록에 전체 URL이 남는지는 다른 질문입니다. HTML만 가져가고 페이지 스크립트를 돌리지 않는 미리보기는 보통 # 뒤 키를 못 읽고, 암호문을 가져가는 인터페이스에도 닿지 않습니다. 단톡이나 채널에는 s.html?id=…#… 문자열이 그대로 남습니다. 복사한 사람은 아직 열 수 있습니다. 미리보기가 안 태웠다고 해서, 링크가 자격 정보가 아니게 된 것은 아닙니다.

상대는 이미 삭제됐대요. 나는 안 열었어요

일회용 링크의 흔한 설계는 이렇습니다. 암호문을 처음 가져가면 서버가 그 사본을 지웁니다. 읽기 횟수가 1이면 그 한 번이 마지막입니다. 보낸 쪽의 「만들기 성공」과 받는 쪽의 삭제 상태 사이에는, 사람이 누르지 않은 방문이 끼어들 수 있습니다. 채널 미리보기, 메일 보안 검사, 회사 게이트웨이가 주소를 바꾼 뒤 다시 찔러 보는 경로입니다.

Slack은 이 동작을 제품 문서에 적었습니다. Unfurling links in messages에는, 메시지에 링크를 붙이면 Slack이 그 페이지를 가져와 미리보기를 붙인다고 나옵니다. 공식 robots 페이지는 이 가져가기를 하는 봇을 Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)이라 부르고, 가능한 한 적게 가져간다고 적습니다. HTTP Range를 쓰고, 목적은 oEmbed, Twitter Card, Open Graph 같은 메타 태그를 뽑는 것입니다. 태그가 이미지·음성·영상을 가리키면 검증을 위해 그 파일도 가져갑니다. Slack Robots는 같은 URL 응답을 서비스 안에서 약 30분 캐시한다고 쓰고, robots.txt로 자신을 막지 않는다고 합니다. 검색엔진처럼 사이트를 훑는 것이 아니라, 이용자를 대신해 요약을 가져간다는 입장입니다.

따라서 「채널에 카드가 떴다」가 증명하는 것은 하나입니다. 받는 사람이 아닌 기계가, 붙인 URL로 HTTP 요청을 적어도 한 번 보냈다. 평문을 읽었다는 증거가 아닙니다. 암호문이 읽기 횟수에 들어갔다는 증거도 아닙니다. 태웠는지를 보려면, 그 요청이 어느 층에 닿았는지를 봐야 합니다.

미리보기가 보내는 URL은 어디까지인가

복사하는 전체 링크 형태는 …/s.html?id={id}#{key}입니다. 물음표 뒤 id는 HTTP 요청 줄에 들어갑니다. 우물정자 뒤 키는 프로토콜상 클라이언트에 남습니다. 근거는 RFC 3986 §3.5와 RFC 9110 §7.1입니다. 대상 URI는 fragment를 빼니다. 이 조각은 클라이언트가 처리합니다. 미리보기 봇이 내는 것은 평범한 HTTP GET이고, 요청 줄에 올 수 있는 것은 GET /ko/s.html?id=…까지입니다. 우물정자 뒤 키는 암호문을 맡긴 기계에 도착하지 않습니다.

HTML만 가져가는 미리보기가 보통 평문을 풀지 못하는 이유도 여기 있습니다. 읽기 페이지가 복호화하려면, 브라우저 스크립트가 location.hash를 읽고, 서버에 암호문을 요청한 뒤, 이 기기에서 AES-256-GCM으로 풀어야 합니다. 미리보기 크롤러에게는 우물정자 뒤 키가 없고 번호만 있습니다. s.html HTML 전체를 저장해도 그 안에 비밀번호 원문은 없습니다. 읽기 페이지는 noindex 착륙 페이지입니다. 초기 HTML의 제목은 「일회용 링크 · MyPassGen」뿐입니다. 평문은 스크립트가 끝난 뒤에야 페이지에 쓰입니다.

메신저가 저장하는 것은 다른 물건입니다. 이용자가 붙인 것은 우물정자와 키를 포함한 문자열 전체입니다. 채널 검색, 메시지 동기화, 다른 휴대폰에서 같은 방을 다시 열면 전체 자격 정보가 돌아옵니다. 키를 # 뒤에 두는 일은 미리보기 GET과 일반적인 서버 로그에서 키를 빼는 것입니다. 단톡 기록에서 전체 링크를 지워 주지는 않습니다. 더 민감한 인계는 번호와 키를 두 통로로 나눕니다. 뒤에서 적습니다.

가져가기는 세 종류, 횟수에 들어가는 것은 하나

RFC 9110은 GET을 안전한 메서드로 둡니다. 보내도 파괴적인 부작용이 없어야 한다는 뜻입니다. 카드만 그리려고 페이지를 GET하는 일은, 그 의미에서는 암호문을 지워서는 안 됩니다. 실제 일회용 도구가 「문서에 대한 첫 GET」을 읽기로 치면, 미리보기 봇이 받는 사람보다 먼저 내용을 태웁니다. 차이는 메신저 이름이 아닙니다. 횟수를 어느 요청에 묶었느냐입니다.

실행 능력으로 세 층으로 나눕니다. 첫째는 첫 화면 HTML만 가져가 <title>과 Open Graph를 읽고, 페이지 스크립트는 돌리지 않습니다. Slack 공식 Link Expanding 설명이 여기 들어갑니다. 메타 태그를 뽑고, 필요하면 태그가 가리킨 미디어를 가져갑니다. Apple Ensuring Beautiful Rich Links는 리치 링크를 만들 때 JavaScript를 돌리지 않으니 Open Graph를 페이지 소스에 쓰라고 합니다. Discord 채널 임베드도 흔한 구현은 Discordbot/2.0이 초기 HTML을 읽는 것이지, 완전한 브라우저 엔진을 여는 것이 아닙니다.

둘째는 페이지 스크립트는 돌리지만, 요청에 fragment가 없습니다. 헤드리스 브라우저, 일부 기업 검사 샌드박스가 여기입니다. 읽기 페이지 JavaScript는 실행할 수 있어도 location.hash는 못 읽습니다. 이 사이트에서는 키가 없으면 암호문을 가져가지 않습니다. 페이지는 「링크가 불완전합니다」에서 멈추고, 읽기 횟수는 늘지 않아야 합니다.

셋째는 스크립트를 돌리고, 우물정자까지 포함한 전체 URL을 진짜 페이지 환경에 올립니다. 누르기 직전 링크를 기기 WebView로 여는 일부 보안 소프트웨어, 보낸 기기에서 페이지를 통째로 로드하는 미리보기는 「암호문을 가져와 횟수를 올린」 단계까지 갈 수 있습니다. 이 층은 프로토콜로 막을 수 없습니다. 같은 통로에서 시험용 링크로 재현하는 수밖에 없습니다.

슬랙, 카카오톡, 메일 게이트웨이의 차이

Slack이 가장 대조하기 쉽습니다. 공식 robots가 User-Agent를 공개합니다. 같은 문자열로 읽기 페이지를 요청해, 응답이 정적 HTML인지, 이후 읽기 횟수가 움직였는지를 볼 수 있습니다. 약 30분 전역 캐시도 적혀 있습니다. 짧은 시간에 같은 URL을 여러 채널에 붙여도, 매번 원본 서버로 다시 가진 않습니다. 카드의 사이트 제목은 메타 태그 또는 <title>을 읽었다는 뜻뿐입니다. 한국어 읽기 페이지 기본 제목은 「일회용 링크 · MyPassGen」입니다. 시험 문장 원문은 들어 있지 않습니다.

국내 일상 채팅은 카카오톡이 먼저 나옵니다. 카카오 스크랩은 Open Graph를 읽어 링크 카드를 그립니다. 개발자 문서와 데브톡은 스크랩봇 User-Agent를 facebookexternalhit/1.1;kakaotalk-scrap/1.0으로 안내하고, 방화벽에서 스크랩 서버 대역을 막으면 미리보기가 실패한다고 적습니다. 근거는 카카오 데브톡 스크랩 안내와 카카오디벨로퍼스 방화벽입니다. Slack처럼 「스크립트를 돌리지 않는다」를 계약서처럼 읽을 공식 robots 페이지는 없습니다. 그 자리에서 확인할 수 있는 것은 두 가지입니다. URL을 붙인 뒤 제목 카드가 뜨는지, 받는 사람이 연 뒤 읽기 페이지가 복호화인지·불완전한지·이미 삭제인지. 메신저 카드를 만드는 흔한 구현은 서버가 HTML 제목과 요약을 가져가는 것이지, 받는 사람 휴대폰에서 읽기 페이지 스크립트를 먼저 돌리는 것이 아닙니다. 공개 규격이 없을 때는 이 시험용 링크의 결과를 믿으세요. 「카드가 떴다」를 「암호문을 가져갔다」와 같은 말로 두지 마세요.

중국 쪽 팀과 넘길 때는 위챗도 같은 확인이 됩니다. 이쪽도 Slack형 공식 robots는 없습니다. 카드가 뜨는 것과, 전체 링크를 다시 열었을 때의 상태를 따로 봅니다.

회사 메일은 세 번째 길입니다. Microsoft Safe Links 개요는 수신 메일을 검사하고 URL을 바꿀 수 있으며, 클릭 때 다시 검증한다고 적습니다. 바뀐 주소는 safelinks.protection.outlook.com 같은 접두사를 답니다. 배달 때 검사와 클릭 때 리다이렉트 모두 대상에 GET을 한 번 더 보낼 수 있습니다. 볼 곳은 두 군데입니다. 본문이 이미 포장됐는지. 클릭 뒤 주소창에 # 뒤가 남았는지. 바꾸기나 리다이렉트에서 키가 떨어지면 읽기 페이지는 「링크가 불완전합니다」여야 하고, 평문은 나오면 안 됩니다. 우물정자까지 포함한 전체 URL이 스크립트를 돌리는 샌드박스에 올라가면 횟수는 늘 수 있습니다. 「모든 게이트웨이가 HTML만 본다」고 가정하지 마세요. Microsoft Teams 채널 링크도 Safe Links를 탈 수 있습니다. 정책은 테넌트마다 다릅니다.

읽기 페이지가 실제로 보내는 요청

MyPassGen 읽기 페이지가 열리면 스크립트는 순서대로 두 가지를 합니다. 먼저 번호로 상태를 묻습니다. 이 요청은 아직 있는지, 이미 삭제됐는지, 만료인지만 답하고, 읽기 횟수는 올리지 않습니다. # 뒤에 키가 없으면 여기서 멈추고, 페이지는 링크가 불완전하다고 합니다. 키가 있으면 이어서 암호문 GET을 냅니다. 횟수를 올리는 것은 이 요청입니다. read_count가 정한 상한(기본 1, 최대 10)에 닿으면 서버가 암호문을 지웁니다. 다음에 열면 삭제 상태입니다. 기한은 만들 때 고른 TTL을 따릅니다. 1시간, 24시간, 7일, 또는 횟수만 보고 TTL 없음입니다.

따라서 s.html?id=…만 GET하는 미리보기와, 상태 인터페이스만 치는 검사는 그 한 번을 쓰지 않습니다. 횟수를 쓰는 것은 「키를 이미 가진 읽기 페이지 스크립트」가 내는 암호문 요청입니다. 만들 때 브라우저는 이 기기에서 AES-256-GCM으로 암호화하고, IV는 12바이트, 평문 상한은 32KB입니다. 서버가 맡는 것은 암호문뿐입니다. 키는 HTTP 요청 줄에 안 들어갑니다. 알고리즘과 「평문이 올라가지 않았는지」 확인은 브라우저에서 암호화할 때, 평문이 올라가지 않았는지 그 자리에서 확인하는 방법에 있습니다.

읽기 페이지에 따로 「열기」 버튼은 없습니다. 키가 갖춰지면 탭을 연 시점에 암호문을 가져갑니다. 이는 「미리보기 크롤러는 HTML만 가져간다」와 모순되지 않습니다. 그 크롤러는 보통 암호문 단계까지 가지 않습니다. 모순이 나는 것은 셋째 가져가기입니다. 전체 URL이 스크립트를 돌리는 환경에 올라갔을 때입니다. 그때는 사람이 탭을 연 것과 같고, 기본 1회 링크는 소진됩니다. 카드 모양으로는 층을 가릴 수 없습니다. 다음 절처럼 상태를 보세요.

미리보기가 안 태워도, 방 기록은 자격 정보입니다

Slack 채널, 카카오톡 단톡, 위챗 채팅, 메일 스레드에 남은 전체 링크는 아직 자격 정보입니다. 평문까지 한 단계가 더 있을 뿐입니다. 그 메시지를 검색할 수 있는 사람은 삭제되기 전에 열 수 있습니다. 시크릿 창을 닫아도 북마크나 다운로드에 남은 전체 URL은 사라지지 않습니다. 경로는 시크릿 창을 닫아도 다운로드, 북마크, 클립보드의 비밀번호는 남는다에 있습니다.

미리보기 뒤에 남는 것

같은 시험용 링크, 읽기 횟수 1로 두었을 때, 미리보기 뒤 보낸 사람과 받는 사람이 보는 것은 같지 않습니다. 표는 열 수 있는 페이지로 씁니다. 제품 구호로 쓰지 않습니다.

일어난 일 채팅창에서 흔히 보이는 것 전체 링크를 다시 열면
HTML 메타만 가져가고 스크립트는 안 돌림 제목 카드. 시험 문장 원문은 없음 시험 문장을 아직 복호화할 수 있음
스크립트는 돌렸으나 요청에 #가 없음 카드 또는 빈 미리보기. 서버에는 상태 조회만 아직 복호화됨. 키 없는 쪽은 불완전하다고 해야 함
전체 URL이 스크립트를 돌리는 환경에 올라감 카드 또는 검사 보고. 읽기 횟수는 이미 쓰임 이미 삭제 또는 만료. 원문 없음
메일 게이트웨이가 URL을 바꿔, 이동 뒤 fragment를 잃음 본문이 safelinks… 같은 포장 주소 링크가 불완전함. 암호문은 보통 남아 있음

네 번째 줄과 세 번째 줄을 섞지 마세요. 키를 잃으면 받는 사람은 못 열고, 보낸 사람은 원래 전체 링크로 아직 열 수 있습니다. 횟수는 안 쓰였고, 상대가 받은 조각만 짧은 것입니다. 키는 있는데 페이지가 이미 삭제면, 미리보기나 검사가 먼저 읽은 것입니다. 전자는 우물정자 뒤를 다시 보내면 됩니다. 후자는 새로 만들어야 합니다. 서버에 평문 백업은 없고, 고객 메일로 되찾을 수도 없습니다.

그 자리에서 확인하기

아래 단계는 어떤 브랜드 약속도 전제로 두지 않습니다. 처음부터 끝까지 실제 계정에 로그인하지 않는 시험 문장을 씁니다. 예: orange-lake-7. 지금 쓰는 마스터 비밀번호, 운영 키, 실제 일회용 링크로 연습하지 마세요.

  1. 일회용 링크를 엽니다. 시험 문장을 넣고, 만료는 24시간, 읽기 횟수는 1로 둡니다. 링크를 만든 뒤 전체 주소를 적고, 형태가 s.html?id=…#…인지 확인합니다. 열면 바로 씁니다. 가입은 없습니다.
  2. 우물정자 앞만 따로 복사합니다. 터미널에서 이 주소로 Slack User-Agent를 붙여 한 번 요청합니다. 예: curl -A "Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)" "https://mypassgen.com/ko/s.html?id=…". 카카오톡을 대조하려면 User-Agent를 facebookexternalhit/1.1;kakaotalk-scrap/1.0으로 바꿉니다. 응답은 읽기 페이지 HTML이어야 하고, 제목이나 본문에 시험 문장이 있으면 안 됩니다. 이 단계는 「문서만 가져가면 평문을 못 얻는다」만 증명합니다. 실제 채팅을 대신하지는 않습니다.
  3. 브라우저에서 같은 「id만 있고 키는 없는」 주소를 엽니다. 원문이 아니라 링크가 불완전하다고 나와야 합니다. 개발자 도구 Network를 열고 「로그 보존」을 켭니다. 상태 조회는 있어야 하고, 이어지는 암호문 성공 응답은 없어야 합니다.
  4. 바로 전체 링크(# 포함)를 다른 탭에서 엽니다. 시험 문장이 복호화되어야 합니다. 앞 단계에서 이미 탔다면, 구현이나 중간 장비가 「키 없는 방문」도 읽기로 친 것입니다. 여기서 멈추고 실제 내용을 보내지 마세요.
  5. 횟수 1인 시험 링크를 하나 더 만들어, 내가 관리하는 Slack 채널, 카카오톡 나와의 채팅, 또는 시험용 단톡에 전체로 붙입니다. 미리보기 카드가 뜨기를 기다리거나, 카드가 안 뜨는지를 확인합니다. 읽기 페이지는 열지 마세요.
  6. 미리보기가 뜬 뒤, 컴퓨터 브라우저에서 같은 전체 링크를 엽니다. 아직 복호화되면 그 통로의 미리보기는 앞의 두 층입니다. 이미 삭제면 셋째 가져가기가 끼었거나, 내 기기 중 하나가 키가 있는 페이지를 미리 연 것입니다. 다시 보내려면 새로 만듭니다. 읽은 뒤에는 비밀번호를 복사한 뒤, 클립보드는 누가 또 읽는가대로 클립보드를 덮어쓰세요. 우물정자가 붙은 주소를 북마크에 넣지 마세요.

회사 메일은 반 걸음 더 합니다. 시험 링크를 자기 업무 메일로 보내, 본문이 Safe Links류로 포장됐는지 보고, 클릭 뒤 주소창에 키가 남았는지 봅니다. 키를 잃으면 「번호는 메일, 키는 전화」로 나눕니다. 태워 버렸으면 횟수를 올리거나 통로를 바꿉니다. MyPassGen은 어느 게이트웨이가 어느 층인지 대신 판정하지 않습니다. 방금 연 창의 결과가 기준입니다.

미리보기가 뜨는 방에 꼭 보내야 할 때

기본 1회는 「상대가 전체 링크를 들고 바로 연 뒤 폐기」에 맞습니다. 채널, 큰 단톡, 카드가 뜨는 메일 목록은 위 절을 시험 링크로 먼저 돌리세요. 미리보기가 횟수를 안 쓰는 것을 확인한 뒤에 실제 내용을 보냅니다. 시험이 이미 탔다면, 횟수를 올린다고 미리보기가 「안전해진다」고 기대하지 마세요. 횟수를 2로 올리면 사람이 한 번 더 열 여유만 생깁니다. 검사기가 매번 스크립트를 돌리면 횟수는 그대로 바닥납니다.

더 안정적인 나눔은 두 통로입니다. 한 메시지에는 s.html?id=…만 보냅니다. 미리보기가 가져갈 수 있는 것은 번호와 일반 제목뿐입니다. 다른 통로—전화, 대면, 다른 메신저 계정—에는 # 뒤만 보냅니다. 반쪽이 없으면 풀리지 않습니다. 이는 사용법이지, 제품이 기본으로 쪼개 주는 것이 아닙니다. 만들기 페이지가 만드는 것은 여전히 전체 링크 하나입니다. 일대일 인계에 맞춥니다.

비밀번호 자체는 이 기기에서 만드세요. 방에 먼저 쓰고 지우지 마세요. MyPassGen 비밀번호 생성의 무작위 모드는 6–128자, 기본 16자입니다. 8자 미만은 약하다고 봅니다. 열면 바로 쓰고, 생성 결과는 업무 데이터로 올라가지 않습니다. 32KB를 넘는 인증서 묶음이나 내보내기 표는 일회용 링크에 억지로 넣지 말고 파일 암호화로 가세요. 브라우저에서 AES-256-GCM 스트림 암호화, 파일 하나 5GB 이하, 출력은 .lock / .enc, 암호는 따로 보냅니다. 클라우드가 맡는 것은 암호문입니다. 파일을 클라우드에 넣기 전에, 평문은 누가 읽을 수 있고 암호는 어느 길로 보내야 하는가를 보세요.

「미리보기 뒤 전체 링크가 아직 복호화되는가」와 「방 기록에 전체 자격 정보가 남았는가」를 두 번 확인하면, 이 글의 질문에 답할 수 있습니다. HTML만 가져가는 미리보기는 보통 이 사이트 일회용 링크를 먼저 태우지 않습니다. 스크립트를 돌리고 #까지 실어 나르는 가져가기는 태웁니다. 카드 자체는 답을 주지 않습니다. 상태와 두 번째 열기가 답을 줍니다.

자주 묻는 질문

슬랙 채널에 미리보기 카드가 이미 떴습니다. 링크는 버린 건가요?

아닙니다. Slack 공식은 Link Expanding이 메타 태그를 뽑고, Range로 페이지를 가능한 한 적게 가져간다고 적습니다. 카드는 읽기 페이지 HTML이 한 번 긁혔다는 뜻뿐입니다. 전체 링크로 한 번 더 여세요. 아직 복호화되면 횟수는 남아 있습니다. 이미 삭제면 새로 만들고, 같은 링크를 새로고침하며 운을 시험하지 마세요.

카카오톡은 Slack처럼 공식 robots 페이지가 없습니다. 어느 문장을 믿나요?

이 시험용 링크의 결과를 믿으세요. 제목 카드가 떴다는 것은 어떤 프로그램이 페이지 제목이나 요약을 읽었다는 뜻입니다. 받는 사람이 열기 전에 본인이 전체 링크로 먼저 엽니다. 아직 원문이면 그 통로의 미리보기는 암호문을 가져가지 않은 것입니다. 이미 삭제면 통로를 나누거나 일대일로 바꾸세요.

읽기 횟수를 2나 3으로 올리면 미리보기를 막을 수 있나요?

암호문을 가져갈 여유만 몇 번 더 남길 뿐입니다. 미리보기를 안전한 메서드로 바꾸지는 않습니다. 검사기가 매번 키를 들고 스크립트를 돌리면 횟수는 그대로 바닥납니다. 먼저 횟수 1인 시험 링크로 미리보기가 앞의 두 층인지 보세요. 불안정한 통로에 꼭 넣어야 하면 그때 횟수를 올리고, 「한 사람이 더 열 수 있다」를 감수하세요.

만들기와 읽기에 가입이 필요한가요? 미리보기 봇도 「읽는 사람」인가요?

가입은 필요 없습니다. 만들기와 읽기 모두 방문객에게 열려 있습니다. 미리보기 봇이 HTML만 가져가면 읽기가 아닙니다. 암호문 GET을 내면 서버는 사람과 구별하지 못하고 횟수를 깎습니다. 읽기 페이지는 받는 사람에게 공개이고, 로그인 문이 없으며, 이미 삭제된 내용을 되찾을 고객 메일도 없습니다.