SpringSecurityでCORSの設定を行ってみる

CORS

CORS (Cross Origin Resource Sharing) はHTTPヘッダーを使用して異なるオリジン間でリソースを共有する仕組み。サーバーがクライアントのリクエストに対して以下のヘッダーを用いて応答し、どのオリジンに対して許可しているかを示す。

  • Access-Control-Allow-Origin アクセス可能な外部のドメインを指定
  • Access-Control-Allow-Methods アクセス可能なHTTPメソッドを指定
  • Access-Control-Allow-Headers 外部ドメインで使用するヘッダを制限する

CORSは認証や認可のように特定のエンドポイントを保護する仕組みではない。異なるドメイン間の呼び出しの制限を緩和する仕組みになる。なので、CORSを許可していないエンドポイントを呼び出すこと自体は可能になる。

注意しなくてはいけないのはCORSはあくまでもクライアント(ブラウザ)のセキュリティであり、リクエストを受け取るサーバーはCORSの設定有無に関わらずリクエストの認証認可、サニタイジングを行わなくてはいけない。よくある誤解としてCORSにより許可されていないリクエストはサーバーで処理されないと思われがちだが、それは間違いである。

サンプルコード

SpringSecurityでCORSの設定をするには以下のようにする。

@RestController
public class MainController {

    private Logger logger =
            Logger.getLogger(MainController.class.getName());


    @PostMapping("/test")
    @CrossOrigin("http://localhost:8080")
    public String test() {
        logger.info("Test method called");
        return "method called";
    }

}

SpringSecurityでは @CrossOrigin をコントローラーのメソッドにつけることでCORSのヘッダーをレスポンスに追加できる。上記の例では localhost:8080 ドメインのリソースから呼び出すことができることを示している。

オリジン

CORSでは同一オリジンポリシーに従って制限を行う。同一オリジンポリシーとはオリジンが同じか、違うのかを定めるものであり、オリジンの定義に基づく。オリジンとはプロトコル、ポート番号、ホストの組み合わせのことでこれらが一つでも異なるものは同一のオリジンとは判断されない。

例えば以下のオリジンがあったとする。

http://example.com/index.html

上記のオリジンと同一オリジンと判断されるのは以下のようなオリジンになる。プロトコル(http)、ポート番号(省略のためウェルノウンポートの80)、ホスト(example.com)が同じになる。パスは異なるが、オリジンの定義にパスは含まれていないので異なるパスであっても同一オリジンとして判断される。

https://ja.wikipedia.org/wiki/TCPやUDPにおけるポート番号の一覧

http://example.com/admin/users.html

異なるドメインと判断されるのは例えば以下のようにプロトコルが異なる場合などになる。

https://example.com/index.html

外部リンク

CORSについて参考にしたサイトはこちら。ここでは書いていないが単純リクエストとプリフライトリクエスト、資格情報を含むリクエストについても重要な情報だと思う。