web-dev-qa-db-ja.com

Chrome v37 / 38 CORSが失敗しました(再度)OPTIONSプリフライトリクエストの401で)

Chromeバージョン37以降、すべてのCORSヘッダーが正しく設定されていても、サーバーで認証が有効になっている場合、プリフライトされたクロスドメインリクエストは(再び)失敗します。これはlocalhost(私の開発PC)にあります。

一部の人は、特にHTTPSが関係していたとき、Chrome/CORS/authバグの履歴を知っているかもしれません。私の問題はnotHTTPSに関係しません:HTTPベーシック認証が有効になっているlocalhost:8383上のJava(Jetty)サーバーと通信するlocalhost:8081から提供されるAngularJSアプリケーションがあります。 GETは正常に機能しますが、POSTは401で失敗します。

XMLHttpRequest cannot load http://localhost:8081/cellnostics/rest/patient.
Invalid HTTP status code 401

以前、正しいCORSヘッダーを設定するカスタム(Java)CORSフィルターを作成しました。これはv36まで機能していました。 v37および最新のv38(38.0.2125.101 m)でも失敗します。 Internet Explorer 11(11.0.9600)およびOpera 12.17(ビルド1863)では、期待どおりに動作します

[〜#〜] get [〜#〜]リクエストは成功しますが、[〜#〜] post [〜#〜] sは失敗します。 Chromeはcontent-type: "application/json"のためにすべてのPOSTをプリフライトし、プリフライトされたOPTIONSリクエストが失敗しているように見えます。

Angularアプリで、次のリクエストヘッダーを明示的に設定しました。 withCredentialsのこの設定により、OPTIONSリクエストに対しても認証情報が送信されることが保証されます:

//Enable cross domain calls
$httpProvider.defaults.useXDomain = true;

//Send all requests, even OPTIONS, with credentials
$httpProvider.defaults.withCredentials = true;

以下はリクエスト/レスポンスです。 OPTIONSメソッドがAccess-Control-Allow-Methodsヘッダーで有効になっていることがわかります。 JavascriptアプリのOriginが明示的に有効になっていることも確認できます:Access-Control-Allow-Origin: http://localhost:8383

Remote Address:[::1]:8081
Request URL:http://localhost:8081/cellnostics/rest/medicaltest
Request Method:OPTIONS
Status Code:401 Full authentication is required to access this resource

Request headers:

Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,af;q=0.6
Access-Control-Request-Headers:accept, content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:localhost:8081
Origin:http://localhost:8383
Referer:http://localhost:8383/celln-web/index.html
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.101 Safari/537.36

Response headers:

Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, Accept
Access-Control-Allow-Methods:POST, GET, OPTIONS, PUT, DELETE
Access-Control-Allow-Origin:http://localhost:8383
Access-Control-Max-Age:3600
Content-Length:0
Server:Jetty(8.1.8.v20121106)
WWW-Authenticate:Basic realm="Cellnostics"

誰も私が他に何をすべきか考えていますか?テスト、再起動の前にChromeキャッシュをクリアし、再起動前にバックグラウンドChromeプロセスが実行されないことを確認したため、認証が残っていないことを確信しています。キャッシュの問題。

Web開発をテストするためにIE 11に切り替える必要がありました。同じクライアントとサーバーのセットアップがIEとOperaでまだ機能しているという事実と、Chrome/CORSバグの履歴があるという事実は、Chromeを疑っています。

編集:Chrome net-internalsイベントリストからの抜粋です。

t=108514 [st=0]   +URL_REQUEST_START_JOB  [dt=4]
    --> load_flags = 336011264 (BYPASS_DATA_REDUCTION_PROXY | DO_NOT_SAVE_COOKIES | DO_NOT_SEND_AUTH_DATA | DO_NOT_SEND_COOKIES | MAYBE_USER_GESTURE | VERIFY_EV_CERT)
    --> method = "OPTIONS"
    --> priority = "LOW"
    --> url = "http://localhost:8081/cellnostics/rest/patient"
...
t=108516 [st=2] HTTP_TRANSACTION_SEND_REQUEST_HEADERS
--> OPTIONS /cellnostics/rest/patient HTTP/1.1
   Host: localhost:8081
   Connection: keep-alive
   Access-Control-Request-Method: POST
   Origin: http://localhost:8383
   User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.101 Safari/537.36
   Access-Control-Request-Headers: accept, content-type
   Accept: */*
   Referer: http://localhost:8383/celln-web/index.html
   Accept-Encoding: gzip,deflate,sdch
   Accept-Language: en-US,en;q=0.8,af;q=0.6

したがって、withCredentials = trueを明示的に設定しても、OPTIONSプリフライトではAuthorizationヘッダーが送信されないようです。

しかし、なぜIEとOperaはまだ機能するのでしょうか?この点で、Chromeはより標準に準拠していますか?なぜ機能し、v37から失敗し始めたのですか?

編集:Chrome devツールは、上記のダンプにリクエストのContent-Typeを表示しませんが、ここではネットワークログからのものです。最初の写真は、コンテンツタイプが「application/json」として正しく送信され、サーバー認証が無効になっている場合のPOSTを示しています。 2番目の写真は、認証が有効になっている場合で、OPTIONS要求が失敗していることを示しています(OPTIONSは常にコンテンツタイプ「text/plain」で送信されているようです?)。

CORS POST with NO auth on serverCORS POST with auth enabled on server

26
Cornel Masson

@コーネル・マッソン、問題を解決しましたか?サーバーがOPTIONSリクエストの認証を求めている理由がわかりませんが、SAP NetWeaverサーバーに対して同じ問題に直面しています。 CORS仕様全体を読みました(推奨)ので、疑問点を明確にすることができます。

あなたの文章について

Angularアプリで、次のリクエストヘッダーを明示的に設定しました。 withCredentialsのこの設定では、OPTIONS要求に対しても資格情報が送信されることを確認する必要があります。

  • CORS仕様 によると、ユーザーエージェント(したがって、ブラウザー)がリクエスト(OPTIONS HTTPメソッドを使用したリクエスト)をプリフライトする場合、ユーザー資格情報(Cookie、HTTP認証...)を除外する必要がありますOPTIONSリクエストは認証済みとしてリクエストすることはできません。ブラウザは、プリフライトリクエストではなく、実際のリクエスト(GET、POSTなどのリクエストされたHTTPメソッドを持つリクエスト)を認証済みとしてリクエストします。
  • そのため、ブラウザはOPTIONSリクエストで資格情報を送信してはなりません。彼らは実際のリクエストで行います。 withCredentials = trueと書くと、ブラウザは私が言うことをするはずです。

あなたの文章によると:

Chromeは、content-type: "application/json"により、すべてのPOSTをプリフライトしているように見えます。

  • また、仕様では、ヘッダーが「単純なヘッダー」ではない場合にブラウザーによってプリフライトリクエストが行われ、その意味は次のとおりです。

    ヘッダーフィールド名がAccept、Accept-Language、Content-Languageの大文字と小文字を区別しないASCIIである場合、またはASCIIである場合、ヘッダーは単純なヘッダーと呼ばれますContent-Typeとヘッダーフィールド値のメディアタイプ(パラメーターを除く)の大文字と小文字を区別しない一致は、ASCIIapplication/x-www-form-urlencodedmultipart/form-data、またはtext/plain

  • application/jsonは含まれていないため、ブラウザはリクエストをプリフライトする必要があります。

EDIT:実際の問題を反映する同じ問題を持つ人を見つけました。彼と同じサーバーを使用する場合、幸運になります https:// evolpin.wordpress.com/2012/10/12/the-cors/

7
Alex MM

Localhost:4200(Angular CLI Live Development Serverを使用)で実行されているAngular 4フロントエンドアプリケーションをデバッグしようとしたときに、同じ問題が発生していました。 Angularアプリケーションは、Windows認証を使用してlocalhost(IIS Webサーバー)で実行されているASP .Net WebApi2アプリケーションにhttp要求を行います。この問題は、POSTでChromeリクエストを行うときにのみ発生しました(WebApiがCOR用に構成されている場合でも)。この投稿を見つけるまで、Fiddlerを起動してリバースプロキシを実行することで、この問題を一時的に回避することができました(ありがとう)。

Chromeデバッガーのエラーメッセージ:プリフライトリクエストへの応答がアクセス制御チェックに合格しません:要求されたリソースに 'Access-Control-Allow-Origin'ヘッダーがありません

Web Api2-Global.asaxファイルに以下のコードを追加すると、この問題は解決しました。

「CorsHandler」を探している場合は、次のように、単にGeorgeの投稿をハードコードされた文字列値に置き換えることができます。

    protected void Application_BeginRequest()
    {
        if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
        {
            Response.StatusCode = (int)HttpStatusCode.OK;
            Response.Headers.Add("Access-Control-Allow-Credentials", "true");
            Response.Headers.Add("Access-Control-Allow-Origin", Request.Headers.GetValues("Origin").First());
            string accessControlRequestMethod = Request.Headers.GetValues("Access-Control-Request-Method").FirstOrDefault();
            if (accessControlRequestMethod != null)
            {
                Response.Headers.Add("Access-Control-Allow-Methods", accessControlRequestMethod);
            }
            var hdrs = Request.Headers.GetValues("Access-Control-Request-Headers").ToList();
            hdrs.Add("X-Auth-Token");
            string requestedHeaders = string.Join(", ", hdrs.ToArray());
            Response.Headers.Add("Access-Control-Allow-Headers", requestedHeaders);
            Response.Headers.Add("Access-Control-Expose-Headers", "X-Auth-Token");
            Response.Flush();
        }
    }

敬具、

クリス

2
IrishCass101

こっちも一緒。 Windows NTLM認証を使用しています。 Chromeバージョン37までは正常に動作しました。バージョン37、38では、PUTとPOSTの両方でプリフライトOPTIONSにリクエストAuthorizationヘッダーがないため、401(Unauthorized)で失敗します。

サーバー側はMicrosoft Web Api 2.1です。 Microsoftの最新のNuGetパッケージを含むさまざまなCORSを試してみましたが、役に立ちませんでした。

URLのサイズには自然に制限があるため、POSTの代わりにGETリクエストを送信し、複数のリクエストでかなり大きなデータを壊すことで、Chromeで回避する必要があります。

Request/Responseヘッダーは次のとおりです。


Request URL: http://localhost:8082/api/ConfigurationManagerFeed/
Method: OPTIONS
Status: 401 Unauthorized

Request Headers
Accept: */*
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,ru;q=0.6
Access-Control-Request-Headers: accept, content-type
Access-Control-Request-Method: POST
Connection: keep-alive
Host: localhost:8082
Origin: http://localhost:8383
Referer: http://localhost:8383/Application/index.html
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.104 Safari/537.36
X-DevTools-Emulate-Network-Conditions-Client-Id: 49E7FC68-A65C-4318-9292-852946051F27

Response Headers
Cache-Control: private
Content-Length: 6388
Content-Type: text/html; charset=utf-8
Date: Fri, 24 Oct 2014 13:40:07 GMT
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate
NTLM
X-Powered-By: ASP.NET
2
George

MSでIIS Microsoftの標準ページライフサイクルをオーバーライドすることで、別の回避策を実装しました。

public class Global : HttpApplication
{
    /// <summary>Check and cofigure CORS Pre-flight request on Begin Request lifecycle
    /// </summary>
    protected void Application_BeginRequest()
    {
        if (Request.Headers.AllKeys.Contains(CorsHandler.Origin) && Request.HttpMethod == "OPTIONS")
        {
            Response.StatusCode = (int)HttpStatusCode.OK;
            Response.Headers.Add(CorsHandler.AccessControlAllowCredentials, "true");
            Response.Headers.Add(CorsHandler.AccessControlAllowOrigin, Request.Headers.GetValues(CorsHandler.Origin).First());
            string accessControlRequestMethod = Request.Headers.GetValues(CorsHandler.AccessControlRequestMethod).FirstOrDefault();
            if (accessControlRequestMethod != null)
            {
                Response.Headers.Add(CorsHandler.AccessControlAllowMethods, accessControlRequestMethod);
            }
            var hdrs = Request.Headers.GetValues(CorsHandler.AccessControlRequestHeaders).ToList();
            hdrs.Add("X-Auth-Token");
            string requestedHeaders = string.Join(", ", hdrs.ToArray());
            Response.Headers.Add(CorsHandler.AccessControlAllowHeaders, requestedHeaders);
            Response.Headers.Add("Access-Control-Expose-Headers", "X-Auth-Token");
            Response.Flush();
        }
    }
}
2
George