nekoTheShadow’s diary

IT業界の片隅でひっそり生きるシステムエンジニアです(´・ω・`)

闘いの記録:CORSを理解するまでの調査メモ

この記事を一言でいうなら、「闘いの記録」です。ここ数ヶ月、とある大規模Webアプリの保守運用に関わっているのですが、その中でCORS対応にどっぷり浸かることになりました。 正直に白状すると、これまでの開発人生でCORSをあんまり意識してこなかったというか、中身についてはお恥ずかしながら詳しくなかったんです。そんなわけで、今回は基礎中の基礎から泥臭く調べ直しました。この記事はその時の「調査メモ」を自分なりに整理してまとめたものです。正直なところ、ネットにある情報を自分なりに解釈し直しただけなので、「わざわざ世に出すほどの内容かな?」と迷うラインではありました。でも、せっかく七転八倒してまとめたので、供養のつもりで公開しちゃいます。ちなみに、普段の技術ネタはQiitaに書くというマイルールがあるのですが、今回の記事はあまりに「自分用の格闘メモ」すぎるので、この個人ブログにひっそりと置いておくことにしました。


はじめに

Webブラウザには「同一オリジンポリシー」という基本的なセキュリティルールが実装されており、異なるドメイン間でのデータ通信が制限されています。

例えば、xxx.com上で動作するJavaScriptからyyy.comのAPIにPOSTリクエストを送信しようとすると、エラーが発生します。

しかし、実際の運用においては、異なるドメイン間で通信を許可する必要が生じる場合があります。これを実現する仕組みがCORS(Cross-Origin Resource Sharing)です。

概要

1. ブラウザによるプリフライトリクエストの送信

ブラウザは、クロスオリジンで「安全でない」とみなされるリクエスト(POSTやPUTなどGET以外のメソッド、カスタムヘッダー付きのリクエスト等)を送信する際、事前にOPTIONSメソッドによるプリフライトリクエストを送信します。

2. サーバーによるCORSレスポンスヘッダーの送信

サーバーはCORS関連のHTTPヘッダーを付与してレスポンスを返します(つまり、サーバー側で設定が必要になります)。

3. ブラウザによるレスポンスヘッダーの検証

ブラウザは、以下の条件を確認します。

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Methods
    • リクエストで指定したHTTPメソッド(例: POST、PUTなど)が許可されているか。
  • Access-Control-Allow-Headers
    • リクエストで使用するカスタムヘッダー(Content-TypeやAuthorization等)が許可されているか。

これらの条件がすべて満たされていれば、リクエストは許可されたと判断されます。条件を満たさない場合、リクエスト自体が送信されず、JavaScript側でエラーとなります。

4. 本来のリクエストの送信

ブラウザが条件をすべて満たしていると判定した場合、実際のリクエスト(GET, POST, PUTなど)が送信されます。

5. サーバーによるリクエスト処理とCORSレスポンスヘッダーの付与

サーバーは、リクエストが同一オリジンかクロスオリジンかに関係なく、通常どおりリクエスト内容を処理します。ただし、レスポンスにもCORS関連のヘッダーを付与する必要があります。

6. ブラウザによる最終判定とJavaScriptからのアクセス制御

ブラウザはレスポンスヘッダーを確認し、Access-Control-Allow-Originが自身のオリジンと一致していれば、JavaScriptからレスポンス本文にアクセスできます。一致しない場合、レスポンス本文へのアクセスはブロックされ、CORSエラーとなります。

発生条件

CORSは、JavaScriptによるクロスオリジンのAPIアクセス(fetch、XMLHttpRequest、画像の読み込みなど)に対するセキュリティ制約です。フォーム送信やリンククリックによるページ遷移には適用されません。例えば、JavaScriptでフォーム送信を実行した場合、CORS認証やプリフライトリクエストは発生しません。サーバー側でリダイレクトやエラーが返されることはありますが、CORSエラー(JavaScriptによるレスポンスのブロック)は生じません。

fetch APIにおけるレスポンス種別

fetch APIを利用してクロスオリジンリクエストを行う際、CORSの設定やリダイレクトの有無によって、返されるレスポンスの「種別(typeプロパティ)」が変化します。これにより、JavaScriptからアクセスできる情報の範囲が制限されます。

リクエストの状況に応じたレスポンス種別の判定フローは以下の通りです。

レスポンス種別の詳細

判定された各 typeによって、JavaScriptからアクセスできる情報の範囲が以下のように制限されます。

  • basic
    • 同一オリジンへのリクエスト、またはCORSを介さないリクエストで返されます。レスポンスボディ、ヘッダー、ステータスコードのすべてにアクセス可能です。
  • cors
    • CORSが正しく許可されたクロスオリジンリクエストで返されます。レスポンスボディと、特定の制限されたヘッダー(および Access-Control-Expose-Headers で許可されたもの)にアクセスできます。
  • opaque
    • no-cors モードで送信されたリクエストの結果です。セキュリティ上の理由から、レスポンスの内容(ボディやヘッダー)は一切読み取れず、ステータスコードも一律で 0 となります。
  • opaqueredirect
    • リダイレクト(3xx)が発生し、そのリダイレクト先がクロスオリジンである場合に返されることがあります。opaque 同様、内容へのアクセスは制限され、ステータスコード0 になります。

Tips

  • 異なるドメインへの通信でも、プリフライトリクエストが送信される場合と送信されない場合があります。詳細については、以下のURLを参照してください。
  • Chromeではセキュリティ上の理由から、開発者ツールのネットワークタブでプリフライトリクエストの内容を確認できません。プリフライトリクエスト自体が送信されているかどうかも確認できないため、専用ツールや拡張機能の導入が必要です。なお、Firefoxの開発者ツールでは確認可能です。
  • 本リクエストのレスポンスが3xx(リダイレクト)ステータスの場合、ブラウザはリダイレクト先に自動的にリクエストを送信します。リダイレクト先がクロスオリジンである場合、リダイレクト先のサーバーでもCORSヘッダーを返す必要があります。ヘッダーが返されない場合、ブラウザはそのレスポンスをブロックし、JavaScriptから結果を取得できません。

読書記録③『Python Django本格入門』『実務で役立つ ログの教科書』『システムの引き継ぎに失敗しないための本』『サイバー攻撃 その瞬間 社長の決定』

気づけば3回構成になってしまった読書メモの続きです。ここまで来たので最後までまとめておこう、という気持ちで書いている3回目です。


Python Django本格入門』

honto.jp

FWについては、定期的に勉強したいと思っていて、なかでもDjangoは少し気になっているFWだったので、そういう意味ではドンピシャの1冊でした。簡単なアプリケーションを実装しながら、Djangoの機能を一通り学べる内容で、Djangoのとっかかりにはよかったかと思います。写経スタイルなところも、個人的には好みでした。Type Hintをまったく取り入れていないこと、レスポンスがHTMLばかりで、JSONを返させる例がないこと。このあたりがややひっかかりましたが、全体的には満足ですね。

『実務で役立つ ログの教科書』

honto.jp

コンピューターにかかわっていて、ログというのは避けて通れないものですが、しかし、本としてまとまっているものは意外にないということで、発売直後に買って読んだ1冊です。教科書と名乗るにふさわしく、ログとは何かというところから、その活用法にいたるまで、ログにかかわるトピックを包括的に扱う内容になっています。ログといっても、PCのイベントログからWebシステムのアプリケーションログまで、さまざまな種類があります。活用法も千差万別。監査やマーケティング、あるいは、昨今はやりのAIにいたるまで、幅広い内容をぎゅっとまとめています。特殊なユースケースにすぐ適用できるような即効性がある内容にはなっていませんが、しかし、基礎的な部分を再度整理しなおすというところでは、読んでよかったと思いました。

『システムの引き継ぎに失敗しないための本』

honto.jp

システムを担当している担当者やベンダーがいなくなるというのがIT業界にいると意外にあることで、計画的に交代することもあれば、急にいなくなることも少なくないと聞いています。本書はそういうシステムのノウハウをまとめており、珍しい視点ではあるのですが、確実に需要のある本ではあります。内容も全体的に納得感のあるものとなっており、きわめて実践的・実務的であると感じました。自分はベンダー側の人間なので、どちらかといえば引き継ぐ側の人間ですが、引継ぎが発生した場合には、本書を参考によい引継ぎをしていきたいと思いました。

サイバー攻撃 その瞬間 社長の決定』

honto.jp

技術書ではないんですが、ITにかかわる本なので、読書メモを残しておきます。関通という物流会社がランサムウェアの被害にあったときのことを社長自らが記した1冊です。本として洗練されているとは言い難いので、若干読みづらさはありますが、攻撃を受けた側が何を考えて、どう行動したのかを当事者が記録しているというのは珍しく、目から鱗な話も多く面白く読みました。あとは、この本を紹介しているYoutube動画もおすすめです(というかこれに影響されて買った)

www.youtube.com

読書記録②『SQLアンチパターン 第2版』『分散システムのためのデザインパターン』『ソフトウェア設計の結合バランス』

最近読んだ技術書のメモを書いていたら、思った以上に分量がふくらんでしまいました。というわけで、前回に続いての2回目です。自分の備忘録も兼ねて、ゆるっと残しておきます。


SQLアンチパターン 第2版』

SQLアンチパターン 第2版www.maruzenjunkudo.co.jp

初版はむかしむかしに読んでいて、引っ越しの際に捨ててしまったのですが、新版が出ると聞いて、買いなおし&読み直しました。いわずとしれた名著なので、内容はいわずもがなよかったです。いろいろ経験したこともあって、昔読んだときより学びが深まったような気がします。SQLに触れるITエンジニアであれば必読でしょう。

『分散システムのためのデザインパターン

honto.jp

ここ数か月に読んだ技術書の中では、とびぬけて骨のある1冊でした。まず前半で、MongoDBやTiDBのような分散システムがどのように動いているのかについて、その概要・全体像を解説。後半では、前半で紹介した全体像をもとに、整合性をとりながら分散システムをうまく動かす仕組みをパターンとして紹介します。分散システムの専門家でもないので、全部を理解できたわけではないのですが、これまでのシステムエンジニア経験でいろいろ聞きかじってきたワードの概要ぐらいはわかったと思います。今後、仕事で何かかかわることがあったら、辞書的に開くことになりそうです。

『ソフトウェア設計の結合バランス』

honto.jp

これは面白かった!世の中にはモジュールを分割するテクニックはあふれていますが、しかし現実には、モジュールどうしを結合して初めてシステムというのは出来上がるわけです。本書はこのモジュールの結合について、深く議論した1冊です。そもそもの命題設定自体もかなり面白いですが、なかで展開される議論や尺度についても、あまり考えたことがなかったような斬新な視点ばかりで、これからのソフトウェアアーキテクチャやソフトウェア設計を語るうえでニュースタンダードになる気がします。よい結合・あるべき結合について、本書はわかりやすい結論のようなものを提示するわけではないですが、逆にそれも本書の価値をあげている気がします。システムアーキテクトを名乗る人はみな読むべき1冊だと思いました。

読書記録①『エンジニアのためのWord再入門講座 新版』『JavaScript/TypeScript実力強化書』『Exercise JavaScript』『型システムのしくみ』

最近読んだ技術書のメモを書いていたら、思ったより長くなってしまいました。というわけで、全3回に分けてまとめています。まずはその1回目として、ここしばらく読んだ本を簡単に振り返ります。


『エンジニアのためのWord再入門講座 新版』

honto.jp

仕事でWordをがっつり使うかもしれなかったので、読んだ本(結局使わなかった)。大学生の卒論以来、Wordをまともに使ったことがなかったので、Wordの思想や便利な機能を知れたのはよかったです。筆者がおすすめするWordテンプレートを配布してくれたらもっとよかったですね。

JavaScript/TypeScript実力強化書』

honto.jp

TypeScriptを利用する仕事に就くとなって、読んだ本になります。いろいろな著者が書いた雑誌の記事をまとめたものなので、内容やレベル感は正直まちまちではあります。初歩的な記事はともかくとして、やや発展的なトピックを扱った記事については、知らないことも多かったので、勉強になりました。自分のような初心者以上上級者未満向けの内容の本は珍しいので、貴重な1冊だと思いました。

『Exercise JavaScript

honto.jp

あんまり期待せずに読んだのですが、結構面白かったです。JavaScriptのニッチな仕様をクイズ形式で紹介するという、それはそれでニッチな需要に応えた本なのですが、なんとなくでJavaScriptに向き合ってきた自分にとっては、かなり勉強になりました。とくに巻き上げ関連の仕様はぜんぜん知らなかったので、この本を読んでいてよかったなと思いました。ページ数は少なめ、内容もぎっしり詰まっている感じではないので、自分のようなJavaScriptよわよわ勢にはおすすめです。

『型システムのしくみ』

型システムのしくみ TypeScriptで実装しながら学ぶ型とプログラミング言語www.maruzenjunkudo.co.jp

個人的にはここ数か月で一番のヒットでした。TypeScriptのサブセット言語の型検査器を自作することで、型システムの基礎を学ぶ1冊です。実際に手を動かすと、字を読んでいるより、ずっと実感がわいて、いいですよね。知的好奇心を満足させることもさることながら、TypeScriptを利用する仕事についているということで、仕事に直結しました。筆者はTAPLの入門書・副読本として読んでほしいとしていますが、自分のようにそこまで進まなくても、型のあるプログラミング言語の利用者であれば、かなり勉強になると思います。

最近見かけて感心したJavaのイディオム

いつもこの手の記事はQiitaに書くのですが、Qiitaに書くにはあまりに公益性がないので、エッセー的に残しておきます。

問題:以下のJavaコードは何をしているでしょうか?

String[] words = {"apple", "banana", "apple", "orange", "banana", "apple"};
Map<String, Integer> counter = new HashMap<>();
for (String word : words) {
    counter.merge(word, 1, Integer::sum);
}
IO.println(counter);

正解:配列内の単語の出現回数を数えて、各単語が何回出現するかをカウントしています。

どこで見かけたのか、どういうきっかけで見かけたのかは忘れてしまったのですが、最近見かけて個人的に興味を引かれたイディオムです。Mapの要素更新にmergeメソッドを使うという発想が自分の中になかったので、思わず唸ってしまいました。

とはいえ、イディオムすぎて実用性は微妙かもしれません。好みの問題もありますが、同じことをするならStreamを使うほうが宣言的でやりたいことが明確だと思います。

String[] words = {"apple", "banana", "apple", "orange", "banana", "apple"};
Map<String, Long> counter = Arrays.stream(words)
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
IO.println(counter);

mergeメソッド ← こいつの存在を忘れがちなので、思い出すきっかけになっただけでも、よかったとしましょう。

読書メモ③:『Web アプリケーションアクセシビリティ』『プロを目指す人のための TypeScript 入門』『フルスタックテスティング』『実践プロパティベーステスト』

3回に分けて書いている読書メモ、いよいよ最終回です。今回も最近読んだ本のメモをざっくり紹介していきます。

Web アプリケーションアクセシビリティ

honto.jp

Web アプリケーションは、多様な人に使われます。なかには身体に制約を持つ方、認知に障害を持つ方もいるわけで、誰にとっても使いやすいアプリケーション設計は必須です。本書は、それを実現するための実践ガイドとして、HTML/WAI-ARIA の基礎から、フォーム改善、複雑な UI パターンへの適用、そして組織的導入までを段階的に解説しています。現場で「今日から始められる」改善手法を、豊富な事例とタスクで示している点も魅力です。

自分もこれまでは「アクセシビリティは大事だろう」という抽象的な理解しか持っておらず、具体的な方法論はまったく知りませんでした。本書を通じて、そのギャップを大いに埋められたと感じます。サーバーサイド技術者として、ユーザー層が限られた社内システムばかり扱っている私にとっても、こうした視点は軽視できないテーマです。もっと多くの人に読まれるべき本だと思いますし、自分でも実践していきたいと思いました。

プロを目指す人のための TypeScript 入門

honto.jp

Vue3の勉強をするなかで、TypeScript の理解が不十分だと痛感し、急遽この本を読みました。本書は、JavaScript の仕様を踏まえながら、TypeScript 独自の機能や型システムを丁寧に解説しており、単なる基礎知識の列挙にとどまらない、実践的なノウハウがふんだんに盛り込まれています。特に型システムの理解が深まったのは、自分にとって大きな収穫でした。

フルスタックテスティング

honto.jp

UI 層からデータ層まで、10 のカテゴリにまたがるテスト手法を体系的に整理した一冊です。テストの技法を多方面から紹介する書籍は意外と少ないため、私にとっては非常に学びになる内容でした。各手法について、具体的なツール活用例も取り上げられており、「すぐに手を動かす」ための知見が詰まっている点も評価できます。

実践プロパティベーステスト

実践プロパティベーステスト ― PropErとErlang/Elixirではじめようwww.maruzenjunkudo.co.jp

フルスタックテスティング』で紹介されていたのがきっかけで手に取った本です。プロパティベーステストという手法はこれまで私には未知で、読んでよかったと思います。例示コードは Erlang/Elixir でしたが、自分は Java + jqwik に写経しながら読み進めました。jqwik も初見だったので、そこからの学びも大きかったです。

ただし、生成 AI によってテストコードを量産できる時代において、プロパティベーステストの優位性や適用範囲を考察する必要があるな、という思いも残りました。しかし本書そのものは丁寧に書かれていて良書だと思います。

読書メモ②:『JavaScriptレスの動的 UI 開発 htmx 入門』『Vue3 フロントエンドの教科書』『システム運用アンチパターン』『ソフトウェアテスト徹底指南書』

前回に続いて、最近読んだ本の読書メモを紹介します。全部まとめると長くなりすぎるので、3回シリーズにしていて、今回はその2回目になります。

JavaScriptレスの動的 UI 開発 htmx 入門

honto.jp

htmx という名前は聞いたことがあっても、詳しい仕組みは知らない状態で読んだ本です。ひと言で言えば、htmx の基本機能を簡潔に整理した上で、後半に実践的なアプリケーションを構築する流れまで踏み込んでおり、基礎から応用まで学べる構成になっています。

htmx は “HTML に便利な機能を追加する” というアプローチのフレームワークなので、リッチなクライアント機能を必要としないケースには適していると感じます。ただ、状態管理を複雑に扱おうとすると難しさが出てきそう、という印象もあります(その点では、jQuery やバニラ JS でも十分対応できるケースも多いのでは、という思いも残ります)。総じて、htmx に興味があるなら、少ない類書のなかでも有力な選択肢になる本だと思います。

Vue3 フロントエンドの教科書

honto.jp

Vue3 関連の仕事にアサインされたため、キャッチアップを目的に読んだ一冊です。Vue3 の基本機能やよく使われるライブラリが網羅的かつわかりやすく解説されており、Vue3 入門書として非常に良くできている印象を持ちました。私は以前に Vue2 を使っていた経験があったので、その知識のアップデートにもなりましたし、実務でも役立っています。

ハンズオン形式である点は好みです。ただ、各セクション開始時に npm init を都度行う構成になっているのがやや煩わしく感じる場面はありました。

システム運用アンチパターン

システム運用アンチパターンwww.maruzenjunkudo.co.jp

運用・保守の現場では、しばしば似たような“やってはいけない”状況に遭遇します。本書はそうした状況をアンチパターンとして整理し、それぞれの原因と対処法を解説しています。個人的には、DevOps を文化として捉える視点が特に興味深かったです。DevOps を導入するには、自動化や技術面だけでなく、組織文化として根付かせていくことが不可欠で、それには発信力や人を巻き込む力が求められる――という指摘には強く共感しました。

また、本書はマネージャやアーキテクトだけでなく、一般のエンジニアにも視点を向けて書かれている点も好印象です。組織上層部だけで改善を進められるわけではなく、現場レベルの技術者が改善の種をまけるような示唆も多く含まれています。体系的な DevOps 解説ではないものの、アンチパターンという切り口を入り口に現場改善へつなげる意味では、とても実践的な良書だと感じます。

ソフトウェアテスト徹底指南書

honto.jp

ソフトウェアテストに関する知見を、極めて包括的かつ体系的に整理した一冊です。全43章にわたって、テスト設計、マネジメント、モニタリング、リスク管理、テスト自動化など、あらゆる領域を網羅しています。内容量が非常に多いため、一気通読は根気を要しますが、それだけの価値があります。業界で話題になったのも納得の出来です。情報量と実践性のバランスが優れており、学習者にも実務者にも手元に置いておきたい良書だと感じました。

特に印象に残ったのは、品質管理とテストを全体で統合的に捉える章立てと、プロジェクトリスクやモニタリングの章の実践的な示唆です。読んでいくうちに、自分の足りなさを思い知らされるような、いわば“教えられる側”に立たされる感覚もありました。