URL Rewrite 에서 인코딩된 주소를 재작성시 제대로 처리하지 못하는 문제

Problem discription

URL rewrite 가 인코딩된 주소를 받고, 이를 재작성(또는 리디렉션) 된 주소에 다시 활용하는 경우 잘못 인코딩된(=입력과 동일하지 않은) 주소를 반환하는 문제.

Background

워드프레스에서 제목을 한글로 쓰면 퍼머링크도 기본적으로 한글로 작성되기 때문에 이것을 수정하지 않고 저장하면 페이지 보기가 안되고 404 가 뜨는 문제가 있었다.

이것이 OS의 레거시 인코딩 문제(윈도우즈에서 유니코드가 아닌 ANSI 문자열을 사용하는 레거시 API를 호출하는 프로그램이 겪는 문제) 라고 생각했었는데… 아주 틀린 건 아니지만 내가 생각한 종류의 것은 아니었다.

알고보니 한글로 작성을 하더라도 클라이언트에서는 이 퍼머링크를 인코딩하여 보내므로 저장까지는 인코딩 문제가 발생하지 않고 잘 된다. 그러나 페이지 보기를 누르면 워드프레스의 설정의 사이트 주소가 http 를 기준으로 설정되어 있으므로 퍼머링크도 http 링크로 생성되어1 클라이언트가 http 주소로 접속을 시도한다. 그러면 서버는 이 요청을 https 리다이렉트 룰에 의하여 https 주소로 리다이렉트하는데, 이 과정에서 URL rewrite 가 프로토콜만 변경하고 나머지 값은 그대로 유지하여야 하지만 실제로는 그렇게 동작하지 않아서(path 값이 입력 그대로가 아닌 잘못 인코딩된 값으로 반환된다) 결국 404 에러가 발생하게 된다.

이것을 해결하기 위해서는,

  1. 워드프레스 사이트 주소를 https 로 설정
  2. 리다이렉트 룰이 제대로 인코딩 된 주소를 보내도록 수정

중에 하나를 수행하여야 하는데, 현재는 2개 모두 적용했다.

1. 의 경우에는 wp_config.php 파일의 WP_HOME 및 WP_SITEURL 변수를 수정해주면 되고, 2. 의 경우에는 아래에 서술한다.

Solution

원래는 이런 식의 https 리다이렉트 룰을 썼었다.

 <rule name="https redirect" enabled="true" patternSyntax="Wildcard" stopProcessing="true">
          <match url="*" />
          <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
            <add input="{HTTPS}" pattern="OFF" />
          </conditions>
          <action type="Redirect" url="https://{HTTP_HOST}{R:0}" redirectType="Permanent"  />
        </rule>

이것을 보면, 룰에 의하여 캡처된 주소를 그대로 리턴하므로 문제가 없을 것 같지만 실제로는 잘못된 주소를 리턴한다.

이를 해결하기 위해 현재는 다음의 룰을 사용한다.

 <rule name="https redirect" enabled="true" patternSyntax="Wildcard" stopProcessing="true">
          <match url="*" />
          <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
            <add input="{HTTPS}" pattern="OFF" />
          </conditions>
          <action type="Redirect" url="https://{HTTP_HOST}{UNENCODED_URL}" redirectType="Permanent"  />
        </rule>

캡처 과정에서 문제가 발생하는 것 같아 {R:0} 대신 {UNENCODED_URL} 를 사용하여 클라이언트가 요청한 값을 그대로 돌려주도록 했다.

한편, URL Rewrite Module Configuration Reference2 에 의하면 또한 {HTTP_X_ORIGINAL_URL} 도 제시되고 있는데, 로그를 보면 X-ORIGINAL-URL 서버 변수는 기록되고 있는 것으로 보이지만 URL Rewrite 에서 저 변수를 쓰면 그냥 공백이 리턴된다. 전에도 다른 건으로 검색해보았지만 납득할만한 설명이 없었던 것으로 보아 이것 또한 버그로 보인다.

원래 이런 종류의 기술 문서는 영어로 작성하는 것을 개인적인 원칙으로 세웠지만, M$ 욕 좀 하려고 한글로 적었다. 이런 종류의 문제를 겪지 않으리라 믿고 IIS 를 웹 서버로 선택했는데 최근 들어선 이럴 바엔 그냥 apache 하는 게 나았으리란 생각이 든다. 얘네들은 장사에 좀 도움이나 되지…


2017-08-17: 다시 읽어보니 대상이 생략된 부분이 있어 문제가 어떨 때 발생하고 무엇이 문제였는지 파악하기 어려우므로 몇몇 문장을 수정했다. 당시에도 비슷한 고민을 하다가 필요 없다고 느껴져서 안 썼던 것 같긴 한데 지금 보니 이 편이 나은 것 같다.

  1. 이게 참 병신같은 점인데 설치 시에 http 로 접속해서 설정을 진행했기 때문에 그렇다. 편하게 하려고 azure 템플릿으로 설치를 했더니 이래놨다. 뭐 제대로 하는 게 없네… 글을 쓰는 도중에 수정하려고 잠시 뒤져봤더니 wp_config.php 파일에 http로 하드코딩되어있었다. db에도 이 설정이 있던데 혹시 몰라서 양쪽 모두 변경함. 차라리 건드리지 말던가 왜 하드코딩을 그것도 http로 해놨는지 모르겠다.
  2. 이 레퍼런스를 내가 썼으면 이것보다 훨신 잘 썼을 것이다. 많은 부분이 잘못되거나 부실하게 기재되어 있다. 이것 때문에 낭비한 시간이 누적 24시간은 넘을 것이다.

Leave a Reply

Your email address will not be published. Required fields are marked *