転送:https://my.oschina.net/u/4203303/blog/3102954
まず、クロスドメインとは何でしょうか?
以下のためのJavaScriptのセキュリティの考慮事項が行う、相同政策の制限を許可しない、クロスドメインの他のリソースへのアクセスを。一般的にクロスドメインリクエストが成功し、ブラウザが対応して、サーバから返された結果を拒否します。
どのような側面セキュリティ上の理由から1?
同一生成元ポリシーの目的は、いくつかの操作を行うには、ユーザーを偽装ユーザーデータ情報を盗むために悪意のあるWebサイトを防ぐためです。相同な制限は、攻撃のコストを増加させます。JavaScriptの相同制限なし:
(1)CSRF攻撃
(2)XSS攻撃
2.相同とは何ですか?
ドメイン名、プロトコル、ポートは同じです。例えば、http://www.example.com/dir/page.html
URLはプロトコルでありhttp://
、ドメイン名www.example.com
、ポート80
(デフォルトのポートを省略することができます)
3.制限は何?
(1)ウィンドウオブジェクト間のクロスオリジン通信:クッキー、のlocalStorage、IndexDBおよびDOMへのアクセスを読み取ることができませんが、次のタグによってドメイン間でリソースにアクセスすることができます。
<img src="URL">
<link href="URL"> <script src="URL"> <iframe src="URL"> <form action="URL" method="get/post"> First name: <input type="text" name="fname"><br> Last name: <input type="text" name="lname"><br> <input type="submit" value="提交"> </form>
さらに、非相同ウェブあれば、今JavaScriptのスクリプトを介して他のウィンドウ/ページを取得することが許さwindow
9つの4つのプロパティとオブジェクトのメソッドを。
- window.closed
- window.frames
- window.length
- window.locationの
- いるwindow.opener
- window.parent
- window.self
- window.top
- window.window
- window.blur()
- window.close()
- window.focus()
- window.postMessage()
唯一ここでwindow.location
読むこと(非相同の場合には、唯一の呼び出しができますlocation.replace
方法と書き込みlocation.href
、他の8つのすべての読み取り専用のプロパティを)。
ルーム(3)クライアントサーバー:ブラウザのAJAX要求は応答を拒否します。
4.どのようにクロスドメインであることを?
対照的にhttp://store.company.com/dir/page.html
相同の検出の例:
URL | 結果 | 理由 |
---|---|---|
http://store.company.com/dir2/other.html |
成功 | 唯一の異なるパス |
http://store.company.com/dir/inner/another.html |
成功 | 唯一の異なるパス |
https://store.company.com/secure.html |
故障 | 異なるプロトコル(HTTPSとHTTP) |
http://store.company.com:81/dir/etc.html |
故障 | 異なるポート(HTTP:// 80がデフォルトです) |
http://news.company.com/dir/other.html |
故障 | 別のドメイン名(ニュースや店) |
注意:IPに対応するドメイン名が正常にアクセスできません。
第二に、どのようにクロスドメインの制限を解決するには?
オブジェクト間のクロスソース通信1.Window
(1)ページの場合ちょうど2つの異なるセカンダリドメイン、ドメイン名と同じ
①ブラウザの設定ができますdocument.domain
クッキーの共有が、DOMを取得します。
/****A网页:http://t1.example.com/a.html*/
document.domain = 'example.com';
//设置cookie
document.cookie = "test1=hello"; /****B网页:http://t2.example.com/b.html,设置相同的document.domain*/ document.domain = 'example.com'; //访问A网页的cookie console.log(document.cookie); /*注意:A 和 B 两个网页都需要设置document.domain属性,才能达到同源的目的。因为设置document.domain的同时,会把端口重置为null,因此如果只设置一个网页的document.domain,会导致两个网址的端口不同,还是达不到同源的目的*/
②また、サーバはまた、クッキー、クッキーは、ドメイン名がドメイン名に属している指定した場合に設定することができ、第二/第3レベルドメインは、任意の設定をしない、あなたはクッキーを読むことができます
Set-Cookie: key=value; domain=.example.com; path=/
短所:このメソッドは、この方法では、ドメイン間で共有することはできません共有クッキーとiframeウィンドウ、のlocalStorageとIndexDBにのみ適用されます
(2)完全に異なるウェブサイトのソースの場合、クロスドメイン通信の問題は3つのウィンドウを追跡することによって解決することができます。
①セグメント識別子(URLの#
数の背面部)
ただ、URLのフラグメント識別子を変更、ページが子ウィンドウのフラグメント識別子を記述し、親ウィンドウが情報を置くことができる更新されません。
//****父窗口把要共享的信息添加到子窗口url的#后
var src = originURL + '#' + data;
document.getElementById('myIFrame').src = src; //****子窗口监听窗口变化 window.onhashchange = ()=>{ //获取url的#后的数据 var data= window.location.hash; } //子窗口也可以通过这种方式向父窗口共享信息 parent.location.href= target + "#" + hash;
②window.name
ブラウザウィンドウのwindow.name
Webページがそれを読んで、そして大容量ことができた後限り、同じウィンドウ内の相同、フロントページは、この属性は、設定されているかどうかの属性は、非常に長い文字列を配置することができます。
//****子窗口:http://child.url.com/xxx.html,将信息写入window.name属性:
window.name = data;
location = 'http://parent.url.com/other.html';//接着,子窗口跳回一个与父窗口同域的网址。
//****父窗口:http://parent.url.com/xxx.html,先打开不同源的子窗口网页: var iframe = document.createElement('iframe'); iframe.id='myFrame'; iframe.src = 'http://child.url.com/xxx.html';//iframe可以跨域加载资源 document.body.appendChild(iframe); //然后,父窗口就可以读取子窗口的window.name了。 var data = document.getElementById('myFrame').contentWindow.name;
短所:子ウィンドウに耳を傾ける必要がありwindow.name
、Webパフォーマンスの影響をプロパティを変更します。
③window.postMessage
HTML5クロスソースウィンドウオブジェクトとの間の通信の問題を(IFRAMEがその中に埋め込まれている間に、ポップアップウィンドウの間に例えば:ページ、または、特に、参照解決するために:https://www.w3cschool.cn/fetch_api/fetch_api- lx142x8t.html)、導入-クロスドキュメント通信APIを。このAPIは、window
新しいの対象window.postMessage
かどうかに関係なく2つの相同窓の、クロスウィンドウの通信を可能にする方法。
/*语法:otherWindow.postMessage(message, targetOrigin, [transfer]);
message:要发送的数据信息
targetOrigin:接收消息的窗口的源(origin),即"协议 + 域名 + 端口"。也可以设为*,表示不限制域名,向所有窗口发送。
*/
//****父窗口"http://aaa.com"向子窗口"http://bbb.com"发消息
var popup = window.open('http://bbb.com', 'title'); popup.postMessage('Hello World!', 'http://bbb.com'); //****子窗口通过message事件,监听发送者的消息 window.addEventListener('message', function(event) { console.log(event.source);//发送源自的窗口:popup (子窗口可以通过event.source属性引用父窗口,然后发送消息) console.log(event.origin);//发送源自的域:"http://aaa.com"(通过event.origin验证发送者,分派事件的origin属性的值不受调用窗口中document.domain的当前值的影响) console.log(event.data);//消息内容:'Hello World!' },false);
セキュリティ上の問題
①あなたが他のサイトからメッセージを受信したくない場合は、メッセージイベントのイベントリスナーを追加しないでください、これはセキュリティ上の問題を回避するために、完全に確実な方法です。
②あなたが他のサイトからメッセージを受信したいならば、悪質なWebサイトによって送信された悪質なメッセージを受信しないように、常に、送信者を確認し、原点とソース属性のIDを使用しています。
③あなたが別のウィンドウにデータを送信するためのpostMessageを使用する場合は、常に正確なターゲットの原点を指定し、*のpostMessageが送信された情報を傍受するために悪意のあるWebサイトの真ん中であることを避けるためにありません。
詳細ビュー:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage
2.AJAX
相同ポリシーは、AJAX要求をのみ、相同URLにそれ以外の場合はエラーを発行することができます。三つのソリューション:
(1)プロキシサーバーをセットアップします
相同ブラウザは、外部サービス後者の要求によって、サーバーを要求し、
(2)JSONP
JSONPを適用する簡単なソースサーバーとクライアント間で通信する一般的な方法、良い相性です。
理論的根拠:
①ページの追加<script>
、これは同一生成元ポリシーの制約、あなたができるクロスドメインリクエストではないとしての要素を、サーバーのスクリプトコードへの要求が直接実行されます。
②サーバが(文字列として、要求、スプライシングの列、関数名JSON上のデータを受信した後bar({...})
)
文字列③クライアントサーバがこれはブラウザいるので、コード解析として返します<script>
スクリプトタグ要求の内容。この場合には、限り、クライアントは定義としてbar()
の機能を、機能は、サーバから返されたJSONデータを取得するために、生体内にあることができます。
//请求的脚本网址有一个callback参数(?callback=bar),用来告诉服务器,客户端的回调函数名称(bar)
<script src="http://api.foo.com?callback=bar"></script>
//定义bar()函数,在该函数体内,拿到服务器返回的 JSON 数据 function foo(data) { console.log('服务器返回:' + data.id); }; //服务器收到这个请求以后,会将数据放在回调函数的参数位置返回。 foo({ 'ip': '8.8.8.8' });
短所:のみ要求を取得することができます
(3)のWebSocket
WebSocketプロトコルはTCPネットワークプロトコルに基づいており、HTTPでトランスポート層として双方向通信技術を置換-サーバが積極的にクライアントに情報を送ることができます。使い方ws://
(非暗号化)およびwss://
プロトコルプレフィックスとして(暗号化)。
①のWebSocketサーバ要求ヘッダOrigin
(:で表されるから、ドメイン要求)フィールドを、現在の通信を許可するか否かを判断します
ホワイトリスト内のドメイン名は、サーバーが応答する場合は②、その制限の相同性はありません
//websocket请求头(摘自网络)
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 Origin: http://example.com //判断为白名单后,服务端做出回应 HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat
(3)ハーツ
CORSは、クロスオリジンリソース共有(クロスオリジンリソースの共有)の頭字語であり、W3C標準であり、クロスソースAJAXリクエストに対する根本的な解決策です。
- のみJSONPの送信と比較すると
GET
、要求を、CORSは、要求のいずれかのタイプを可能にします。 - CORS通信がCORSサーバを達成するための鍵であり、ブラウザとサーバーの両方をサポートする必要があります。CORS長いサーバーはインターフェイスを実装して、あなたはクロスドメインできるコミュニケーションを。
- CORSは、2つのカテゴリに要求する理由を分割する形態が歴史の中でクロスドメイン要求されていることです。、ブラウザは伝統的なアプローチではなく、複合体の振る舞いを踏襲し、開発者は、そうでない場合はCORSの制限を回避するために、フォームを使用するようになるかもしれないシンプルなリクエストフォーム要求です。非単純な要求のために、ブラウザは、新しいアプローチを採用します。
①単純な要求:簡単なHTTPヘッダー情報を持つ単純なHTTPメソッド(ヘッド、GET、POST)(言語を受け入れ、受け入れ、コンテンツ -Language、最終-イベント-ID、Content-Typeのは: 3つの値に制限されていますapplication/x-www-form-urlencoded
、multipart/form-data
、text/plain
)組み合わせ。
- シンプルなリクエストの場合、ブラウザが自動的に追加することでヘッダ情報を、クロスドメインAJAXリクエストがCORSリクエスト直接送信単純な要求を、ある見て
Origin
フィールドを。 - 原点ではなく、許容範囲内のソースを指定した場合、サーバは通常のHTTPレスポンスヘッダ情報がアクセス制御 - 許可由来のフィールドが含まれていない返します。ブラウザがエラーをスローするために受信した後、それをキャプチャするためのXMLHttpRequest ONERRORコールバック関数です。HTTPレスポンスのステータスコードが200であるかもしれないので、このエラーコードは、状態によって認識されないことに注意してください。
- 原点に指定されたドメイン名が範囲を許可した場合、レスポンスヘッダアクセス制御-許可原点リクエストヘッダフィールドにサーバが含まれ
Origin
たフィールドの値を。
//***请求头:
GET /cors HTTP/1.1
Origin: http://api.bob.com /*表示请求来自哪个域(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求*/
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
//****如果Origin指定的域名在许可范围内,服务端响应头之中,会多出几个头信息字段,有三个与 CORS 请求相关的字段,都以Access-Control-开头。 Access-Control-Allow-Origin: http://api.bob.com /*该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。同时,必须在 AJAX 请求中打开withCredentials属性才起作用*/ Access-Control-Allow-Credentials: true/*可选,布尔值。设为true,即表示服务器明确许可,浏览器可以把 Cookie 包含在请求中,一起发给服务器。*/ Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-8
②非単純な要求:要求方法がある:非単純な要求のような特別な要件は、サーバへの要求であるPUT
か、DELETE
またはContent-Type
タイプフィールドですapplication/json
。
- 非単純な要求CORS要求は、公式の通信の前に、「プリフライト」リクエスト(プリフライト)と呼ばれるHTTPクエリ要求を、高めます。
- サーバーを調べ、要求、後の「事前審査」を受け
Origin
、Access-Control-Request-Method
およびAccess-Control-Request-Headers
フィールドの後に、クロスオリジン・リクエストは、私たちが対応できることができ認めます。 - サーバは、「プリフライト」の要求を拒否された場合、それは通常のHTTPレスポンスが、無関連CORSヘッダフィールドを返す、またはそれを明確に要求条件を満たしていないと判断しました。
- それは単純な要求に関連して、ブラウザが通常のCORSを要求するたびの後に「プリフライト」要求を介してサーバー、一度、あるでしょう
Origin
ヘッダフィールド。サーバーの応答はなく、持っているだろうAccess-Control-Allow-Origin
ヘッダフィールドを。
//****JavaScript脚本:
var url = 'http://api.alice.com/cors';
var xhr = new XMLHttpRequest(); xhr.open('PUT', url, true); xhr.setRequestHeader('X-Custom-Header', 'value'); xhr.send(); //****“预检”请求头 OPTIONS /cors HTTP/1.1 /*“预检”请求用的请求方法是OPTIONS,表示这个请求是用来询问的*/ Origin: http://api.bob.com /*表示请求来自哪个源*/ Access-Control-Request-Method: PUT /*该字段是必须的,用来列出浏览器的 CORS 请求会用到哪些 HTTP 方法,本例是PUT*/ Access-Control-Request-Headers: X-Custom-Header /*该字段是一个逗号分隔的字符串,指定浏览器 CORS 请求会额外发送的头信息字段,本例是X-Custom-Header*/ Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0... ①//****服务器否定了“预检”请求的响应头: OPTIONS http://api.bob.com HTTP/1.1 Status: 200 Access-Control-Allow-Origin: https://notyourdomain.com/*明确不包括发出请求的http://api.bob.com*/ Access-Control-Allow-Method: POST //****浏览器发现服务器不同意预检请求,触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。控制台报错信息: XMLHttpRequest cannot load http://api.alice.com. Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin. ②//****服务器允许了“预检”请求的回应头: HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://api.bob.com /*表示http://api.bob.com可以请求数据。该字段也可以设为星号,表示同意任意跨源请求。*/ Access-Control-Allow-Methods: GET, POST, PUT /*该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次“预检”请求。*/ Access-Control-Allow-Headers: X-Custom-Header /*如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在“预检”中请求的字段。*/ Content-Type: text/html; charset=utf-8 Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain Access-Control-Max-Age: 1728000 /*该字段可选,用来指定本次预检请求的有效期,单位为秒。这里有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。*/ //****“预检”请求通过之后,浏览器的会再发一个正常 CORS 请求: PUT /cors HTTP/1.1 Origin: http://api.bob.com Host: api.alice.com X-Custom-Header: value Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0... //****然后,服务器正常的回应: Access-Control-Allow-Origin: http://api.bob.com Content-Type: text/html; charset=utf-8
短所:互換性が良くありません(> IE10)
:を特に参照https://wangdoc.com/javascript/bom/cors.html
詳細ビュー:https://wangdoc.com/javascript/bom/same-origin.html
その他のリンク:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage