世界を動かす技術を、日本語で。

クエリ文字列を禁止しました

概要

  • URLへのトラッキングパラメータ 追加への不快感
  • Refererヘッダー で十分な情報取得が可能
  • UTMパラメータ の乱用に対する批判
  • サイトで 未承認クエリストリング の全面禁止を宣言
  • Caddyfile による技術的実装

URLへのトラッキングパラメータ追加への反対意見

  • 他人がURLにトラッキング用パラメータ を追加する行為への強い不満
  • 自分の管理するURL に勝手にクエリストリングを付与されることへの拒否感
  • 参照元の確認 にはRefererヘッダーで十分という主張
  • Refererが存在しない場合、理由があると考え、追加情報の強制付与を不要と判断
  • ユーザーへの負担やプライバシー侵害 につながる行為として問題視

UTMパラメータの乱用について

  • UTMパラメータ は本来サイト運営者自身が使うものという認識
  • 他者が勝手にUTMパラメータを追加 することへの強い拒否
  • URLの管理権限 は運営者にあるという立場

未承認クエリストリングの全面禁止方針

  • 自サイトでのクエリストリング利用禁止 を宣言
  • 今後クエリストリングを使う場合も、 許可したパラメータのみ許容 方針
  • 過去に使用していたキャッシュバスター用パラメータ (例:?t=…や?h=…)も今後は非対応
  • 正当な理由のないリクエストは破棄 という強い姿勢

実装方法と運営方針

  • Caddyfile による技術実装
  • 自分のサイトは自分で管理 し、他者の干渉を拒否
  • 他人のサイト運営方針を尊重 する立場

関連情報

  • 関連リンク: https://susam.net/no-query-strings.html

Hackerたちの意見

このサイトでは、無許可のクエリ文字列を禁止することにしたんだ。リクエストにクエリ文字列が含まれていると、彼のサイトは(多分間違って)414を返すんだよね。この抗議が、最初からその文字列を管理できなかったユーザーのために行われているなら、なんでそこにあることでペナルティを与えるの?それをヒントにして、ユーザーが自分でどうやってその決定をするか教えればいいじゃん(例えば、ブラウザツールを使って)。

何年も前のことだけど、PLSQLサーバーページのバージョンがあって、知らないクエリ文字列を渡そうとすると500を返してた気がする。

「414 URIが長すぎるって言われてるかもしれないけど、こういう方が面白いと思う。他に考えた選択肢は、400 Bad Request、一般的なクライアントエラーコードで、正しいけどつまらない;402 Payment Required、正直言って、特定のURLをクエリ文字列付きで動かすためにお金を払ってくれるなら、全然OK;404 Not Found、でも副作用が出やすいし、リクエストが不正だったっていうアイデアを伝えられないから、これも違う;303 See OtherでLocationヘッダーなし、最近ではかなり珍しいけど、正当なものだ。RFC 2616では「異なるURIはレスポンスのLocationフィールドで示されるべき」と書かれてたけど、7231と9110ではLocationヘッダーの存在を前提にした言い回しになってるんだよね(「…LocationヘッダーフィールドのURIで示される」)、301、302、307、308は「サーバーはLocationヘッダーフィールドを生成すべき」とも言ってる。まあ、LocationヘッダーなしのSee Otherは妥当だと思うけど、URIが長すぎるのは面白かった。」 https://chrismorgan.info/no-query-strings?foo

実はこれについてすごく興味があって、HTMLとURLのW3C標準に戻ってみたんだけど、驚くことに、パーセントエンコード以外のフォーマットの定義はなかったんだ。クエリ文字列を「form-urlencoded」[0]のクエリ文字列と混同するかもしれないけど、一般的にクエリ文字列はURLの「?」の後に続くパーセントエンコードされた文字列で、レスポンス生成に使える「URL」HTMLオブジェクトの別のプロパティなんだ。さらに、form-urlencodedパーサーでクエリ文字列を解析した結果としてのURLSearchParamsオブジェクトもあるけど、これはJavaScriptのための相互運用レイヤーに過ぎない。正直に言うと、基準を見たときは反対意見を持つつもりだったけど、実際にはかなり明確で、404は予期しないクエリ文字列に対する適切なレスポンスになり得る。クエリ文字列はURL APIの一部であり、パスと同じくらい重要で、ランダムなものをパスに追加するのは良くないし、未定義の動作になることはみんな認められると思う。[0]: https://url.spec.whatwg.org/#application/x-www-form-urlencod... [1]: https://url.spec.whatwg.org/#url-class

パスとクエリ文字列の違いが完全に恣意的で、サーバーによって決まっているって気づくまで待ってみて。クエリ文字列なんて存在するべきじゃなかった。CGIウェブサーバーの実装の詳細があちこちに漏れ出して、今じゃ本当に臭くなってる。

昔はCMSやフォーラムがindex.phpだけで、クエリ文字列でルーティングするのが普通だったよね(フォームURLエンコード形式で、みんな野蛮人じゃなかったし)。だから、index.php?p=homeとかindex.php?p=shopとかあったり。あるいはindex.php?action=showthread&forum=42&thread=17976みたいな感じ。そういう仕組みだと、未知のクエリパラメータに対して404が正しい答えだってすぐにわかるはず。実際、今でもそういうサイトはたくさんあって、SEOのためにapache/nginxのリライトルールの裏に隠してるだけなんだよね。

面白いことに、クエリ文字列を透明に扱うべきところが、その構造についてたくさんの仮定をしていることがあるよね。新しいCDNを選ぶときにそれにぶつかったんだけど、いくつかのプロバイダーは繰り返しのパラメータ(?a=1&a=2)を正しく処理できなかったんだ。

このトーンやクリスの投稿から、クエリパラメータを含めるのは有害だって印象を受けるけど、どうしてそうなるのか理解できない。誰か教えてくれない?クエリパラメータがいくつかのURLを壊す可能性があるのは分かるし、それが理由でやらない方がいいってのも分かるけど、それでもちょっとした不便に感じる。

ああ、いくつか理由があるよ。ユーザーたちは追跡されることに同意していない(これらのクエリパラメータは追跡情報だから)、サイト管理者は受信トラフィックを追跡されたくないんだ。後者は理解しにくいかもしれないけど、例えば、ユーザーに害を及ぼす可能性のある情報がログに残るのは絶対に避けたい。個人的には、メッセージで送るためにリンクをコピーしようとしたとき、追跡コードが元のURLの2倍の長さになってるのが嫌なんだよね…それを整理するために手間をかけるか、送った相手にランダムな文字のスクリーンを見せて「何これ?」って思わせるかのどっちかになるから…だから、ユーザーのプライバシーを侵害してるし、クソなUXだし、そもそも誰もそれを求めてないんだよね…

これに関する人々の問題を知りたいなら、http refererヘッダーについて調べてみてね:https://en.wikipedia.org/wiki/HTTP_referer どんな理由であれ、サイトに自分がどこから来たかを知られたくないことがある。基本的に、訪問しているサイトに自分のブラウジング履歴を共有しているようなものだから。このため、http refererヘッダーには多くの更新があり、送信されるタイミングに制限があったり、機能から完全にオプトアウトできるようになっている。これらの既存のルールやオプトアウトの能力を回避するために、同じ情報を持つURLパラメータを追加するのは良くない。標準を使うべきだよ。

面白いのは、これらのサイトには「検索」機能がないことだね。これは重要なアクセシビリティ機能で、クエリ文字列の明確で正当な使用ケースだと思う。

これは小さな分散型の自己ホスト型ウェブコンソールで、あなたのウェブサイトの訪問者が独立した個人ウェブサイトのオーナーたちが推薦する興味深いウェブサイトやページを探索できるようにするものだ。昔は「ウェブリング」って呼んでたけど、あんまりおしゃれじゃなかった。オープンソースのアプリケーションフレームワークを開発しているときに直面した問題の一つは、FastCGIを使ったホスティングがAuthヘッダーを尊重しないことで、トークンをクエリに渡さざるを得なかったことだ。これが面倒で、ウェブアドレスのコピー&ペーストが本当に問題になった。トークンが含まれることが多かったから。これ、もしかしたら修正されたのかな?私が管理しているバックエンドでは、誰にでも公開する必要がないから、ヘッダーを使ってるよ。

オープンソースのアプリケーションフレームワークで、FastCGIを使ったホスティングがAuthヘッダーを無視してたってこと?つまり、fcgiアプリとしてアプリを書いてたってこと?(例えば)ApacheがAuthヘッダーをうまく処理できてなかったの?もう少し詳しく教えてくれる?PARAMレコードが期待通りの結果を返さないっていう技術的な詳細が気になるんだけど。

元の情報源がHNでまだ議論されてなかったから、そのリンク(https://chrismorgan.info/no-query-strings)を一番上に置いて、レスポンスのリンク(https://susam.net/no-query-strings.html)をトップテキストに移動させたよ。どっちも良いけど、元の方を優先するのがフェアだと思う!

「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エラーは不適切だよ、これはリダイレクトやサーバー側の失敗じゃなくて、クライアント側のリクエストの問題だから。ティーポットか長すぎるのがベストな選択肢だと思う。

もちろんそうだよ。例えば、上から紐を下ろして満水レベルを確認したり、ポットの周りに紐を巻いて円周を確認したりできるよ。

編集: それは違うよ https://news.ycombinator.com/item?id=48077990 「URLにトラッキングのものを追加するのが嫌い」とか「リンクにそれを追加することでユーザーを悪用してる」とか「無許可のクエリ文字列はダメ」とか「今のところクエリ文字列は使ってない」って言ってるのに、なぜか?igshは、確かインスタグラムのトラッキングパラメータだと思うけど、許可されてる。変だね。

?igshは私には通らないし、そのページにはそれを含むリンクも見当たらないよ。

作者の厳しい意見には賛同しないけど、無駄なクエリパラメータが原因でリンクが何千文字にもなるのは嫌だな。リンクを共有する前にクエリパラメータを取り除くために、このブックマークレットを使ってるよ:javascript:(()=>navigator.clipboard.writeText(location.origin+location.pathname))();

これをやってるサイトは初めてじゃないよ。数年前、scarygoround.comがクエリ文字列をブロックし始めたけど、今はそれをやめたみたい。あの頃、Facebookはすべての外部リンクに?fbclid=...を追加し始めてた。

もしかしたら、そういうリンクをたどる人たちに少し不便をかける代わりに、エラーで返すんじゃなくて、「ここにたどり着くためにたどったリンクにはトラッキング用の何かが追加されているようです。もしあなたがランダムなリンクをたどっているボットだったり、より自然な訪問に見せかけるためにランダムなURLを使っている場合は、少しお待ちください。ページに案内する前に、ちょっとしたPoW自動化による抑止を行います。」っていうページを表示するのもありかも。その後、ちょっとした作業(本物のPoWみたいなやつ)をしてからリダイレクトするか、直接リダイレクトせずに、ユーザーがクリックできる素のURLを出力するのもいいかもね(他の人に渡せるように)。もちろん、これで余計なものが追加されるのを止めることはできないけど、エラーも同じだし、潜在的な読者にはあまり不便をかけないから。