XMLHttpRequest không thể tải XXX Không có tiêu đề 'Access-Control-Allow-Origin'


111

tl; dr; Về Chính sách Xuất xứ Giống nhau

Tôi có một quy trình Grunt khởi tạo một phiên bản của máy chủ express.js. Điều này đã hoạt động hoàn toàn tốt cho đến bây giờ khi nó bắt đầu phân phát một trang trống với thông tin sau xuất hiện trong nhật ký lỗi trong bảng điều khiển của nhà phát triển trong Chrome (phiên bản mới nhất):

XMLHttpRequest không thể tải https://www.example.com/ Không có tiêu đề 'Access-Control-Allow-Origin' trên tài nguyên được yêu cầu. Nguồn gốc ' http: // localhost: 4300 ' do đó không được phép truy cập.

Điều gì đang ngăn tôi truy cập trang?


Tôi đang làm việc trên trang web và nó đã ổn 5 phút trước.
Peter David Carter

1
nó có phát hành tiêu đề CORS không? có lẽ nếu bạn chia sẻ một số mã nó sẽ dễ dàng hơn để xem
Jaromanda X

Thật hợp lý. Tôi nên hỏi bộ phận nào để tìm hiểu? Tôi chỉ làm những thứ backbone.marionette chủ yếu ...
Peter David Carter

Vâng. Tôi cho rằng tổ chức của các phòng ban không phải lúc nào cũng đồng nhất, vì vậy nó có thể là một câu hỏi ngớ ngẩn nhưng tôi muốn biết một chút về phụ trợ / định tuyến / sys-admin tại công ty của tôi và đây dường như là một cái cớ tốt để làm quen bản thân tôi vì vậy nếu có vấn đề trong tương lai tôi có thể giúp đỡ.
Peter David Carter

Tôi sẽ hỏi ai đó ở phía máy chủ bên trong hoạt động của bạn. Họ phải thay đổi nó nếu bạn có thể truy cập nó trước đây.
Larry Lane

Câu trả lời:


204

tl; dr - Có phần tóm tắt ở cuối và các tiêu đề trong câu trả lời để giúp bạn dễ dàng tìm thấy các phần liên quan hơn. Mặc dù vậy, bạn nên đọc mọi thứ vì nó cung cấp nền tảng hữu ích để hiểu lý do tại sao giúp việc xem cách áp dụng trong các trường hợp khác nhau dễ dàng hơn.

Về Chính sách Xuất xứ Giống nhau

Đây là Chính sách Nguồn gốc Giống nhau . Nó là một tính năng bảo mật được thực hiện bởi các trình duyệt.

Trường hợp cụ thể của bạn cho thấy cách nó được triển khai cho XMLHttpRequest (và bạn sẽ nhận được kết quả giống hệt nhau nếu bạn sử dụng tìm nạp), nhưng nó cũng áp dụng cho những thứ khác (chẳng hạn như hình ảnh được tải vào a <canvas>hoặc tài liệu được tải vào một <iframe>), chỉ với triển khai hơi khác nhau.

(Thật kỳ lạ, nó cũng áp dụng cho các phông chữ CSS, nhưng đó là vì các xưởng đúc được phát hiện nhấn mạnh vào DRM chứ không phải các vấn đề bảo mật mà Chính sách Nguồn gốc Giống nhau thường đề cập).

Kịch bản tiêu chuẩn thể hiện sự cần thiết của SOP có thể được trình bày bằng ba ký tự :

  • Alice là một người có trình duyệt web
  • Bob điều hành một trang web ( https://www.[website].com/trong ví dụ của bạn)
  • Mallory điều hành một trang web ( http://localhost:4300trong ví dụ của bạn)

Alice đã đăng nhập vào trang của Bob và có một số dữ liệu bí mật ở đó. Có lẽ đó là mạng nội bộ của công ty (chỉ có thể truy cập được đối với các trình duyệt trong mạng LAN), hoặc ngân hàng trực tuyến của cô ấy (chỉ có thể truy cập bằng cookie bạn nhận được sau khi nhập tên người dùng và mật khẩu).

Alice truy cập trang web của Mallory có một số JavaScript khiến trình duyệt của Alice gửi yêu cầu HTTP đến trang web của Bob (từ địa chỉ IP của cô ấy với cookie của cô ấy, v.v.). Điều này có thể đơn giản như sử dụng XMLHttpRequestvà đọc responseText.

Chính sách Nguồn gốc Giống nhau của trình duyệt ngăn JavaScript đó đọc dữ liệu do trang web của Bob trả về (mà Bob và Alice không muốn Mallory truy cập). (Lưu ý rằng bạn có thể, ví dụ: hiển thị hình ảnh bằng cách sử dụng một <img>phần tử trên các nguồn gốc vì nội dung của hình ảnh không được hiển thị với JavaScript (hoặc Mallory)… trừ khi bạn ném canvas vào hỗn hợp trong trường hợp đó bạn sẽ tạo ra một nguồn gốc giống nhau lỗi vi phạm).


Tại sao Chính sách xuất xứ giống nhau được áp dụng khi bạn không nghĩ nó nên

Đối với bất kỳ URL nhất định nào, có thể không cần SOP. Một số tình huống phổ biến trong trường hợp này là:

  • Alice, Bob và Mallory là cùng một người.
  • Bob đang cung cấp thông tin hoàn toàn công khai

… Nhưng trình duyệt không có cách nào để biết liệu một trong hai điều trên có đúng hay không, vì vậy sự tin tưởng không tự động và SOP được áp dụng. Quyền phải được cấp một cách rõ ràng trước khi trình duyệt cung cấp dữ liệu mà nó đã được cấp cho một trang web khác.


Tại sao Chính sách Nguồn gốc Giống nhau chỉ áp dụng cho JavaScript trong một trang web

Tiện ích mở rộng trình duyệt* , tab Mạng trong các công cụ dành cho nhà phát triển trình duyệt và các ứng dụng như Postman là phần mềm được cài đặt. Họ không chuyển dữ liệu từ một trang web sang JavaScript thuộc một trang web khác chỉ vì bạn đã truy cập trang web khác đó . Cài đặt phần mềm thường có sự lựa chọn có ý thức hơn.

Không có bên thứ ba (Mallory) được coi là rủi ro.

*Các phần mở rộng của trình duyệt cần được viết cẩn thận để tránh các vấn đề về nguồn gốc chéo. Xem tài liệu Chrome chẳng hạn .


Tại sao bạn có thể hiển thị dữ liệu trong trang mà không cần đọc nó bằng JS

Có một số trường hợp mà trang web của Mallory có thể khiến trình duyệt lấy dữ liệu từ bên thứ ba và hiển thị dữ liệu đó (ví dụ: bằng cách thêm một <img>phần tử để hiển thị hình ảnh). Tuy nhiên, JavaScript của Mallory không thể đọc dữ liệu trong tài nguyên đó, chỉ có trình duyệt của Alice và máy chủ của Bob mới có thể làm điều đó, vì vậy nó vẫn an toàn.


CORS

Các Access-Control-Allow-OriginHTTP phản ứng tiêu đề được đề cập trong các thông báo lỗi là một phần của CORS tiêu chuẩn cho phép Bob cấp một cách rõ ràng phép trang web Mallory để truy cập dữ liệu thông qua trình duyệt của Alice.

Một triển khai cơ bản sẽ chỉ bao gồm:

Access-Control-Allow-Origin: *

… Trong tiêu đề phản hồi để cho phép bất kỳ trang web nào đọc dữ liệu.

Access-Control-Allow-Origin: http://example.com/

… Sẽ chỉ cho phép một trang web cụ thể truy cập vào nó và Bob có thể tạo động dựa trên Origin yêu cầu tiêu đề để cho phép nhiều, nhưng không phải tất cả, các trang web truy cập nó.

Các chi tiết cụ thể về cách Bob đặt tiêu đề phản hồi đó phụ thuộc vào máy chủ HTTP của Bob và / hoặc ngôn ngữ lập trình phía máy chủ. Có một bộ sưu tập các hướng dẫn cho các cấu hình phổ biến khác nhau có thể hữu ích.

Mô hình áp dụng các quy tắc CORS

NB: Một số yêu cầu phức tạp và gửi yêu cầu TÙY CHỌN trước khi bắt đầu mà máy chủ sẽ phải trả lời trước khi trình duyệt gửi yêu cầu GET / POST / PUT / Bất cứ thứ gì mà JS muốn thực hiện. Việc triển khai CORS chỉ thêm Access-Control-Allow-Originvào các URL cụ thể thường gặp khó khăn bởi điều này.


Rõ ràng việc cấp quyền qua CORS là điều mà Bob chỉ làm nếu:

  • Dữ liệu không phải là riêng tư hoặc
  • Mallory được tin cậy

Nhưng tôi không phải Bob!

Không có cơ chế tiêu chuẩn nào để Mallory thêm tiêu đề này vì nó phải đến từ trang web của Bob, mà cô ấy không kiểm soát.

Nếu Bob đang chạy một API công khai thì có thể có một cơ chế để bật CORS (có thể bằng cách định dạng yêu cầu theo một cách nhất định hoặc một tùy chọn cấu hình sau khi đăng nhập vào trang Cổng thông tin nhà phát triển cho trang của Bob). Tuy nhiên, đây sẽ phải là một cơ chế được thực hiện bởi Bob. Mallory có thể đọc tài liệu trên trang của Bob để xem liệu có thứ gì không, hoặc cô có thể nói chuyện với Bob và yêu cầu anh thực hiện CORS.


Thông báo lỗi đề cập đến "Phản hồi cho chuyến bay trước"

Một số yêu cầu nguồn gốc chéo được đánh dấu trước .

Điều này xảy ra khi (nói một cách đại khái) bạn cố gắng thực hiện một yêu cầu nguồn gốc chéo rằng:

  • Bao gồm thông tin xác thực như cookie
  • Không thể được tạo bằng biểu mẫu HTML thông thường (ví dụ: có tiêu đề tùy chỉnh hoặc Loại nội dung mà bạn không thể sử dụng trong biểu mẫu enctype).

Nếu bạn đang làm một cách chính xác một việc gì đó cần phải có ánh sáng trước

Trong những trường hợp này , phần còn lại của câu trả lời này vẫn được áp dụng nhưng bạn cũng cần đảm bảo rằng máy chủ có thể lắng nghe yêu cầu preflight (sẽ là OPTIONS(và không GET, POSThoặc bất cứ điều gì bạn đang cố gắng gửi) và phản hồi nó bằng quyền Access-Control-Allow-Origintiêu đề mà còn Access-Control-Allow-MethodsAccess-Control-Allow-Headers để cho phép các phương thức hoặc tiêu đề HTTP cụ thể của bạn.

Nếu bạn đang kích hoạt preflight do nhầm lẫn

Đôi khi mọi người mắc lỗi khi cố gắng xây dựng các yêu cầu Ajax và đôi khi những sai lầm này kích hoạt nhu cầu khởi động trước. Nếu API được thiết kế để cho phép các yêu cầu có nguồn gốc chéo, nhưng không yêu cầu bất kỳ thứ gì cần đến preflight, thì điều này có thể phá vỡ quyền truy cập.

Những sai lầm phổ biến gây ra điều này bao gồm:

  • cố gắng đặt Access-Control-Allow-Originvà các tiêu đề phản hồi CORS khác theo yêu cầu. Những điều này không thuộc về yêu cầu, không làm bất kỳ điều gì hữu ích (hệ thống cấp quyền sẽ là gì khi bạn có thể tự cấp quyền cho mình?) Và chỉ được xuất hiện trên phản hồi.
  • cố gắng đặt Content-Type: application/jsontiêu đề cho một yêu cầu GET không có phần thân yêu cầu để mô tả nội dung của (thường là khi tác giả nhầm lẫn Content-TypeAccept).

Trong một trong hai trường hợp này, việc loại bỏ tiêu đề yêu cầu bổ sung thường là đủ để tránh yêu cầu preflight (điều này sẽ giải quyết vấn đề khi giao tiếp với các API hỗ trợ các yêu cầu đơn giản nhưng không phải là preflight request).


Câu trả lời mờ đục

Đôi khi bạn cần thực hiện một yêu cầu HTTP, nhưng bạn không cần đọc phản hồi. ví dụ: nếu bạn đang đăng một thông báo nhật ký lên máy chủ để ghi lại.

Nếu bạn đang sử dụng các fetchAPI (chứ không phảiXMLHttpRequest ), sau đó bạn có thể cấu hình nó để không cố gắng để CORS sử dụng.

Lưu ý rằng điều này sẽ không cho phép bạn làm bất cứ điều gì mà bạn yêu cầu CORS phải làm. Bạn sẽ không thể đọc phản hồi. Bạn sẽ không thể thực hiện một yêu cầu yêu cầu khởi hành trước.

Nó sẽ cho phép bạn thực hiện một yêu cầu đơn giản, không thấy phản hồi và không điền vào Bảng điều khiển dành cho nhà phát triển với các thông báo lỗi.

Cách thực hiện được giải thích bằng thông báo lỗi Chrome đưa ra khi bạn đưa ra yêu cầu bằng cách sử dụng fetchvà không được phép xem phản hồi với CORS:

Quyền truy cập để tìm nạp tại ' https://example.com/' from origin ' https://example.net' đã bị chặn bởi chính sách CORS: Không có Access-Control-Allow-Origintiêu đề '' trên tài nguyên được yêu cầu. Nếu phản hồi không rõ ràng đáp ứng nhu cầu của bạn, hãy đặt chế độ của yêu cầu thành 'no-cors' để tìm nạp tài nguyên khi CORS bị tắt.

Như vậy:

fetch("http://example.com", { mode: "no-cors" });

Các lựa chọn thay thế cho CORS

JSONP

Bob cũng có thể cung cấp dữ liệu bằng cách sử dụng một cuộc tấn công như JSONP , đây là cách mọi người thực hiện Ajax đa nguồn gốc trước khi CORS xuất hiện.

Nó hoạt động bằng cách trình bày dữ liệu dưới dạng một chương trình JavaScript đưa dữ liệu vào trang của Mallory.

Nó yêu cầu Mallory tin tưởng Bob không cung cấp mã độc hại.

Lưu ý chủ đề chung: Trang web cung cấp dữ liệu phải cho trình duyệt biết rằng trang web của bên thứ ba có thể truy cập vào dữ liệu mà nó đang gửi đến trình duyệt.

Vì JSONP hoạt động bằng cách thêm một <script>phần tử để tải dữ liệu dưới dạng chương trình JavaScript gọi một hàm đã có trong trang, nên việc cố gắng sử dụng kỹ thuật JSONP trên URL trả về JSON sẽ không thành công - thường là với lỗi CORB - vì JSON không phải là JavaScript.

Di chuyển hai tài nguyên đến một Nguồn duy nhất

Nếu tài liệu HTML mà JS chạy trong và URL đang được yêu cầu có cùng nguồn gốc (chia sẻ cùng một lược đồ, tên máy chủ và cổng) thì chúng Chính sách nguồn gốc tương tự cấp quyền theo mặc định. CORS không cần thiết.

Proxy

Mallory có thể sử dụng mã phía máy chủ để tìm nạp dữ liệu (sau đó cô ấy có thể truyền dữ liệu từ máy chủ của mình sang trình duyệt của Alice thông qua HTTP như bình thường).

Nó sẽ:

  • thêm tiêu đề CORS
  • chuyển đổi phản hồi thành JSONP
  • tồn tại trên cùng một nguồn gốc với tài liệu HTML

Mã phía máy chủ đó có thể được viết và lưu trữ bởi bên thứ ba (chẳng hạn như CORS Anywhere). Lưu ý các tác động về quyền riêng tư của điều này: Bên thứ ba có thể giám sát ai ủy quyền những gì trên máy chủ của họ.

Bob sẽ không cần cấp bất kỳ quyền nào để điều đó xảy ra.

Không có ý nghĩa bảo mật nào ở đây vì đó chỉ là giữa Mallory và Bob. Không có cách nào để Bob nghĩ rằng Mallory là Alice và cung cấp cho Mallory những dữ liệu cần được giữ bí mật giữa Alice và Bob.

Do đó, Mallory chỉ có thể sử dụng kỹ thuật này để đọc công khai dữ liệu .

Tuy nhiên, xin lưu ý rằng việc lấy nội dung từ trang web của người khác và tự hiển thị nội dung đó của bạn có thể vi phạm bản quyền và khiến bạn dễ bị khởi kiện.

Viết một cái gì đó không phải là một ứng dụng web

Như đã lưu ý trong phần "Tại sao Chính sách Nguồn gốc giống nhau chỉ áp dụng cho JavaScript trong một trang web", bạn có thể tránh SOP bằng cách không viết JavaScript trong một trang web.

Điều đó không có nghĩa là bạn không thể tiếp tục sử dụng JavaScript và HTML, nhưng bạn có thể phân phối nó bằng một số cơ chế khác, chẳng hạn như Node-WebKit hoặc PhoneGap.

Tiện ích mở rộng trình duyệt

Tiện ích mở rộng trình duyệt có thể đưa tiêu đề CORS vào phản hồi trước khi Chính sách nguồn gốc giống nhau được áp dụng.

Những điều này có thể hữu ích cho sự phát triển, nhưng không thực tế đối với một trang web sản xuất (yêu cầu mọi người dùng trang web của bạn cài đặt tiện ích mở rộng trình duyệt vô hiệu hóa tính năng bảo mật của trình duyệt của họ là không hợp lý).

Chúng cũng có xu hướng chỉ hoạt động với các yêu cầu đơn giản (không thành công khi xử lý các yêu cầu OPTIONS trước khi khởi hành).

Có một môi trường phát triển thích hợp với một máy chủ phát triển cục bộ thường là một cách tiếp cận tốt hơn.


Các rủi ro bảo mật khác

Lưu ý rằng SOP / CORS không giảm thiểu các cuộc tấn công XSS , CSRF hoặc SQL Injection cần được xử lý độc lập.


Tóm lược

  • Bạn không thể làm gì trong mã phía máy khách của mình để cho phép CORS truy cập vào máy chủ của người khác .
  • Nếu bạn kiểm soát máy chủ, yêu cầu đang được thực hiện để: Thêm quyền CORS vào nó.
  • Nếu bạn thân thiện với người kiểm soát nó: Yêu cầu họ thêm quyền CORS vào nó.
  • Nếu nó là một dịch vụ công cộng:
    • Đọc tài liệu API của họ để xem họ nói gì về việc truy cập nó bằng JavaScript phía máy khách:
      • Họ có thể yêu cầu bạn sử dụng các URL cụ thể
      • Họ có thể hỗ trợ JSONP
      • Chúng có thể không hỗ trợ truy cập nguồn gốc chéo từ mã phía máy khách (đây có thể là một quyết định có chủ ý vì lý do bảo mật, đặc biệt nếu bạn phải chuyển một Khóa API được cá nhân hóa trong mỗi yêu cầu).
    • Đảm bảo rằng bạn không kích hoạt yêu cầu khởi hành mà bạn không cần. API có thể cấp quyền cho các yêu cầu đơn giản nhưng không phải là các yêu cầu được đánh dấu trước.
  • Nếu không có cách nào ở trên áp dụng được: Thay vào đó, hãy yêu cầu trình duyệt nói chuyện với máy chủ của bạn , sau đó yêu cầu máy chủ của bạn tìm nạp dữ liệu từ máy chủ khác và chuyển nó. (Ngoài ra còn có các dịch vụ được lưu trữ bên thứ ba đính kèm tiêu đề CORS với các tài nguyên có thể truy cập công cộng mà bạn có thể sử dụng).

Nếu tôi chạy mạng LAN cục bộ, một máy chủ web và cố gắng thực hiện tải ajax từ IP / URL, điều đó có hoạt động không? Tôi chưa thử điều đó. như máy chủ web của tôi trả lại đơn dữ liệu json sẽ là một MCU
Ciasto piekarz

@Ciastopiekarz - Áp dụng quy tắc xuất xứ bình thường giống nhau / xuất xứ khác nhau. Các quy tắc định tuyến mạng thông thường được áp dụng.
Quentin

25
Câu trả lời hoàn thiện nhất tôi đã từng đọc, thay vì chỉ một liên kết về CORS ..
pungggi

@Quentin - Chà! +1! Vì vậy, những gì tôi cần hiểu là nếu Alice sử dụng tiện ích mở rộng CORS, máy chủ nghĩ rằng các lệnh gọi http của cô ấy không phải từ javascript mà là từ một tiện ích mở rộng của trình duyệt và xử lý nó như một yêu cầu gốc bình thường?
snippetkid

@snippetkid - Không. Trong trường hợp thông thường, máy chủ sẽ gửi tiêu đề CORS theo phản hồi và không quan tâm yêu cầu đến từ đâu. Trình duyệt có trách nhiệm cho phép hoặc từ chối quyền truy cập vào dữ liệu đối với JS dựa trên các tiêu đề CORS trên phản hồi. (Mọi thứ trở nên / một chút / phức tạp hơn trên máy chủ khi nói đến yêu cầu trước khi bay)
Quentin

3

Máy chủ đích phải cho phép yêu cầu nguồn gốc chéo. Để cho phép nó thông qua express, chỉ cần xử lý yêu cầu tùy chọn http:

app.options('/url...', function(req, res, next){
   res.header('Access-Control-Allow-Origin', "*");
   res.header('Access-Control-Allow-Methods', 'POST');
   res.header("Access-Control-Allow-Headers", "accept, content-type");
   res.header("Access-Control-Max-Age", "1728000");
   return res.sendStatus(200);
});

3

Vì điều này không được đề cập trong câu trả lời được chấp nhận.

  • Đây không phải là trường hợp của câu hỏi chính xác này, nhưng có thể giúp những người khác tìm kiếm vấn đề đó
  • Đây là điều bạn có thể làm trong mã khách hàng của mình để ngăn lỗi CORS trong một số trường hợp .

Bạn có thể sử dụng các Yêu cầu Đơn giản .
Để thực hiện một 'Yêu cầu đơn giản', yêu cầu cần đáp ứng một số điều kiện. Ví dụ như chỉ cho phép POST, GETHEADphương pháp, cũng như chỉ cho phép một số Headers nhất định (bạn có thể tìm thấy tất cả các điều kiện ở đây ).

Nếu mã khách hàng của bạn không đặt rõ ràng các Tiêu đề bị ảnh hưởng (ví dụ: "Chấp nhận") với giá trị sửa chữa trong yêu cầu, có thể xảy ra trường hợp một số máy khách tự động đặt các Tiêu đề này với một số giá trị "không chuẩn" khiến máy chủ không chấp nhận nó như Yêu cầu đơn giản - sẽ gây ra lỗi CORS cho bạn.


2

Điều này đang xảy ra do lỗi CORS. CORS là viết tắt của Cross Origin Resource Sharing. Nói một cách dễ hiểu, lỗi này xảy ra khi chúng tôi cố gắng truy cập một miền / tài nguyên từ một miền khác.

Đọc thêm về nó ở đây: Lỗi CORS với jquery

Để khắc phục điều này, nếu bạn có quyền truy cập vào miền khác, bạn sẽ phải cho phép Access-Control-Allow-Origin trong máy chủ. Điều này có thể được thêm vào tiêu đề. Bạn có thể bật tính năng này cho tất cả các yêu cầu / miền hoặc một miền cụ thể.

Làm thế nào để yêu cầu bài đăng chia sẻ tài nguyên chéo (CORS) hoạt động

Những liên kết này có thể hữu ích


0

Vấn đề CORS này không được giải thích thêm (vì các nguyên nhân khác).

Tôi đang gặp sự cố này do một lý do khác. Giao diện người dùng của tôi cũng đang trả về lỗi tiêu đề 'Access-Control-Allow-Origin'.

Chỉ là tôi đã trỏ sai URL nên tiêu đề này không được phản ánh đúng cách (trong đó tôi cứ cho rằng nó đã làm vậy). localhost (giao diện người dùng) -> gọi tới http không được bảo mật (được cho là https), đảm bảo rằng điểm cuối API từ giao diện người dùng đang trỏ đến đúng giao thức.


0

Tôi gặp lỗi tương tự trong bảng điều khiển Chrome.

Vấn đề của tôi là, tôi đã cố gắng truy cập trang web bằng cách sử dụng http://thay vì https://. Vì vậy, không có gì để sửa chữa, chỉ cần phải đi đến cùng một trang web sử dụng https.


-1

Yêu cầu "Nhận" với các tiêu đề bổ sung chuyển đổi thành yêu cầu "Tùy chọn". Vì vậy, các vấn đề về chính sách Cors xảy ra. Bạn phải thực hiện yêu cầu "Tùy chọn" cho máy chủ của mình.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.