🐿️

Basic認証のCORSエラーに対応する

2024/04/18に公開

はじめに

Basic認証のリクエストでCORSエラーが発生した時に対応した方法についてまとめます。

CORSとは

CORS(Cross-Origin Resource Sharing)とは、異なるオリジン(ドメイン、プロトコル、ポート番号)間でのリソース共有を制御する仕組みです。
ブラウザのセキュリティポリシーにより、異なるオリジンからのリクエストに対してはデフォルトでアクセスが制限されます。

CORSエラーの原因

CORSエラーは、次のような原因で発生する可能性があります。

  • サーバーが適切なCORSヘッダを返さない場合
  • リクエストの起点となるオリジンが許可されていない場合
  • リクエストに認証情報が含まれており、サーバーが適切な設定をしていない場合

Basic認証なしのCORSリクエストの対応

まずは、Basic認証なしの通常のCORSリクエストの対応方法です。

  1. CORSリクエストを送信します
    今回はXMLHttpRequestを使用してリクエストを送信します。

    request.js
    function httpRequest(url) {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4 && xhr.status === 200) {
                console.log(xhr.responseText);
            }
        };
        xhr.send();
    }
    
  2. サーバ側で適切なCORSヘッダを返していない場合は、CORS policyのヘッダエラーが返ります

    blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
    
  3. サーバ側で適切なCORSヘッダを返す様に設定します

    httpd.conf
    <IfModule mod_headers.c>
        Header set Access-Control-Allow-Origin "*"
        Header set Access-Control-Allow-Methods "POST, GET, OPTIONS"
        Header set Access-Control-Allow-Headers "Content-Type, Authorization"
    </IfModule>
    
  4. サーバ側で適切なCORSヘッダを設定すると、正常なレスポンスが返る様になります

Basic認証ありのCORSリクエストの対応

Basic認証ありのCORSリクエストでは、CORSヘッダを返すだけでは不十分です。
(ここでは、Basic認証なしのリクエストで対応した『サーバ側で適切なCORSヘッダを返す設定』は、既に対応していることを前提に進めます)

  1. Basic認証ありのCORSリクエストを送信します

    request.js
    function httpRequest(url, username, password) {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
    
        // Basic認証を設定
        var credentials = btoa(username + ':' + password);
        xhr.setRequestHeader('Authorization', 'Basic ' + credentials);
    
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4 && xhr.status === 200) {
                console.log(xhr.responseText);
            }
        };
        xhr.send();
    }
    
  2. サーバ側でCORSヘッダを返す様に設定していても、CORS policyのpreflightリクエストエラーが返ります

    blocked by CORS policy: Response to preflight request doesn't pass access control check
    

    レスポンスヘッダを確認すると設定したはずのヘッダが入っていません。

     
    色々と調査した結果、Basic認証のCORSリクエストでは、最初にpreflightリクエストでOPTIONSメソッドを送信し、サーバからOKレスポンスを受け取ると、続けてGETメソッドを送信して、レスポンスデータ受け取るという2段階の通信をおこなっているのですが、最初のOPTIONSメソッドではBasic認証のAuthorizationヘッダが入らないので、Basic認証が通らないことが分かりました。
     
    更に、認証を必要とする様なレスポンスデータは2番目のGETメソッドのレスポンスとして返却される為、GETメソッドのBasic認証が有効であれば、最初のOPTIONSメソッドのBasic認証は必ずしも必要無いことが分かりました。
     

  3. OPTIONS以外のメソッドのみ、Basic認証を行う様に設定します

    .htaccess
    <LimitExcept OPTIONS>
      AuthUserFile    /home/www/example/.htpasswd
      AuthName        "your ID and password"
      AuthType        Basic
      Require valid-user
    </LimitExcept>
    
  4. Basic認証で正常なレスポンスが返る様になります


    最初のOPTIONSメソッド

    2番目のGETメソッド
     

  5. Basic認証で誤ったIDやパスワードを指定するとGETメソッドでエラーが返ります

    最初のOPTIONSメソッド

    2番目のGETメソッド

 
ブラウザのキャッシュが残っていると上手く反映されない場合があるので、適宜キャッシュをクリアしてください。

参考

レスキューナウテックブログ

Discussion