GN⁺ 6시간전 | parent | ★ favorite | on: 나는 쿼리 문자열을 금지했다(chrismorgan.info)
Hacker News 의견들
  • 이게 궁금해서 HTML과 URL W3C 표준을 다시 봤는데, 의외로 쿼리 문자열 형식은 퍼센트 인코딩 말고는 별도 정의가 없었음
    쿼리 문자열을 “form-urlencoded”[0] 쿼리 문자열과 혼동할 수 있는데, 이는 상호운용 가능한 형식 중 하나일 뿐임. 일반적으로 쿼리 문자열은 URL의 ? 뒤에 오는 임의의 퍼센트 인코딩 문자열[1]이고, 응답 생성에 사용할 수 있는 HTML URL 객체의 또 다른 속성임
    URLSearchParams 객체는 form-urlencoded 파서로 쿼리 문자열을 파싱한 결과지만, 이는 JavaScript를 위한 상호운용 계층일 뿐임
    솔직히 표준을 보기 전에는 반대 의견을 낼 준비가 되어 있었는데, 표준은 꽤 명확했음. 예상치 못한 쿼리 문자열에 404로 응답하는 것도 적절할 수 있음. 쿼리 문자열은 경로만큼이나 URL API의 일부이고, 경로에 임의 문자열을 덧붙이는 게 좋지 않고 정의되지 않은 동작이라는 점은 대부분 인정할 수 있을 것임
    [0]: https://url.spec.whatwg.org/#application/x-www-form-urlencod...
    [1]: https://url.spec.whatwg.org/#url-class

    • 예전에는 CMS나 포럼이 index.php 하나만 두고, 라우팅을 전부 쿼리 문자열로 처리하는 일이 꽤 흔했음
      물론 form-urlencoded 형식이었고, 사람들도 야만인은 아니었음. 그래서 index.php?p=home, index.php?p=shop, 또는 index.php?action=showthread&forum=42&thread=17976 같은 URL이 나왔음. 이런 구조에서는 알 수 없는 쿼리 매개변수에 404가 맞는 응답이라는 게 바로 드러남
      실제로 지금도 많은 사이트가 그렇게 동작하고, SEO 때문에 Apache/nginx 재작성 규칙 몇 개 뒤에 숨겨둘 뿐임
    • 맞음, URL에는 의미론이 그리 많지 않음. 경로는 계층형 데이터, 쿼리는 비계층형 데이터를 위한 의도가 분명해 보이고, 강한 관습도 있으며 일부는 라이브러리가 지원하거나 강제하기도 하지만 실제 규칙은 없음
      결국 URL은 서버가 어떻게 처리할지 정하는 문자열일 뿐임
      이 논의에서 정말 웃긴 점은, 404로 응답했을 때의 부작용을 걱정하면서도 웹 역사에서 경로가 얼마나 오랫동안 무의미했는지를 완전히 잊고 있었다는 것임. 이제는 경로가 이겼음. 더 이상 /item?id=… 같은 URL로 새로 시작하는 일은 거의 없음. 좋네!
    • 범용적인 400이 더 낫지 않을까 함. 페이지를 못 찾은 게 아니라, 허용되지 않는 요청을 보낸 것임
      “요청을 고쳐서 다시 시도하라”로 읽히고, 내가 제공하는 API에서도 그렇게 씀. 406보다 이쪽을 선호하는 이유는 내 쪽이 처리할 수 없는 문제가 아니기 때문임. 쿼리 문자열에 뭔가를 덧붙여 깨뜨리려 했거나 문서대로 요청을 만들지 않았다면, 그건 요청자 책임
    • No-Vary-Search 제안은 쿼리의 어떤 부분이 관련 있는지 지정하게 해줌
      https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/...
      예를 들어 캐싱 관점에서는 url?a=b&c=durl?c=d&a=b와 일치한다고 볼 수 있음
    • 표준은 누군가 어딘가에 적어둔, 널리 받아들여진 동작일 뿐임
      공식 표준으로 문서화된 적은 없지만 따르지 않으면 광범위하게 깨지는 관습도 아주 많고, 문자 그대로 따르면 바보가 되는 “표준”도 많음
      원 글의 경우 깨지는 것은 그 사이트를 방문하려는 사람뿐이고, 아마 브라우저 뒤로 가기를 누르고 자기 할 일을 할 것임. 그 정도 피해를 받아들일지는 본인이 결정하면 됨. 다만 어떤 표준도 금지하지 않았다고 해서 정의상 허용되는 것은 아니고, 반대로 표준이 금지했다고 해서 갑자기 허용 불가가 되는 것도 아님
  • 이해한 바로는, 다른 웹사이트가 작성자 사이트로 가는 링크에 ?ref=origin.com 같은 쿼리 문자열을 붙이는 데 짜증이 난 것 같음
    이게 원본 사이트에는 어떤 이익이 있고, 작성자 사이트에는 어떤 피해가 있는지 모르겠음
    양쪽의 행동이 모두 완전히 혼란스러움
    광고 캠페인을 운영할 때 Google이 UTM 쿼리 문자열을 붙여서 어떤 캠페인에서 사용자가 왔는지 추적하고 싶은 건 이해함. 그때는 출발지와 목적지가 협력하는 관계임. 그런데 여기서는 출발지가 아무 이유 없이 뭔가를 붙이고 있음. 왜일까?

    • 원본 사이트 입장에서는 마케팅임. 작성자가 ref 쿼리 문자열에서 xyz.com에서 상당한 트래픽이 온다는 걸 보고, 그 사이트에 광고하거나 제휴할 수 있다고 생각하는 흐름임
      솔직히 틈새/스타트업 사이트에는 꽤 유용함. 웹 분석에서 이런 값을 보고 시작된 대화의 양쪽을 모두 겪어봤고, 한 번은 유입 트래픽을 보고 내가 연락했고, 다른 한 번은 내가 링크한 사이트에서 연락을 받았음. 두 번 모두 서로에게 이로운 파트너십으로 끝났음
      프라이버시 논점도 어느 정도 이해하지만, 표준 Referer 헤더보다 더 많은 정보를 제공하지는 않음. Simple Analytics/Plausible 같은 분석 도구를 쓰면 훨씬 더 눈에 잘 띌 뿐임
    • 대체로 추적에 반대함. 추적은 보통 개인의 이익에 반함
      쿼리 문자열 추가는 흔히 추적에 쓰임. Firefox의 “copy clean link”나 UTM 매개변수 일부를 선제적으로 제거하는 Enhanced Tracking Protection 같은 기능이 존재한다는 점만 봐도 많은 사람이 이를 원하지 않는다는 걸 알 수 있음
      어떤 사이트들은 내가 가볍게 “추적 경제”라고 부를 시스템에 기꺼이 참여함. 수신자가 로그에서 많은 사람이 자기 사이트에서 온다는 걸 보고, 그 사이트에 도움이 되는 행동을 할 수 있기 때문임
      쿼리 문자열을 거부하는 건 그 시스템에 대한 단순한 항의임
    • 인기 있는 웹사이트가 그 매개변수를 붙이면 대상 사이트가 누가 트래픽을 보내는지 쉽게 알 수 있고, 그것이 스폰서십이나 제휴 계약의 기반이 될 수 있음
  • “웹사이트 방문자가 독립 개인 웹사이트 운영자 커뮤니티가 추천한 흥미로운 웹사이트와 페이지를 탐색할 수 있게 하는, 작고 탈중앙화된 자체 호스팅 웹 콘솔”이라는 설명을 보니 예전에는 이런 걸 Webring이라고 불렀음. 다만 그렇게 화려하진 않았음
    오픈소스 애플리케이션 프레임워크를 개발할 때 겪은 문제 중 하나는 FastCGI를 쓰는 호스팅이 Auth 헤더를 존중하지 않아서 토큰을 쿼리로 넘길 수밖에 없었다는 점임. 웹 주소를 복사/붙여넣기할 때 토큰이 들어가는 일이 잦아서 정말 별로였음. 지금은 고쳐졌을지도 모르겠음
    내가 제어하고 모두에게 공개할 필요가 없는 백엔드에서는 헤더를 씀

    • 오픈소스 애플리케이션 프레임워크를 fcgi-app으로 작성했는데, 예를 들어 Apache가 Auth 헤더를 망가뜨렸다는 뜻인가?
      이 부분을 더 자세히 설명해줄 수 있는지 궁금함. 기술적으로는 PARAM 레코드가 기대한 값을 실제로 주지 않는다는 얘기 같음
  • “그래서 이 사이트에는 포괄 금지를 시도하기로 했다: 승인되지 않은 쿼리 문자열 없음”이라고 했는데, 그의 사이트는 요청에 쿼리 문자열이 포함되면 414를 반환하는 것 같고, 내 생각엔 잘못된 선택임
    이 항의가 사용자를 옹호하려는 것이라면, 애초에 그 문자열을 통제하지 못했을 사용자에게 왜 벌을 주는 걸까?
    차라리 사용자가 브라우저 도구 등을 통해 스스로 이 결정을 내릴 수 있는 방법을 알려주는 신호로 쓰면 되지 않을까?

    • “내가 414 URI Too Long을 남용하고 있다고 주장할 수 있다. 내 답은, 이 방식이 더 웃기다는 것이다. 고려했던 다른 선택지는 다음과 같다:
      400 Bad Request, 일반적인 클라이언트 오류 코드로 맞지만 재미없다
      402 Payment Required, 솔직히 쿼리 문자열이 있는 특정 URL이 동작하게 해달라고 돈을 낸다면 열려 있다
      404 Not Found, 하지만 부작용이 너무 생기기 쉽고, 내가 의도하는 ‘요청 형식이 잘못됐다’는 느낌을 전달하지 못한다
      303 See Other에 Location 헤더 없음. 요즘은 극히 드물지만 정당하다. 적어도 RFC 2616에서는 그랬다(“The different URI SHOULD be given by the Location field in the response”). 하지만 7231과 9110에서는 Location 헤더의 존재를 전제로 하는 방식으로 바뀌었다(“… as indicated by a URI in the Location header field”). 반면 301, 302, 307, 308은 “the server SHOULD generate a Location header field”라고 한다. 어쨌든 Location 헤더 없는 See Other도 충분히 괜찮다고 본다. 하지만 URI Too Long이 더 웃겼다”
      https://chrismorgan.info/no-query-strings?foo
    • 오래전이라 가물가물하지만, 알 수 없는 쿼리 문자열을 넘기면 500을 반환하던 PLSQL 서버 페이지 버전이 있었던 것 같음
  • “내가 414 URI Too Long을 남용하고 있다고 주장할 수 있다. 내 답은, 이 방식이 더 웃기다는 것이다. 고려했던 다른 선택지는…”이라는 대목에서, 또 다른 선택지로 418 I'm a teapot도 생각해볼 수 있음. 찻주전자도 보통 쿼리 문자열을 지원하지 않으니까

    • 그냥 400 “Bad Request”나 403 “Forbidden”도 방어 가능한 선택으로 보임. URI 매개변수 전용 오류 응답 코드가 없다는 게 이상함
      적절해 보이지만 자세히 보면 아닌 선택지도 여럿 있음: 406 “Not Acceptable”은 콘텐츠 협상 헤더 기반이고, 409 “Conflict”는 주로 WebDAV 요청용이며, 411, 422, 431 같은 것도 여기와 관련 없는 특정 조건용임
      300이나 500 계열 오류도 부적절함. 이건 재배치나 서버 측 실패가 아니라 클라이언트 측 요청 문제이기 때문임
      찻주전자나 너무 김이 최선의 후보 같음
    • 당연히 지원함. 예를 들어 위에서 줄을 내려서 찻주전자의 수위를 질의할 수 있고, 줄을 주전자 둘레에 감아서 둘레를 질의할 수도 있음
    • 하지만 난 찻주전자가 아님. 차를 싫어함
  • 이 글과 Chris의 글의 어조를 보면 이런 쿼리 매개변수를 포함하는 게 해로운 것처럼 느껴지는데, 어떻게 해로운지 이해가 안 됨
    일부 URL을 망가뜨릴 수 있다는 건 이해하고, 그것만으로도 하지 않을 이유는 충분함. 그래도 사소한 불편처럼 보임. 누가 설명해줄 수 있을까?

    • 세 가지 관점이 있음
      기술적 순수주의 관점에서는, 관습상 받아들여지더라도 URL을 수정하는 건 기술적으로 부정확함. URL은 기본적으로 불투명한 값으로 다뤄야 함
      사회적 관점에서는 추적이며, 형제 댓글 스레드들이 잘 설명하고 있으니 반복하지 않겠음
      잡음 관점에서는, 사용자가 신경 써야 할 부분을 가리고 URL이 너무 어렵고 복잡해져 일반 사람들이 더 이상 URL에 관심을 갖지 않게 만드는 데 기여함
    • HTTP Referer 헤더 관련 문제를 읽어보면 사람들이 왜 싫어하는지 알 수 있음: https://en.wikipedia.org/wiki/HTTP_referer
      어떤 사이트에 도달하기 전에 어디에 있었는지를 그 사이트가 알지 못하게 하고 싶은 이유는 많음. 기본적으로 방문 중인 사이트에 브라우징 기록을 공유하는 셈임
      그래서 HTTP Referer 헤더에는 전송 조건 제한과 기능을 완전히 끌 수 있는 기능 등 많은 업데이트가 있었음
      같은 정보를 URL 매개변수로 추가하면 이런 기존 규칙과 거부 기능을 우회하게 됨. 그냥 표준을 써야 함
    • 전혀 이유가 없음. 그 정보는 그냥 버리면 됨
      터무니없이 극단적인 태도이고, 이게 어떻게 더 나은 웹으로 이어지는지 제대로 설명하지 못함
    • 흥미로운 건 이런 사이트들 중 검색 기능을 가진 곳이 없다는 점임. 검색은 중요한 접근성 기능이고 쿼리 문자열의 명확하고 정당한 사용 사례임
    • 이유가 몇 가지 있음. 사용자는 추적에 동의하지 않았고, 이런 쿼리 매개변수는 추적 정보임. 또한 사이트 관리자는 유입 트래픽이 추적되는 걸 원하지 않을 수 있음
      후자는 이해하기 어려울 수 있지만, 내 경우 로그에 사용자를 해칠 수 있는 정보가 남는 걸 절대 원하지 않음
      개인적으로는 링크를 복사해 메시지로 보내려는데 원래 URL보다 두 배나 긴 추적 코드가 붙어 있으면 정말 싫음. 일일이 지워야 하거나, 아니면 화면 가득한 임의 문자들을 받은 사람이 이게 대체 뭔지 의아해하게 둬야 함
      사용자 프라이버시를 침해하고, 사용자 경험도 나쁘고, 무엇보다 아무도 요청하지 않았음
  • 원문 소스가 아직 HN에서 논의된 적이 없어서, 그 링크(https://chrismorgan.info/no-query-strings)를 맨 위에 두고 응답 글 링크(https://susam.net/no-query-strings.html)는 상단 설명으로 옮겼음
    둘 다 좋지만 원문에 우선순위를 주는 게 공정해 보임

  • 이 근처에서 아직 GET 쿼리를 쓰는 사이트 대부분은 지방정부가 운영하는 세금 징수 사이트인데, 로그인 후 변수들을 이리저리 넘김
    사실 GET 요청이 하는 일을 똑같이 하면서도 진짜 URL인 척하는 라우팅 파서가 훨씬 더 짜증남

  • 쿼리 문자열은 쓸모가 있음. 파일 검색이나 다른 종류의 동적 파일 같은 경우가 그렇지만, 쿼리 문자열을 기대하지 않는 URL에 붙이면 안 됨
    그래서 UTM 같은 것이 덧붙은 요청을 거부하는 건 맞다고 봄
    쿼리 문자열이 예상되지 않았는데 존재한다면 응답으로는 404가 가장 말이 되는 것 같고, 400도 적절할 수 있음