루트 없이 Android VPN: 동의, 경로, 차단은 누구의 것인가
동의, TUN 인터페이스, 시스템의 차단 정책은 서로 다른 세 가지 권한입니다. Android VPN 앱을 검토하기 전에 각각을 어떤 구성 요소가 소유하는지 추적하세요.
루트는 Android VPN 앱이 트래픽을 나르고, 유출을 차단하고, 재부팅 후에도 살아남게 해 주는 것이 아닙니다. 사람들은 이 모든 것을 „앱에 VPN 권한이 있다“로 요약하는데, 그 말은 세 가지 별개의 메커니즘을 감춥니다. 사용자의 동의, 시스템이 설정하는 패킷 인터페이스, 그리고 앱이 정의할 것이 아닌 플랫폼의 차단 정책입니다. Android VPN 설계를 검토한다는 것은 어떤 주장이 실제로 이 셋 중 어디에 기대고 있는지 묻는 일이며, 각각은 소유자도 실패 방식도 다릅니다.
동의는 시스템 액티비티를 통해 온다
VpnService.prepare()는 아무것도 부여하지 않습니다. 동의가 없을 때 시스템 동의 액티비티로 인텐트를 돌려주고, 앱은 그 대화상자를 띄워 사용자가 서비스를 승인하게 합니다. 앱 자체의 프로세스를 시작하거나, 매니페스트에 권한을 추가하거나, 별도의 „VPN 켜기“ 화면을 보여 주는 것은 권한을 만들지 않습니다.
권한에는 범위도 있습니다. 권한은 사용자 프로필 안의 패키지에 속하므로 개인 사본과 업무 사본은 별개의 결정이고, 기기 소유자는 관리 프로필을 개인 프로필과 다르게 준비할 수 있습니다. 대화상자가 한 번도 나타나지 않고 prepare()가 null을 반환한다면 그 프로필의 그 패키지에는 이미 동의가 있는 것입니다. 그것은 앱이 신뢰할 만하다는 증거가 아니라 권한이 있다는 뜻일 뿐입니다.
인터페이스는 시스템이 이행하는 요청이다
동의 후 앱은 VpnService.Builder로 원하는 것을 기술합니다. 주소, 경로, DNS 서버, MTU, 그리고 지원되는 경우 포함하거나 제외할 앱입니다. establish()는 시스템에 터널 인터페이스를 만들고 일치하는 트래픽을 그리로 보내라고 요청합니다. 라우팅 결정은 시스템이 소유합니다. 앱은 파일 디스크립터를 받고 그다음 패킷으로 무언가 유용한 일을 해야 합니다.
| What you observe | Who actually owns it |
|---|---|
| VPN consent dialog | The system, triggered by prepare() |
| Routes, DNS and app lists | The app requests them; the system applies them |
| One active VPN per profile | The platform; a new service replaces the old one |
| Always-on and block-without-VPN | Device policy enforced by the platform |
그 표가 한곳에 정리된 아키텍처입니다. 앱은 패킷 처리에 참여하지만 인터페이스, 라우팅 테이블, 실행할 수 있는 서비스 수를 소유하지는 않습니다.
터널 소켓은 자기 터널에서 빠져나와야 한다
암호화된 트래픽을 나르는 연결 자체가 소켓입니다. 그것이 앱이 방금 만든 인터페이스로 다시 라우팅되면 터널이 터널에 의존해 멈춥니다. VpnService.protect()는 그 소켓을 하위 네트워크에 묶어 캡처를 우회하게 하며, 그래서 올바른 클라이언트는 첫 핸드셰이크 전에 바깥 소켓을 보호합니다.
adb shell dumpsys connectivity | grep -i -A5 vpn
adb shell settings get global always_on_vpn_app
adb shell settings get global always_on_vpn_lockdown
이 명령들은 설치된 VPN 네트워크, 상시 켜짐 패키지, 잠금 설정 여부를 보여 줍니다. 모두 읽기 전용 관찰입니다. 값이 설계의 주장과 맞지 않는다면 그 주장은 시스템 상태가 아니라 앱의 화면에 관한 것입니다.
차단은 플랫폼의 것일 수 있다
Android는 VPN을 사용하지 않는 연결을 차단하는 정책을 문서화합니다. 그 시행은 플랫폼의 계약이며, 앱이 루프에서 연결을 다시 시도하는 것이 아닙니다. 스위치는 기기 VPN 설정의 „VPN 없이 연결 차단“에 있고, 관리 기기에서는 소유자가 전체 프로필에 대해 켤 수 있습니다. 이 구분은 마케팅 주장을 평가할 때 중요합니다. 클라이언트는 자물쇠 아이콘을 보여 주고 공격적으로 다시 연결하면서도 직접 트래픽은 여전히 가능할 수 있고, 또는 대상 앱은 시스템이 잠금을 시행하기 때문에 오프라인으로 남을 수 있습니다.
자물쇠 아이콘은 앱이 그리는 것이므로 앱이 연결되었다고 믿는다는 것만 증명합니다. 다른 앱이 네트워크 접근을 잃는지는 플랫폼이 결정하므로, 유용한 확인은 터널이 켜져 있는 동안 그 앱이 실패하는지 보는 것입니다.
앱 스토어의 „상시 켜짐“ 라벨도 그 계약을 대신하지 못합니다. 상시 켜짐과 잠금은 기기 설정이며 흔히 기기 소유자가 적용하고, 제외된 앱에 대한 동작은 플랫폼이 정의합니다. 배지가 아니라 설정을 읽으세요.
설계 검토를 위한 네 가지 질문
첫째, 누가 동의했는가: 어느 패키지, 어느 프로필, 그리고 사용자인가 관리 기기 정책인가? 둘째, 앱이 무엇을 요청했는가: 어떤 경로, 어떤 주소 체계, 어떤 앱을 포함하거나 제외했는가? 셋째, 터널을 쓸 수 없을 때 무슨 일이 일어나는가: 시스템이 차단하는가, 아니면 트래픽이 하위 네트워크로 되돌아가는가? 넷째, 앱이 받은 패킷으로 무엇을 하는가?
네 번째 질문은 권한 모델이 답할 수 없는 질문입니다. 동의와 TUN 인터페이스는 앱이 트래픽을 받을 수 있음을 증명하지만, 그것을 암호화하는지, 상대를 인증하는지, 깔끔하게 복구하는지는 증명하지 않습니다. 그것들은 구현의 속성이며, 정직한 검토가 시간을 쓰는 곳입니다.
불필요한 루트 요청은 결과를 킬 스위치라고 부른다고 정당해지지 않으며, 동의 대화상자는 보안 감사가 아닙니다. 세 권한을 분리해 두면 모든 주장이 검증 가능해집니다.