Read My Blog With JavaScript

Michael Lynch

JavaScript로 제 블로그 읽기

이제 클라이언트 측 JavaScript로 제 블로그를 읽을 수 있습니다. 왜 굳이 그렇게 하려 할지는 모르겠지만, 어쨌든 가능합니다.

예를 들어 좋아하는 블로그들의 최신 글을 모아 보여주는 블로그롤을 사이트에 추가하고 싶은데, 서버 측에서 가져오고 싶지 않을 수도 있습니다. 제 블로그의 최신 글 5개의 제목을 JavaScript로 표시하고 싶다면, 코드는 다음과 같이 작성할 수 있습니다.

fetch("https://mtlynch.io/index.xml")
  .then((response) => response.text())
  .then((str) => new DOMParser().parseFromString(str, "application/xml"))
  .then((data) => {
    const articles = [...data.querySelectorAll("item")].map((item) => ({
      title: item.querySelector("title").textContent,
      date: new Date(item.querySelector("pubDate").textContent),
    }));

    // Sort articles by date, newest to oldest.
    articles.sort((a, b) => b.date - a.date);

    // Print the titles of the 5 most recent articles.
    articles.slice(0, 5).forEach((article) => console.log(article.title));
  });

위 코드는 다음과 같은 출력을 생성합니다.

Refactoring English: Month 10
Get xkcd Cartoons at 2x Resolution
List of 2x-resolution xkcd Cartoons
I Once Appeared in The Old New Thing
Refactoring English: Month 9

이 아이디어는 Simon Willison이 Lobsters에 남긴 최근 댓글에서 얻었습니다.

JavaScript가 제 사이트를 읽게 하려면 어떻게 해야 할까요?

JavaScript 접근을 허용하기 위해 제가 변경해야 했던 유일한 것은 RSS 피드에 Cross-Origin Resource Sharing(CORS) HTTP 헤더를 설정하는 것이었습니다. 일반적으로 다른 사이트가 클라이언트 측 JavaScript로 서로의 콘텐츠를 읽지 못하도록 막는 것은 동일 출처 정책(same-origin policy)입니다.

동일 출처 정책에 따르면 각 사이트(오리진)는 자신의 도메인과 연결된 리소스만 읽을 수 있습니다. 따라서 mtlynch.io에 있는 제 블로그를 방문했을 때, 제 페이지에 있는 JavaScript가 chase.com에서 여러분의 은행 잔고를 읽으려 한다면, 동일 출처 정책이 그 정보에 접근하는 것을 차단합니다.

다른 웹사이트에서 JavaScript를 통해 제 블로그를 읽을 수 있도록 하려면, 블로그의 RSS 피드에 CORS 헤더를 설정해야 했습니다. 이 블로그는 현재 Netlify에서 호스팅 중인 정적 사이트이므로, Netlify 설정 파일을 수정해 RSS 피드 URL에 CORS 헤더를 지정해야 했습니다.

[[headers]]
  for = "/index.xml"
  [headers.values]
    Access-Control-Allow-Origin = "*"
    Access-Control-Allow-Methods = "GET, HEAD, OPTIONS"
    Access-Control-Allow-Headers = "Content-Type"

무슨 문제가 생길 수 있을까요?

CORS는 보안 메커니즘이므로, 인터넷에 공개된 사이트의 보안 제한을 완화하는 일에는 항상 신중해야 합니다. 하지만 한동안 위험성을 고민해 본 결과, 제 상황에서는 의미 있는 위험이 없다고 판단했습니다.

공격자가 비밀 데이터를 유출할 수 있을까요?

동일 출처 정책의 목적은 사용자가 사이트 A에 민감한 데이터를 가지고 있을 때, 사이트 A가 명시적으로 허용하지 않는 한 사이트 B가 그 데이터에 접근할 수 없도록 하는 것입니다.

제 블로그는 비밀 정보가 없는 정적 사이트입니다. 제가 mtlynch.io에 접속했을 때 보는 것은 다른 모든 사람이 보는 것과 완전히 동일합니다. 따라서 공격자가 저를 속여 제3자 사이트에서 악성 JavaScript를 실행하게 하더라도, 제 블로그에서 제가 가진 특별한 권한 자체가 없기 때문에 그 코드가 제 권한을 악용할 수는 없습니다.

임베디드 댓글 기능으로는 TalkYard를 사용하고 있고 거기서는 관리자 권한을 가지고 있지만, RSS 피드에 대한 CORS 설정은 TalkYard에는 영향을 주지 않습니다.

공격자가 DDoS 공격을 할 수 있을까요?

처음에는 공격자가 CORS 설정을 악용해 제 사이트에 DDoS 공격을 할 수 있지 않을까 생각했습니다. 공격자가 수백만 명을 어떤 페이지로 유도한 뒤, 백그라운드의 JavaScript가 제 RSS 피드를 계속 요청하게 하면 어떻게 될까 하는 생각이었습니다.

하지만 그런 DDoS 공격은 이미 가능하다는 것을 깨달았습니다. CORS는 서드파티 도메인이 요청 결과를 읽을 수 있는지만 제어할 뿐, 애초에 요청 자체를 차단하지는 않습니다. CORS 설정과 관계없이 어떤 도메인이라도 다른 도메인에 GET 및 POST 요청을 보낼 수 있습니다.

공격자가 제 사이트를 사칭할 수 있을까요?

제가 고려했던 또 다른 공격은 사칭입니다. 방문자가 evil.example.com에 접속하면, 그곳의 서버가 방문자의 브라우저에서 제 블로그를 재구성하는 JavaScript를 내려보낼 수 있습니다. 주소 표시줄에는 여전히 evil.example.com이라고 표시된 채로 말입니다.

이 공격이 통할 수는 있지만, 제 CORS 설정과 관계없이 제 블로그를 사칭하는 더 쉬운 방법이 있습니다. 사칭하는 사람은 제 블로그로 요청을 전달하는 HTTP 프록시를 운영할 수 있는데, 이는 제 블로그를 사칭하는 더 간단한 방법입니다. 혹은 그냥 제 사이트를 스크랩해서 다른 곳에 호스팅할 수도 있습니다.

왜 제 블로그를 JavaScript가 읽도록 허용했을까요?

아무도 제게 RSS 피드에 CORS를 활성화해 달라고 요청한 적은 없으므로, 이게 실제로 누군가에게 도움이 될지는 모르겠습니다. 하지만 저는 개방적인 웹을 좋아하고, 다른 사이트가 제 사이트와 상호 운용될 수 있게 하는 흥미로운 방법이기도 해서, 한번 해보기로 했습니다.

이번 변경으로 제 RSS 피드를 활용해 뭔가 흥미로운 것을 만들게 된다면, 알려 주세요.

원문은 Michael Lynch님이 에 게재했습니다.

이 글은 muse-spark-1.2-contributor 모델을 사용해 번역했습니다.