데스크톱 없이 안드로이드 Chrome 디버깅 — 로컬 프록시로 Origin 검사 우회

데스크톱 없이 안드로이드 기기 한 대로 그 기기의 Chrome을 디버깅한다. Termux에서 파이썬 스크립트를 돌리고, DevTools는 폰 브라우저로 연다.

순서를 기억하려고 적어둔 것이다. 각 단계의 방법이 아니라 밟는 차례가 내용이다.

길이 셋인데 하나만 해봤다. Origin 문제를 없애는 방법이 셋이다 — Chrome을 --remote-allow-origins=*로 띄우거나, 프론트엔드를 localhost에서 self-host하거나, 로컬 프록시로 Origin 검사를 우회하거나. 아래는 프록시 길이고 앞의 둘은 해보지 않았다.

폰 안에는 DevTools 프론트엔드가 없다. 그래서 구글이 호스팅하는 것(chrome-devtools-frontend.appspot.com)을 연다 — 그 순간 프론트엔드의 origin이 appspot.com이 되고, Chrome은 그 Origin이 붙은 CDP WebSocket을 거부한다.1 로컬 프록시(9223)를 사이에 끼워 그 거부를 우회한다.

프론트엔드 WS를 로컬 프록시(9223)가 종단하고, 파이썬이 Origin 없는 새 WS로 9222에 재접속해 Chrome의 cross-origin 거부를 우회하는 구조

연결 경로:

  • adb forward가 Chrome의 chrome_devtools_remote unix socket을 localhost:9222로 연다
  • Chrome이 9222에서 /json으로 탭 목록을, /devtools/page/{id}로 페이지별 CDP WS를 준다
  • aiohttp 프록시가 9223에서 프론트엔드 WS를 받아 9222로 양방향 중계한다
  • termux-open-url이 폰 브라우저로 프론트엔드를 열고, ?ws=localhost:9223/{id}가 백엔드를 가리킨다
adb forward로 소켓을 노출하고 프록시를 띄운 뒤 DevTools 프론트엔드를 실행하기까지의 전체 연결 수명주기

프록시가 하는 일은 중계가 아니라 연결 종단과 재접속이다. 프록시가 프론트엔드 WS를 종단하고, 파이썬 프로세스가 새 WS로 9222에 다시 접속한다. 파이썬이 여는 소켓에는 브라우저가 붙이는 Origin 헤더가 없으니 통과한다. cors_middleware는 프론트엔드 쪽 응답에 허용 헤더를 붙인다.

기억해둘 것:

  • ws://localhost는 HTTPS 페이지에서도 mixed-content로 안 막힌다 — localhost가 secure context로 취급되기 때문. IP나 도메인이었으면 wss 강제로 깨졌을 것이다.
  • ?@f84901f7…는 DevTools 프론트엔드 빌드 리비전 핀이다.

Footnotes

  1. Origin 검사(Chrome 111~)와 DNS rebinding을 막는 Host 헤더 검사(Chrome 66~)는 다른 방어다. 여기 걸리는 건 앞쪽 — WS 핸드셰이크에 --remote-allow-origins에 없는 Origin이 붙으면 거부된다. (Chromium issues)

#565raw