file URI와 same-origin policy

modern web browser에는 보안을 위한 여러 가지 기능들이 들어있다. 그중 가장 대표적인 기능이 same-origin policy다. same-origin policy 덕분에 (개발자 입장에서는 약간 짜증 나기는 하지만) 특별히 신경을 쓰지 않아도 보안에 관해 상당히 많은 부분을 커버할 수 있다. same-origin policy의 원칙은 매우 간단하다. 내 사이트가 다른 사이트에서 호스팅 되는 리소스에 의존하는 것을 금지해서, 내 사이트가 오염되거나 다른 사이트에 의해 공격당하는 것을 막는 것이다.

same-origin인지 결정하는 것은 매우 간단한데 프로토콜, 호스트, 포트가 같은 URI를 same-origin이라고 판단한다. 요새는 대부분 개인 서버와 개인 도메인을 사용하기 때문에, 프로토콜과 포트까지 같은지 판단하는 것은 너무 빡빡한 기준이라고 생각할 수도 있지만, 워크스테이션이나 공용 서버에서 작업하는 일도 많다는 것을 생각하면 포트와 프로토콜까지 고려하는 것은 역시 상식적인 판단이라고 할 수 있다.

브라우저에서 많이 쓰이는 http나 https에서는 이 규칙이 상식적이라고 할 수 있다. 문제는 file URI에서의 동작이다. file URI에 대해서는 어떤 URI를 same-origin이라고 할 것인지 정해진 것이 없고, 브라우저마다 알아서 자신이 옳다고 생각하는 방식으로 구현했다.

우선 오페라는 file URI도 다른 URI와 같은 정책으로 처리한다. 따라서 file URI로 접근한 페이지에서는 읽기 권한이 있는 모든 파일을 읽어서 리소스로 활용할 수 있다. 어차피 파일은 OS가 access list로 보호하고 있으니, 로컬 파일에 대한 보안을 OS에 맡겨 버린 것이라고 할 수 있겠다. 약간 무책임한 것 같지만, 오페라의 구현이 가장 웹서버 없이 웹 페이지를 테스트하기 편한 구현이다.

반면 크롬은 modern browser 중에 가장 빡빡한 규칙을 적용한다. 크롬에서는 file URI로 들어오는 요청에 대해 무조건 다른 origin인 것으로 처리한다. 심지어 host name을 명시적으로 입력해서 겉으로 보기에는 protocol, host name, port가 같아서 같은 origin으로 보이는 경우도 다른 origin인 것처럼 처리한다. 따라서 크롬에서는 웹 서버 없이 웹 페이지를 테스트하는 것이 불가능한 경우도 생긴다.

이렇게 빡빡한 규칙을 적용한 이유는 찾을 수 없었다. 아마도 크롬이 Chrome OS와 코드를 공유하기 때문으로 추측된다. Chrome OS의 파일 권한이 앱별로 있는 것이 아니라서 다른 앱에서 로컬에 있는 파일을 읽는 것을 막기 위해서 file URI를 모두 다른 origin으로 취급해야 했던 게 아닐까 싶다.

파이어폭스는 크롬과 오페라의 중간 정도 되는 정책을 취한다. 파이어폭스에서 file URI를 쓰면 현재 directory를 기준으로 자신보다 아래 경로에 있는 파일은 읽을 수 있도록 허용한다.1) 덕분에 파이어폭스도 웹 서버 없이 테스트하지 못하는 웹 페이지가 생기기도 한다. 하지만 크롬보다는 상황이 조금 나은 게 최소한 자신의 것이 확실한 (자기 디렉토리 아래에 있는)리소스는 마음껏 사용할 수 있다.

크롬 브라우저에는 file URI를 이용하면서도 다른 파일을 같은 origin인 것처럼 사용하는 방법도 있다. 크롬을 실행할 때 --allow-file-access-from-files switch를 이용하면 file URI에서 모든 파일에 접근할 수 있도록 해준다. 주의해야 할 것은 기존에 실행시켰던 크롬이 백그라운드로 떠 있으면, 새로 크롬을 실행시켜도 백그라운드 프로세스로 떠 있던 크롬이 포크 되며 실행되기 때문에 switch가 반영되지 않는다. 따라서 switch를 주면서 크롬을 실행시킬 때는 기존의 프로세스가 전부 꺼졌는지 확인하고 실행해야 한다.

파이어폭스도 file URI에 대한 동작을 변경할 수 있다. security.fileuri.strict_origin_policy 설정을 이용하면 오페라와 같이 모든 로컬파일을 리소스로 쓸 수 있게 된다.

이런 식으로 크롬이나 파이어폭스를 이용해도 switch나 preference를 통해서 file URI로 로컬에 있는 페이지에 접근해서 테스트할 수도 있다. 하지만 테스트를 위해서가 잠시 값을 바꿔서 쓰는 게 아니라 기본값을 바꿔서 계속 사용하는 것은 좋은 방식이 아니라고 생각한다. same-origin policy라는 것의 목적은 보안을 위한 것이다. 보안을 위한 기능을 편의를 위해 끄고 쓰는 것은 열쇠 가지고 다니기 귀찮다고 문 열어놓고 다니는 것과 마찬가지의 행동이다. 게다가 file URI를 통해 간단한 테스트는 가능할 수도 있지만, file URI는 http나 https와 동작이 달라서 실제 웹앱과 완벽하게 같은 테스트는 안된다. 따라서 실제로 웹 서버를 띄우는 것이 가장 확실한 방법이다.

하지만 구태여 웹 페이지를 file URI로 테스트하려고 했던 것은, 현재 머신에 웹서버를 설치하기 싫거나, 설치할 수 없거나, 설정하기 귀찮은 경우일 것이다. 그런 상태에서 웹 서버를 설치하고 테스트하라고 말해봐야 보안에 구멍이 생기더라도 브라우저 설정을 바꾸는 것을 택할 것이다. 그런 사람들을 위해 간단하게 웹서버 돌리는 방법을 소개해 주겠다. 어디든지 실행시키고 싶은 웹 앱의 최상단 경로에서 python3 -m http.server {port}를 입력하면 python으로 웹 서버가 실행된다. 아무 기능도 없지만, 최소한 file URI로 테스트하려던 수준의 웹 페이지라면 충분히 테스트할 수 있다.


1) https://developer.mozilla.org/en-US/docs/Same-origin_policy_for_file:_URIs

댓글

이 블로그의 인기 게시물

[C++] enum class - 안전하고 쓰기 쉬운 enum

Log Aggregator 비교 - Scribe, Flume, Fluentd, logstash

RAII는 무엇인가

[Python] cache 데코레이터로 최적화하기

[Web] SpeechSynthesis - TTS API