しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

IIS CORS Module を試してみた

割と旬を逃した感じはしますが、IIS 側で CORS の設定を行える拡張モジュールがリリースされています。

もっと早くリリースされていれば、苦労しなかったシーンが個人的にちらほら。これまでは URL Rewrite で頑張ってた人も多いのではないでしょうか。

インストールすると CORS が扱えるようになりますが、IIS Manager から簡単に設定できるヘルパー的なものは用意されていないので、Configuration Editor から設定するか、Web.config を編集する必要があります。

f:id:shiba-yan:20171218112421p:plain

個人的にはまず Configuration Editor で適当に触ってみるのが簡単でお勧めです。設定に関するドキュメントも既にちゃんと用意されているので、CORS の知識が少しあれば簡単に有効に出来ます。

f:id:shiba-yan:20171218112519p:plain

しかしながら、既に ASP.NET MVC / Web API / Core を使っている場合は、フレームワーク側に CORS 機能が組み込まれているので、あまり必要性を感じないかも知れませんが、API 全体で同じポリシーを適用したい場合には便利だと思いました。

ちなみに Web API で CORS を有効化したい場合には、以下のドキュメントを参照ください。

あと、個人的には属性に全ての設定を詰め込むよりも、XML でオリジン別に設定を定義できる IIS CORS Module の書き方の方が好きです。

ドキュメントにあるサンプル定義を見ると、EnableCors 属性に詰め込むよりわかりやすいです。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <cors enabled="true" failUnlistedOrigins="true">
            <add origin="*" />
            <add origin="https://*.microsoft.com"
                 allowCredentials="true"
                 maxAge="120"> 
                <allowHeaders allowAllRequestedHeaders="true">
                    <add header="header1" />
                    <add header="header2" />
                </allowHeaders>
                <allowMethods>
                     <add method="DELETE" />
                </allowMethods>
                <exposeHeaders>
                    <add header="header1" />
                    <add header="header2" />
                </exposeHeaders>
            </add>
            <add origin="http://*" allowed="false" />
        </cors>
    </system.webServer>
</configuration>
CORS Module Configuration Reference | Microsoft Docs

現実問題としてオリジン別に定義することが多いかは微妙かも知れませんが、許可するヘッダーや HTTP Method の設定が分かりやすいですし、オリジンにはワイルドカードが使えるのがかなり良さそうです。

上の例では https://*.microsoft.com と書いてあるので、microsoft.com のサブドメイン全体からの設定を行えるようになっています。これは便利。

最近は JavaScript のような静的ファイルに対しても CORS の設定を正しく行っておかないと、エラーを上手くキャッチできないらしいので、今回の IIS CORS Module は有用な気がします。

CDN を Web サーバーの上に被せつつ、別ドメインにするという方法も良く使われているので、CORS の設定は地味ながら重要という立ち位置なんだと再認識しました。

長々と書いてしまいましたが、実際に IIS 10.0 と ASP.NET Web API のサンプルを使って動作を確認しておきました。当然ながら IIS CORS Module は後ろに ASP.NET などのアプリケーションが居ても使えます。

よくある例

外部リソースを参照する時に CORS 設定が有効になるか試します。楽するために scirpt タグを使いました。

<script src="http://***/jquery-3.2.1.min.js" crossorigin="anonymous"></script>

これで別オリジンからページを読み込むと、クロスオリジンリクエストになるので、IIS CORS Module がちゃんとヘッダーを返してくれます。

f:id:shiba-yan:20171218153730p:plain

設定でオリジンを * にしたので、無条件で有効になっています。なので意図した挙動です。

preflight が発生する例

苦労しそうなのが preflight リクエストが発生する場合です。preflight は OPTIONS として投げられるので、ASP.NET でハンドリングする場合は Web.config を修正したりと、これが地味に面倒。

IIS CORS Module では preflight リクエストも自動的に処理してくれるので、後ろにいるアプリケーションは CORS のことを考える必要がないというのも、メリットの一つですね。

実際に別オリジンから preflight になるリクエストを投げると、ちゃんと OPTIONS が処理されます。

f:id:shiba-yan:20171218155720p:plain

Pragma や Cache-Control が付いていないので、ASP.NET に届く前に処理されていることが分かります。

preflight で問題なければ実際のリクエストが投げられて、こっちは ASP.NET 側で処理されます。

f:id:shiba-yan:20171218155731p:plain

もちろん、CORS 設定でオリジンやヘッダーを許可しない場合にはエラーになります。

f:id:shiba-yan:20171218165400p:plain

アプリケーションに手を加えることなく、CORS を有効化できるのは割と便利でした。XML での設定に関しては賛否両論ありそうですが、属性に詰め込むのよりは圧倒的に可読性とメンテナンス性が高いと思います。

URL Rewrite や customHeaders で CORS ヘッダーを書き出している場合は、乗り換えるのはアリです。