CORSエラー、君は誰だ?
CORSエラー、君は誰だ?

CORSエラー、君は誰だ?

작성자
ユミンユミン
카테고리
Dev.Log
작성일
2024년 03월 28일
태그
Error
Project
Go
CS
notion image
 

問題の発生

Ginフレームワークを使用してAPIを構築する過程で、次のようなCORS関連のエラーが発生しました:
Access to XMLHttpRequest at '${Gin ip Link}' from origin '${Frontend Origin URL}' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 
このエラーは、サーバーが特定のオリジンからのリクエストを拒否する際に生じます。通常、ブラウザはセキュリティ上の理由から、異なるオリジンへのスクリプトによるリソースへのアクセスを制限しています。これを「同一オリジンポリシー」といい、CORSはこのポリシーの柔軟な運用を可能にします。
 
以前のCORS設定は以下のようになっていました:
router := gin.Default() router.Use(cors.New(cors.Config{ AllowOrigins: []string{"http://localhost:3000", "http://127.0.0.1:3000"}, AllowMethods: []string{"GET", "POST", "PATCH", "PUT", "DELETE"}, AllowHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization"}, ExposeHeaders: []string{"Content-Length"}, }))
しかし、この設定では望まれる動作をせず、エラーが発生しました。
 

問題解決のアプローチ

CORS設定を以下のように変更しました:
router.Use(CORS()) // 新たに定義したCORSミドルウェアの使用 ... func CORS() gin.HandlerFunc { return func(c *gin.Context) { c.Writer.Header().Set("Access-Control-Allow-Origin", "http://localhost:3000") // 認証情報を含むリクエストを許可 c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") // 必要なヘッダーを明確に設定 c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With") c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, PATCH, GET, PUT, DELETE, OPTIONS") // OPTIONSリクエストに対しては204 No Contentを返す if c.Request.Method == "OPTIONS" { c.AbortWithStatus(204) return } c.Next() } }
この変更により、Access-Control-Allow-Originを特定のドメインに限定し、CORSポリシーに従って必要なヘッダーを明確に設定しました。これにより、もともと発生していたエラーを成功的に解決することができました。
 

CORSとは?

notion image
CORS(Cross-Origin Resource Sharing)は、異なるドメイン間でのリソース共有を可能にするためのウェブブラウザのセキュリティメカニズムです。これにより、ウェブページは異なるオリジン(ドメイン、スキーム、ポートが異なる場所)のリソースにアクセスできるようになります。同一オリジンポリシーによる制限を緩和しながらも、セキュリティを確保することが可能です。
 

Origin

https://google.com:80/search?page=1
このURLは私たちが毎日目にするGoogleのURLです。
上記の構成要素のうち、Protocol(https://) + Host(google.com) + Port(80) 3つが同じなら同じソース(Origin)と言います。
 

CORSが必要な理由

私たちはウェブで <img> <script> <frame> <video> タグを使用しながら、新しいリソースを外部から取り込むことができます。
もし、銀行のホームページに入ったら、悪質なコードが植えられた<script>ファイルが含まれているevil.comページを開いたらどうなるでしょうか?
notion image
残念ながら、scriptファイルにDelete/accountリクエストが含まれていて、ページを開くとすぐにユーザーのアカウントが削除されてしまいました。
このような予期せぬ事故を防ぎ、セキュリティを強化するため、他のソースからのアクセスを防ぐポリシーが登場しました。
 

同一原産地政策 (Same-Origin Policy)

そのため、同じソースからしかリソースを共有できないというポリシーを使うようになりました。
ここで、同じソースとは、クライアントとサーバーが同じソースにある場合は同じソースであり、別のサーバーにある場合は別のソースとして扱います。
notion image
例えば、上の写真でdomain-a.comのユーザーがdomain-b.comのサーバーにリクエストすると、ホストが違うので他のソースにリクエストした状態です。
 
ドメイン以外にも同じプロジェクト内で定義されたcssファイルに対するリクエストは同一ソースリクエストであり、フォントの場合、googleのような外部サイトからリソースを取得する場合は別のソースリクエストと言えます。
 
しかし、このように厳密にブロックしてしまえば、好きなページを作ることができるのでしょうか🤔?
オープンなインターネット環境では、他のソースからリソースを取り込んで使用することはよくあることです。
 
そのため、いくつかの例外規定を設け、他のソースからのリソースを許可するポリシーが登場しました。
それは、CORSのポリシーを守ったリソースリクエストです!
 

その他のソースポリシー

実際、私たちを悩ませたCORSの真っ赤なエラーメッセージは、他のソースからリソースを取得するための解決策でした。
同一ソースポリシー(SOP)に違反してもCORSのポリシーを守れば、他のソースのリソースも呼び出すことができるようになるのです!
では、どのようにCORSエラーを解決することができるのでしょうか?
まず、ブラウザでのCORSの動作過程について説明します。

1.クライアントからHTTPリクエストのヘッダーにOriginを入れ、転送

notion image
Webはサーバーにリクエストを送る際にHTTPプロトコルを利用します。
このとき "ここから来ました"を表す Origin という値をリクエストヘッダに載せて送ります。
 

2.サーバーは応答ヘッダにAccess-Control-Allow-Originを入れ、クライアントに転送

notion image
サーバーはリクエストを受け取った後、クライアントにこの「このURLはリソースにアクセスできますよ」Access-Control-Allow-Originフィールドに入れて応答します。
 

3.クライアントからの応答を比較し、ブロックの可否を決定します。

ブラウザは自分が送ったリクエストのOriginとサーバーが送ったAccess-Control-Allow-Originの値を比較して、応答を使うかどうかを判断します。
もし一致しない場合、応答を使用せずに破棄し、このような状況がCORSエラーに該当します。
 

CORSの設定方法と注意点

AJAXリクエストにおける認証情報の扱い方

  • 通常、AJAXリクエストでは認証情報(クッキー、認証ヘッダー、TLSクライアント証明書など)が自動的に含まれません。
  • 認証情報を含むAJAXリクエストを送信するには、特定の設定が必要です。

withCredentialscredentials引数の設定

  • XMLHttpRequestを使用する場合: withCredentials引数をtrueに設定します。これにより、ブラウザはクロスオリジンリクエストにクッキーや認証ヘッダーを含めるようになります。
  • Fetch APIを使用する場合: credentials引数をincludeに設定します。これにより、クロスオリジンリクエストにも認証情報が含まれるようになります。

CORS設定でのオリジン指定の重要性

  • 認証情報を含むリクエストをAPIサーバーに送信する場合、サーバーはAccess-Control-Allow-Credentials: trueヘッダーを含む応答を返します。
  • クライアントは、このヘッダーが応答に含まれていない場合、リクエストを拒否します。
  • セキュリティ上の理由から、APIサーバーでCORS Credentialを許可する場合、オリジンを具体的に指定する必要があります。ワイルドカード(*)は使用できません。
 

結論

CORS問題はウェブ開発で頻繁に直面する課題の一つです。この記事を通じて、CORS設定の重要性と適切な設定方法を理解し、将来的なCORSエラーに効果的に対応できるようになることを願っています。
 

댓글

guest