탭에는 터널이 끊기기 전의 대시보드가 아직 표시되어 있습니다. 상태 숫자는 멈추고, 작은 스피너는 계속 돌아가고, 주소 표시줄에는 한 시간 전에 연 앱이 그대로 남아 있습니다. 끊긴 뒤 아무것도 건드리지 않았는데도 페이지는 여전히 자체 일정에 따라 서버에 닿으려고 할 수 있습니다. 사람들이 놓치는 부분이 바로 이것입니다. 단지 보이는 페이지만과 여전히 요청을 보내는 페이지는 밖에서 보면 똑같아 보이고, 네트워크 로그에 나타나는 것은 둘 중 하나뿐입니다.

페이지가 당신 없이 시작하는 작업

네 가지 메커니즘이 로드된 문서를 계속 바쁘게 만듭니다. 반복 타이머는 몇 초마다 상태 호출을 다시 실행할 수 있습니다. 탭으로 돌아온 뒤 탭이 다시 보이게 되면 fetch가 실행될 수 있습니다. WebSocket이나 서버 전송 이벤트로 만든 라이브 채널은 자체 백오프 일정에 따라 재연결을 시도할 수 있습니다. 사이트가 등록한 서비스 워커는 앞에 탭이 없어도 대기 중인 동기화를 위해 깨어날 수 있습니다.

그중 어느 것도 클릭이 필요하지 않고, 어느 것도 문서를 다시 로드하지 않습니다. 주소 표시줄, 스크롤 위치, 렌더링된 값은 모두 그대로입니다. 변하는 것은 네트워크 쪽뿐입니다. 새 시도 각각은 그것이 시작되는 순간 내려진 새로운 결정입니다.

이 구분이 중요한 이유는 보이는 페이지가 로컬에 저장되기 때문입니다. 이미 그려진 픽셀은 다음 요청이 성공했는지에 대해 아무것도 말하지 않습니다. 스피너가 있는 멈춘 차트는 지금 요청이 실패하고 있는 페이지의 평범한 모습입니다. 화면을 읽으면 서버가 몇 분 전에 말한 것을 알 수 있을 뿐, 브라우저가 지금 무엇을 하는지는 알 수 없습니다.

이전 페이지 로드가 경로를 유지하지 못하는 이유

페이지 로드의 어떤 것도 문서를 터널에 묶지 않습니다. 라우팅은 패킷마다, 전송 시점에, 패킷이 나갈 때 존재하는 테이블에서 해석됩니다. 터널 인터페이스가 사라지면 그 조회는 더 이상 터널 경로와 일치하지 않습니다. 물리 어댑터로 떨어지거나 아무것도 찾지 못합니다. 클라이언트가 무엇을 남겼는지에 따라 다릅니다.

반복 콜백은 평범한 예약 작업입니다. HTML 표준의 타이머 절은 그것들이 어떻게 큐에 들어가는지 설명하고 간격을 정확한 주기의 약속이 아니라 최소 지연으로 취급합니다. 그래서 백그라운드 탭은 코드가 요구하는 것보다 훨씬 드물게 폴링할 수 있습니다. 시도가 적은 것은 시도가 없는 것과 같지 않으며, 탭을 다시 앞으로 가져오는 것은 그것들이 몰려 나오는 흔한 순간입니다.

실패 정책이 어디에 떨어지는가

클라이언트의 차단은 페이지를 가져올 때가 아니라 연결을 시도할 때 평가됩니다. 일반 접근이 여전히 허용되면 재시도는 물리 링크를 통해 평문으로 나갈 수 있습니다. 정책이 터널이 돌아올 때까지 그 트래픽을 붙잡으면 시도는 연결 시점에 실패하고 페이지는 몇 초 뒤 다시 시도할 수 있는 오류를 표시합니다.

둘 중 무엇을 얻을지는 두 가지 세부 사항이 결정합니다. 첫째는 클라이언트가 지원하는 적용 범위입니다. 기기 전체 차단, 터널 어댑터로 제한된 차단, 예외가 있는 규칙 집합 중 하나입니다. 둘째는 목적지가 이전에 로컬 프린터, 캡티브 포털, 스트리밍 서비스를 위해 추가한 예외 안에 들어가는지입니다.

응용 프로그램 수준 암호화는 이것을 바꾸지 않습니다. HTTPS는 브라우저와 서버 사이의 바이트를 보호하지만, 어느 인터페이스가 그것을 나르는지는 말하지 않습니다. 페이지는 완벽하게 암호화되어 있어도 잘못된 경로로 나갈 수 있고, 좁은 차단이 허용하는 것이 바로 그것입니다.

일회용 페이지로 하는 통제된 확인

직접 관리하는 호스트와 그것을 호출하는 것 외에는 아무것도 하지 않는 페이지를 사용해 실제 데이터가 개입되지 않게 합니다. 터미널에서 끊기기 전과 후에 경로를 샘플링합니다.

curl -sS --max-time 5 -o /dev/null -w '%{http_code} %{remote_ip}\n' https://probe.example.net/ping

터널을 올린 상태에서 실행하고, 그다음 터널을 내린 뒤 다시 실행합니다. 터널이 내려간 동안 공인 주소에서 응답이 오면 직접 경로가 열려 있다는 뜻입니다. 시간 초과나 거부된 연결은 정책이 붙잡고 있다는 뜻입니다. 클라이언트가 재연결한 뒤 한 번 더 반복해, 당연하게 여기지 말고 터널 경로가 돌아오는 것을 확인합니다.

브라우저에서는 네트워크 패널이 두 질문을 분리합니다. Fetch/XHR로 필터링한 다음 개시자 열을 읽습니다. 타이머나 스크립트가 시작했고 그 앞에 탐색이 기록되지 않은 항목은 다시 로드가 아니라 백그라운드 시도입니다. 그 시작 시간을 터널이 끊긴 순간과 비교합니다. 터널이 사라졌는데 항목이 아직 대기 중이라면, 요청은 더 이상 존재하지 않는 경로를 기다리고 있습니다.

서버 측 증거가 브라우저가 보여주는 무엇보다 강합니다. 타임스탬프와 출발지 주소가 있는 요청 로그는 패킷이 도착했음을 증명합니다. 브라우저 항목은 쿠키, 토큰, 전체 URL을 담을 수 있으므로 질문에 필요한 필드만 남기고 나머지는 어디에 붙여 넣기 전에 가립니다.

답을 어떻게 쓸 것인가

터널이 내려간 동안 백그라운드 시도가 계속 성공한다면 차단은 생각보다 좁고, 그 틈은 민감한 작업을 클라이언트에 맡기기 전에 닫을 가치가 있습니다. 실패한다면 정책이 제 일을 하고 있는 것이며 멈춘 페이지는 겉모습일 뿐입니다. 어느 쪽이든 탭 하나를 닫는 것은 기기 전체의 통제가 아닙니다. 다른 탭, 다른 브라우저, 다른 앱은 각자 자기 작업을 예약합니다.

해 볼 만한 다음 단계는 추가한 예외와 그 이유를 나열하고, 클라이언트가 터널 범위의 트래픽만 차단하는지 모든 트래픽을 차단하는지 확인하고, 서버 로그를 열어 둔 채 백그라운드 요청 하나를 처음부터 끝까지 지켜보는 것입니다. 그 세 가지 답이 «VPN이 끊겼는데 뭔가 계속 연결되어 있다»는 보고서의 실제 내용 대부분을 덮습니다.

관련 글