Kiểm soát truy cập-Cho phép-Xuất xứ nhiều tên miền gốc?


1049

Có cách nào để cho phép nhiều tên miền chéo sử dụng Access-Control-Allow-Origintiêu đề không?

Tôi biết điều đó *, nhưng nó quá mở. Tôi thực sự muốn cho phép chỉ một vài tên miền.

Ví dụ, một cái gì đó như thế này:

Access-Control-Allow-Origin: http://domain1.example, http://domain2.example

Tôi đã thử đoạn mã trên nhưng dường như nó không hoạt động trong Firefox.

Có thể chỉ định nhiều tên miền hay tôi bị mắc kẹt chỉ với một tên miền?



3
Sử dụng Firefox gần đây nhất, các miền không được phân tách bằng dấu phẩy, cũng như không gian được phân tách đều hoạt động. Kết hợp với danh sách các tên miền và đặt một máy chủ lưu trữ vào các tiêu đề vẫn bảo mật tốt hơn và hoạt động đúng.
Daniel W.

1
Nếu bạn đang vật lộn với điều này cho HTTPS, tôi đã tìm ra giải pháp .
Alex W

7
lưu ý quan trọng : chỉ cho phép xác định tên miền trongAccess-Control-Allow-Origintiêu đề không có nghĩa là các tên miền khác không thể kích hoạt một phương thức trên điểm cuối này (ví dụ: phương thức API REST). Điều đó chỉ có nghĩa là nguồn gốc không được phép không thể sử dụng kết quả trong javascript (trình duyệt đảm bảo điều này). Để hạn chế quyền truy cập vào điểm cuối cho các miền cụ thể, hãy sử dụng bộ lọc yêu cầu phía máy chủ, ví dụ trả về HTTP 401 cho các miền không được phép.
klues

1
Bạn phải luôn luôn thêm Vary: Origintiêu đề khi bạn muốn sử dụng nhiều URL, xem: fetch.spec.whatwg.org/#cors-protatio-and-http-caches
Null

Câu trả lời:


861

Âm thanh giống như cách được đề xuất là để máy chủ của bạn đọc tiêu đề Origin từ máy khách, so sánh với danh sách các tên miền bạn muốn cho phép và nếu nó khớp, hãy trả lại giá trị của Origintiêu đề cho máy khách như các Access-Control-Allow-Origintiêu đề trong các phản ứng.

Với .htaccessbạn có thể làm điều đó như thế này:

# ----------------------------------------------------------------------
# Allow loading of external fonts
# ----------------------------------------------------------------------
<FilesMatch "\.(ttf|otf|eot|woff|woff2)$">
    <IfModule mod_headers.c>
        SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.example|dev02.otherdomain.example)$" AccessControlAllowOrigin=$0
        Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        Header merge Vary Origin
    </IfModule>
</FilesMatch>

41
Điều này khớp với những gì W3C gợi ý - w3.org/TR/cors/#access-control-allow-origin-response-apse
Simon B.

153
Vấn đề của tôi với câu trả lời này là nó không thực sự giúp tôi, vì chúng tôi sử dụng CDN và rõ ràng chúng tôi không thể kiểm soát cách CDN đặt tiêu đề theo chương trình.
BT

6
Ví dụ thực tế (Nginx) trong câu trả lời của tôi dưới đây - stackoverflow.com/a/12414239/6084
mjallday

71
Nếu bộ nhớ cache hoặc CDN là mối quan tâm, hãy sử dụng tiêu đề Vary để báo cho bộ đệm / CDN để giữ các phản hồi riêng biệt cho các giá trị tiêu đề yêu cầu Origin khác nhau. Bạn sẽ bao gồm một tiêu đề như "Vary: Origin" trong phản hồi của bạn. Bộ đệm / CDN sau đó biết rằng nó sẽ gửi một phản hồi cho một yêu cầu có tiêu đề "Origin: foo.example.com " và một phản hồi khác với một yêu cầu có tiêu đề "Origin: bar.example.com ".
Sean

10
@saturdayplace, nếu bạn có quyền truy cập vào tiêu đề Origin, bạn đã qua CORS.
Paul Draper

222

Một giải pháp khác tôi đang sử dụng trong PHP:

$http_origin = $_SERVER['HTTP_ORIGIN'];

if ($http_origin == "http://www.domain1.com" || $http_origin == "http://www.domain2.com" || $http_origin == "http://www.domain3.com")
{  
    header("Access-Control-Allow-Origin: $http_origin");
}

12
Tại sao không sử dụng phương pháp được đề xuất trong stackoverflow.com/a/1850482/11635 [và không gửi ký tự đại diện, chỉ là nguồn gốc được yêu cầu]? Đây chỉ là dễ dãi hơn mà không đạt được gì thêm?
Ruben Bartelink

15
header('Access-Control-Allow-Origin: *')đôi khi nói không thể sử dụng thẻ hoang dã nếu thông tin cờ là đúng - xảy ra khi header('Access-Control-Allow-Credentials: true')có thể. Vì vậy, tốt hơn là Cho phép Xuất xứ $http_originchính nó nếu các điều kiện được đáp ứng
Rakib

6
thay thế dòng cuối cùng header("Access-Control-Allow-Origin: " . $http_origin);để làm cho nó hoạt động
François Romain

2
Mã này có vẻ không hoàn hảo, trong đó nếu không có tiêu đề HTTP_ORIGIN nào được nhận ra thì không có Access-Control-Allow-Origin nào được đặt, để mở rộng tập lệnh.
Stephen R

9
@StephenR thực sự "đóng cửa rộng" sẽ chính xác hơn, vì mục đích của việc này là mở tập lệnh sang các miền khác;)
Kaddath

113

Điều này làm việc cho tôi:

SetEnvIf Origin "^http(s)?://(.+\.)?(domain\.example|domain2\.example)$" origin_is=$0 
Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is

Khi đặt vào .htaccess, nó sẽ hoạt động chắc chắn.


24
Giải pháp tốt nhất cho tôi, nhưng tôi đã thêm hỗ trợ cổng (ví dụ: localhost: 3000 để phát triển): SetEnv If Origin "^ http (s) ?: // (. + \.)? (localhost | stackoverflow.com | example1.com) ( : [0-9] +)? $ "Origin_is = $ 0
vszurma

2
Trong số một số câu trả lời xung quanh stackoverflow, đây là câu trả lời có hiệu quả.
Meetai.com 3/03/2015

Tôi cần thêm Header set Access-Control-Allow-Credentials trueđể làm việc này như câu trả lời của @George
99 Vấn đề - Cú pháp không phải là

Điều này hoạt động chắc chắn khi tôi sử dụng Origin. Nhưng trong một số trường hợp, Origin không có sẵn trong một số yêu cầu và nó cũng dành riêng cho trình duyệt. Sau đó, tôi quyết định sử dụng Refererthay vì Origin. Sử dụng Referercông việc nhưng vấn đề là nó đặt URL đầy đủ trở lại Access-Control-Allow-Origintôi muốn cắt tên miền ra Referervà gán nó cho Access-Control-Allow-Origin. Một cái gì đó giống như kết quả của điều này - echo http://example.com/index.php/ab/cd | cut -d'/' -f1,2,3trong lệnh bash. Điều này có thể làm tương tự trong tệp conf (apache) không? Bất kỳ ý tưởng?
3AK

1
Điều này không làm việc cho tôi. Luôn có lỗi mã 500 khi tôi thêm 2 dòng. Thực tế sử dụng PHP 5.6.15
BoCyrill

91

Tôi gặp vấn đề tương tự với phông chữ woff, nhiều tên miền phụ phải có quyền truy cập. Để cho phép tên miền phụ, tôi đã thêm một cái gì đó như thế này vào httpd.conf của mình:

SetEnvIf Origin "^(.*\.example\.com)$" ORIGIN_SUB_DOMAIN=$1
<FilesMatch "\.woff$">
    Header set Access-Control-Allow-Origin "%{ORIGIN_SUB_DOMAIN}e" env=ORIGIN_SUB_DOMAIN
</FilesMatch>

Đối với nhiều tên miền, bạn có thể thay đổi regex trong SetEnvIf.


4
Đã lừa Chỉ cần chắc chắn rằng bạn điều chỉnh biểu thức chính xác. Tôi cần thêm một dấu hỏi để cho phép tên miền, ví dụ: (.*\.?example\.org)cho example.comsub.example.com.
trkoch

3
Bạn có suy nghĩ gì về cách thích ứng với IIS 7 không?
Đánh dấu

Không phải là đánh bại mục đích mặc dù? Điều gì sẽ ngăn người dùng độc hại giả mạo giá trị tiêu đề Origin?
Grégory Joseph

1
@ GrégoryJoseph Kiểm soát truy cập-Cho phép-Xuất xứ không phải là về việc ẩn tài nguyên khỏi người có thể yêu cầu. Đó là về việc ngăn chặn một trang web độc hại có người dùng cuối gọi trang web của bạn. Trong trường hợp tệp phông chữ, điều này chỉ có thể hạn chế hiệu quả liên kết nóng của phông chữ, tại sao chúng (mozilla / firefox) không làm như vậy đối với các tài nguyên khác (js, css, v.v.) nằm ngoài tôi.
Tracker1

@trkoch, có một lỗi trong regex của bạn, nó cũng sẽ cho phép subexample.com. Bạn nên đổi nó thành:((.*\.)?example\.org)
bluesmoon

65

Đây là cách lặp lại tiêu đề Origin nếu nó khớp với tên miền của bạn với Nginx, điều này rất hữu ích nếu bạn muốn cung cấp một phông chữ nhiều tên miền phụ:

location /fonts {
    # this will echo back the origin header
    if ($http_origin ~ "example.org$") {
        add_header "Access-Control-Allow-Origin" $http_origin;
    }
}

Không thể hiểu điều này khác với: add_header Access-Control-Allow-Origin *; Quan tâm để giải thích?
Anoyz 2/2/2015

điều này sẽ trả về một tiêu đề cho phép trình duyệt chỉ gửi yêu cầu từ tên miền được chỉ định. nếu tôi đoán tôi sẽ nói trình duyệt có thể ủy quyền nội dung từ một tên miền khác được tải trên trang đó để truy cập máy chủ.
mjallday 6/2/2015

7
@Anoyz vì một điều có thể có bảo mật nâng cao trong đó "Cho phép *" không được phép, nhưng tên máy chủ được chỉ định và phù hợp cho tiêu đề cho phép hoạt động. Một ví dụ ở đây, nếu bạn muốn gửi thông tin ủy quyền tên miền chéo, bạn không thể sử dụng "Cho phép *"
TCC

3
.in example.org được hiểu là bất kỳ giá trị nào vì đây là biểu thức chính quy? Trong trường hợp nào, điều này có nhầm lẫn cho phép một TLD ví dụ tùy chỉnh không?
mắc kẹt

1
Một regex chính xác phải là "^example\.org$"vì bạn cần đảm bảo tin tặc không thể lướt qua regex của bạn bằng subdomainexample.org(sử dụng ^) hoặc example.orgevil(sử dụng $) hoặc examplezorg(thoát \.)
zeg

27

Đây là những gì tôi đã làm cho một ứng dụng PHP đang được AJAX yêu cầu

$request_headers        = apache_request_headers();
$http_origin            = $request_headers['Origin'];
$allowed_http_origins   = array(
                            "http://myDumbDomain.example"   ,
                            "http://anotherDumbDomain.example"  ,
                            "http://localhost"  ,
                          );
if (in_array($http_origin, $allowed_http_origins)){  
    @header("Access-Control-Allow-Origin: " . $http_origin);
}

Nếu máy chủ yêu cầu của tôi được cho phép, hãy trả lại $http_originchính nó dưới dạng giá trị của Access-Control-Allow-Origintiêu đề thay vì trả về *ký tự đại diện.


20

Có một nhược điểm bạn cần lưu ý: Ngay khi bạn gửi các tệp nguồn ra CDN (hoặc bất kỳ máy chủ nào khác không cho phép tập lệnh) hoặc nếu các tệp của bạn được lưu trong bộ đệm, hãy thay đổi phản hồi dựa trên 'Origin' tiêu đề yêu cầu sẽ không hoạt động.


4
Bạn có thể giải thích về điều này, hoặc chỉ cho chúng tôi một nơi nào đó chúng tôi có thể tìm kiếm thêm thông tin? Tôi đang tìm cách làm điều đó với Limelight và tôi hy vọng bạn đã sai. Một trong những nhân viên công nghệ của chúng tôi nói rằng miễn là máy chủ hạt giống CDN của chúng tôi gửi tiêu đề, chính CDN sẽ gửi nó. Vẫn chưa thử nghiệm
BT

12
Nếu bộ nhớ cache hoặc CDN là mối quan tâm, hãy sử dụng tiêu đề Vary để báo cho bộ đệm / CDN để giữ các phản hồi riêng biệt cho các giá trị tiêu đề yêu cầu Origin khác nhau. Bạn sẽ bao gồm một tiêu đề như "Vary: Origin" trong phản hồi của bạn. Bộ đệm / CDN sau đó biết rằng nó sẽ gửi một phản hồi cho một yêu cầu có tiêu đề "Origin: foo.example.com " và một phản hồi khác với một yêu cầu có tiêu đề "Origin: bar.example.com ".
Sean

Vary: Origin không được Akamai hỗ trợ , một trong những CDN lớn nhất ngoài kia ... Cũng có thêm thông tin chi tiết tại đây
Brad

20

Đối với nhiều tên miền, trong .htaccess:

<IfModule mod_headers.c>
    SetEnvIf Origin "http(s)?://(www\.)?(domain1.example|domain2.example)$" AccessControlAllowOrigin=$0$1
    Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
    Header set Access-Control-Allow-Credentials true
</IfModule>

4
Đoạn trích này hoạt động hoàn hảo cho tôi. Nhưng tôi không hiểu nó làm gì: D
Karl Adler

2
cái này hiệu quả với tôi, mặc dù tôi phải thêm '^' tức là ...
SetEnv If

Nó thực hiện khá giống với stackoverflow.com/a/14034228/209139 . Chỉ là cú pháp .htaccess khó đọc hơn PHP rất nhiều. Header set Vary Originsẽ là một bổ sung tốt đẹp cho câu trả lời này.
TRiG

1
Cảm ơn rất nhiều vì sự giúp đỡ của bạn
Cool Perfectionist

2
Tôi đã phải thay đổi AccessControlAllowOrigin=$0$1để AccessControlAllowOrigin=$0. Mặt khác, nó không hoạt động đối với nguồn gốc HTTPS. http://example.comđi ra một cách chính xác, nhưng https://example.comđi ra như https://example.coms, với một phần phụ sở cuối.
TRiG

17

Đối với người dùng Nginx cho phép CORS cho nhiều tên miền. Tôi thích ví dụ của @ marshall mặc dù anwers của anh ta chỉ phù hợp với một tên miền. Để khớp với danh sách tên miền và tên miền phụ, biểu thức chính này giúp bạn dễ dàng làm việc với các phông chữ:

location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ {
   if ( $http_origin ~* (https?://(.+\.)?(domain1|domain2|domain3)\.(?:me|co|com)$) ) {
      add_header "Access-Control-Allow-Origin" "$http_origin";
   }
}

Điều này sẽ chỉ lặp lại các tiêu đề "Truy cập-Kiểm soát-Cho phép-Xuất xứ" phù hợp với danh sách tên miền đã cho.


Hãy nghĩ rằng bạn cần khóa regex đó vào cuối với \ z vì nếu không domain3.com.badhacker.com sẽ được phép truy cập.
dft

@dft Chúng tôi xác định $ ở cuối mà thực hiện điều đó
Adriano Rosa

Xin lỗi, ý tôi là trong ví dụ chính, bài đăng thực tế của @AdrianoRosa thực hiện tương tự như \ z
dft


13

Đây là một giải pháp cho ứng dụng web Java, dựa trên câu trả lời từ yesthatguy.

Tôi đang sử dụng Jersey REST 1.x

Định cấu hình tệp web để nhận biết Jersey REST và CORSResponseFilter

 <!-- Jersey REST config -->
  <servlet>    
    <servlet-name>JAX-RS Servlet</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param> 
        <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
      <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
      <param-value>com.your.package.CORSResponseFilter</param-value>
    </init-param>   
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>com.your.package</param-value>
    </init-param>        
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>JAX-RS Servlet</servlet-name>
    <url-pattern>/ws/*</url-pattern>
  </servlet-mapping>

Đây là mã cho CORSResponseFilter

import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;


public class CORSResponseFilter implements ContainerResponseFilter{

@Override
public ContainerResponse filter(ContainerRequest request,
        ContainerResponse response) {

    String[] allowDomain = {"http://localhost:9000","https://my.domain.example"};
    Set<String> allowedOrigins = new HashSet<String>(Arrays.asList (allowDomain));                  

    String originHeader = request.getHeaderValue("Origin");

    if(allowedOrigins.contains(originHeader)) {
        response.getHttpHeaders().add("Access-Control-Allow-Origin", originHeader);

        response.getHttpHeaders().add("Access-Control-Allow-Headers",
                "origin, content-type, accept, authorization");
        response.getHttpHeaders().add("Access-Control-Allow-Credentials", "true");
        response.getHttpHeaders().add("Access-Control-Allow-Methods",
                "GET, POST, PUT, DELETE, OPTIONS, HEAD");
    }

    return response;
}

}

Liên kết trên đã hết hạn, bạn có thể thêm câu hỏi mới hoặc cập nhật câu trả lời với nhiều chi tiết hơn không, Cảm ơn
RajKumar Samala

Tôi đã thêm chi tiết, hy vọng điều này sẽ giúp
duvo

12

Như đã đề cập ở trên, Access-Control-Allow-Originphải là duy nhất và Varynên được đặt thành Originnếu bạn đứng sau CDN (Mạng phân phối nội dung).

Phần có liên quan trong cấu hình Nginx của tôi:

if ($http_origin ~* (https?://.*\.mydomain.example(:[0-9]+)?)) {
  set $cors "true";
}
if ($cors = "true") {
  add_header 'Access-Control-Allow-Origin' "$http_origin";
  add_header 'X-Frame-Options' "ALLOW FROM $http_origin";
  add_header 'Access-Control-Allow-Credentials' 'true';
  add_header 'Vary' 'Origin';
}

set $corsmột số loại ý nghĩa ẩn, hoặc nó chỉ cụ thể cho conifg của bạn? có vẻ như nó có thể được bỏ qua cùng với lần thứ haiif
mikezter

Điều đó đúng, nó có thể được bỏ qua nếu đó là điều kiện duy nhất bạn kiểm tra để đặt các tiêu đề, tôi có nhiều trong cấu hình của mình.
hernvnc

9

Có thể tôi sai, nhưng theo như tôi thấy Access-Control-Allow-Origincó một "origin-list"tham số.

Theo định nghĩa, an origin-listlà:

origin            = "origin" ":" 1*WSP [ "null" / origin-list ]
origin-list       = serialized-origin *( 1*WSP serialized-origin )
serialized-origin = scheme "://" host [ ":" port ]
                  ; <scheme>, <host>, <port> productions from RFC3986

Và từ điều này, tôi lập luận các nguồn gốc khác nhau được thừa nhận và nên được phân tách không gian .


2
Đó dường như là một cách giải thích chính xác của thông số kỹ thuật; điều đó nói rằng, thông số kỹ thuật dường như không được hỗ trợ đầy đủ bởi các trình duyệt hiện tại (ví dụ: tôi chỉ thử nghiệm điều này trên Firefox 17.0 và xác nhận rằng nó sẽ không hoạt động).
Rick Riensche

7
Các CORS đặc điểm kỹ thuật phần 5.1 Access-Control-Allow-Origin Response Headertiểu bang mà nguồn gốc-danh sách bị hạn chế: Thay vì cho phép một dấu cách để tách nguồn gốc, nó là cả một nguồn gốc duy nhất hoặc chuỗi "null".
maxpolk

2
Như tôi đã đề cập trong một nhận xét về câu trả lời của riêng tôi, đó là một phần của ghi chú người thực hiện, không phải là yêu cầu RFC 2119. Câu trả lời 'chính xác' hoàn toàn là sử dụng các giá trị được phân tách bằng dấu cách. Vấn đề chỉ đơn giản là việc triển khai không đầy đủ và vì vậy câu trả lời 'chính xác' không nhất thiết phải hoạt động. Nó nên, nhưng nó không. Tuy nhiên, trong tương lai, khi việc triển khai trở nên tốt hơn, điều này có thể thay đổi.
Bob Aman

8

Đối với các ứng dụng ExpressJS bạn có thể sử dụng:

app.use((req, res, next) => {
    const corsWhitelist = [
        'https://domain1.example',
        'https://domain2.example',
        'https://domain3.example'
    ];
    if (corsWhitelist.indexOf(req.headers.origin) !== -1) {
        res.header('Access-Control-Allow-Origin', req.headers.origin);
        res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
    }

    next();
});

điều này sẽ cho phép tất cả các cuộc gọi khác bằng cách gọi tiếp theo ...
Ievgen Naida

@IevgenNaida Vậy sao? Vấn đề là gì?
EyecatchUp

7

Tôi đã vật lộn để thiết lập điều này cho một tên miền chạy HTTPS, vì vậy tôi nghĩ rằng tôi sẽ chia sẻ giải pháp. Tôi đã sử dụng chỉ thị sau trong tệp httpd.conf của mình :

    <FilesMatch "\.(ttf|otf|eot|woff)$">
            SetEnvIf Origin "^http(s)?://(.+\.)?example\.com$" AccessControlAllowOrigin=$0
            Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
    </FilesMatch>

Thay đổi example.comtên miền của bạn. Thêm phần này vào <VirtualHost x.x.x.x:xx>trong tệp httpd.conf của bạn . Lưu ý rằng nếu bạn VirtualHostcó hậu tố cổng (ví dụ :80) thì lệnh này sẽ không áp dụng cho HTTPS, do đó bạn cũng cần phải truy cập / etc / apache2 / site-Available / default-ssl và thêm cùng một lệnh trong tệp đó, bên trong của <VirtualHost _default_:443>phần.

Khi các tệp cấu hình được cập nhật, bạn sẽ cần chạy các lệnh sau trong thiết bị đầu cuối:

a2enmod headers
sudo service apache2 reload

Tôi thích tùy chọn này và kết hợp / sửa đổi nó với cách triển khai mà @George có. Đôi khi, các máy chủ không có sẵn a2enmod, vì vậy tất cả những gì bạn phải làm là kiểm tra httpd.conf chính của mình để xem dòng: LoadModule headftimemodule mô-đun / mod_headers.so không bị lỗi.
Mike Kormendy

Nguồn gốc của tôi có số cổng, vì vậy tôi đã sửa đổi biểu thức chính quy để bao gồm: ^http(s)?://(.+\.)?example\.com(:\d+)?$
indiv

5

Nếu bạn gặp sự cố với phông chữ, hãy sử dụng:

<FilesMatch "\.(ttf|ttc|otf|eot|woff)$">
    <IfModule mod_headers>
        Header set Access-Control-Allow-Origin "*"
    </IfModule>
</FilesMatch>

3

Một cách tiếp cận linh hoạt hơn là sử dụng các biểu thức của Apache 2.4. Bạn có thể đối sánh với tên miền, đường dẫn và chỉ về mọi biến yêu cầu khác. Mặc dù phản hồi được gửi luôn luôn *, nhưng những người yêu cầu duy nhất nhận được nó là những người đáp ứng yêu cầu. Việc sử dụng Origintiêu đề yêu cầu (hoặc bất kỳ loại nào khác) trong biểu thức sẽ khiến Apache tự động hợp nhất nó vào Varytiêu đề phản hồi, do đó phản hồi sẽ không được sử dụng lại cho một nguồn gốc khác.

<IfModule mod_headers.c>
    <If "%{HTTP:Host} =~ /\\bcdndomain\\.example$/i && %{HTTP:Origin} =~ /\\bmaindomain\\.example$/i">
        Header set Access-Control-Allow-Origin "*"
    </If>
</IfModule>

2
Tôi đến đây vì một số trình duyệt không chấp nhận *thông tin đăng nhập như Đăng nhập. Vì vậy, sẽ tốt hơn nếu bạn vượt qua tên máy chủ phù hợp thay vì *.
KeitelDOG

@KeitelDOG làm thế nào để tự động nắm bắt nguồn gốc chính xác và gửi lại khi có nhiều nguồn gốc, thay vì lặp lại mã cho mỗi tên miền? Có vẻ như điều đó thể xảy ra với các biểu thức nhưng tài liệu không rõ ràng đối với tôi.
Rời

Trong thực tế, vấn đề thực sự của tôi là do laravel không trả lại Access-Control-Allow-Origintiêu đề cho OPTIONSyêu cầu preflight mà kiểm tra các tiêu đề để xem máy chủ có cho phép nguồn gốc này không. Tôi đã sửa nó. Vì vậy, *đó không phải là vấn đề thực sự đối với tôi. Tuy nhiên, vẫn có một số trình duyệt không chấp nhận *thông tin đăng nhập, vì vậy khi Ứng dụng web đang gửi yêu cầu Cross-Origin, họ phải chỉ định HTTP_ORIGINtiêu đề mà bạn có thể truy cập động với biến Origintrong .htaccessApache hoặc $_SERVER['HTTP_ORIGIN'];trong PHP. Dù sao, giải pháp của bạn là tốt vì nó cho phép mọi nguồn gốc, nhưng kém an toàn hơn
KeitelDOG

Nhưng 2 điều cần nhớ là 1) Cung cấp *cho phép mọi thứ. 2) HOST khác với nguồn gốc. HOST là 'MỤC TIÊU HOST` thực tế được chuyển đến tiêu đề yêu cầu. Nhưng ORIGIN là INITIAL HOSTgửi yêu cầu đến TARGET HOST. Do đó, trong mã của bạn, ORIGIN HOSTđược bỏ qua và không bao giờ được sử dụng. Xem câu trả lời ở trên và bạn sẽ thấy cách họ sử dụng ORIGINcác giá trị để thêm chúng vào Access-Control-Allow-Origin.
KeitelDOG

@KeitelDOG *Không cho phép tất cả mọi người vì sử dụng Origintiêu đề yêu cầu trong biểu thức khiến Apache tự động hợp nhất nó vào Varytiêu đề phản hồi, trừ khi người ta sử dụng req_novary('Origin')(có thể không mong muốn). Các trình duyệt biết rằng họ có thể nhận được phản hồi khác nhau Originvà nếu giá trị được gửi không vượt qua kiểm tra của một người, Access-Control-Allow-Origintiêu đề sẽ không bao giờ được đặt.
trục trặc

3

Mã PHP:

$httpOrigin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : null;
if (in_array($httpOrigin, [
    'http://localhost:9000', // Co-worker dev-server
    'http://127.0.0.1:9001', // My dev-server
])) header("Access-Control-Allow-Origin: ${httpOrigin}");
header('Access-Control-Allow-Credentials: true');

2

HTTP_ORIGIN không được sử dụng bởi tất cả các trình duyệt. HTTP_ORIGIN an toàn đến mức nào? Đối với tôi nó xuất hiện trống rỗng trong FF.
Tôi có các trang web mà tôi cho phép truy cập vào trang web của mình gửi qua ID trang web, sau đó tôi kiểm tra DB của mình để biết bản ghi đó với id đó và nhận giá trị cột SITE_URL (www.yoursite.com).

header('Access-Control-Allow-Origin: http://'.$row['SITE_URL']);

Ngay cả khi việc gửi qua ID trang web hợp lệ, yêu cầu cần phải đến từ tên miền được liệt kê trong DB của tôi được liên kết với ID trang web đó.


2

Đây là một tùy chọn mở rộng cho apache bao gồm một số định nghĩa phông chữ mới nhất và theo kế hoạch:

<FilesMatch "\.(ttf|otf|eot|woff|woff2|sfnt|svg)$">
    <IfModule mod_headers.c>
        SetEnvIf Origin "^http(s)?://(.+\.)?(domainname1|domainname2|domainname3)\.(?:com|net|org)$" AccessControlAllowOrigin=$0$1$2
        Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        Header set Access-Control-Allow-Credentials true
    </IfModule>
</FilesMatch>

2

Để tạo điều kiện truy cập nhiều tên miền cho dịch vụ ASMX, tôi đã tạo chức năng này trong tệp global.asax:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    string CORSServices = "/account.asmx|/account2.asmx";
    if (CORSServices.IndexOf(HttpContext.Current.Request.Url.AbsolutePath) > -1)
    {
        string allowedDomains = "http://xxx.yyy.example|http://aaa.bbb.example";

        if(allowedDomains.IndexOf(HttpContext.Current.Request.Headers["Origin"]) > -1)
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", HttpContext.Current.Request.Headers["Origin"]);

        if(HttpContext.Current.Request.HttpMethod == "OPTIONS")
            HttpContext.Current.Response.End();
    }
}

Điều này cho phép xử lý CORS của OPTIONSđộng từ cũng.


2

Ví dụ mã PHP để phù hợp với tên miền phụ.

if( preg_match("/http:\/\/(.*?)\.yourdomain.example/", $_SERVER['HTTP_ORIGIN'], $matches )) {
        $theMatch = $matches[0];
        header('Access-Control-Allow-Origin: ' . $theMatch);
}

2

Để sao chép / dán khá dễ dàng cho các ứng dụng .NET, tôi đã viết cái này để kích hoạt CORS từ trong một global.asaxtệp. Mã này tuân theo lời khuyên được đưa ra trong câu trả lời hiện được chấp nhận, phản ánh bất kỳ nguồn gốc nào được đưa ra trong yêu cầu vào phản hồi. Điều này đạt được hiệu quả '*' mà không cần sử dụng nó.

Lý do cho điều này là vì nó cho phép nhiều tính năng CORS khác , bao gồm khả năng gửi AJAX XMLHttpRequest với thuộc tính 'withCredentials' được đặt thành 'true'.

void Application_BeginRequest(object sender, EventArgs e)
{
    if (Request.HttpMethod == "OPTIONS")
    {
        Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
        Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
        Response.AddHeader("Access-Control-Max-Age", "1728000");
        Response.End();
    }
    else
    {
        Response.AddHeader("Access-Control-Allow-Credentials", "true");

        if (Request.Headers["Origin"] != null)
            Response.AddHeader("Access-Control-Allow-Origin" , Request.Headers["Origin"]);
        else
            Response.AddHeader("Access-Control-Allow-Origin" , "*");
    }
}

1

Và thêm một câu trả lời trong Django. Để có một chế độ xem cho phép CORS từ nhiều tên miền, đây là mã của tôi:

def my_view(request):
    if 'HTTP_ORIGIN' in request.META.keys() and request.META['HTTP_ORIGIN'] in ['http://allowed-unsecure-domain.com', 'https://allowed-secure-domain.com', ...]:
        response = my_view_response() # Create your desired response data: JsonResponse, HttpResponse...
        # Then add CORS headers for access from delivery
        response["Access-Control-Allow-Origin"] = request.META['HTTP_ORIGIN']
        response["Access-Control-Allow-Methods"] = "GET" # "GET, POST, PUT, DELETE, OPTIONS, HEAD"
        response["Access-Control-Max-Age"] = "1000"  
        response["Access-Control-Allow-Headers"] = "*"  
        return response

1

Cổng AWS Lambda / API

Để biết thông tin về cách định cấu hình nhiều nguồn gốc trên Serverless AWS Lambda và API Gateway - mặc dù là một giải pháp khá lớn cho thứ gì đó mà người ta cảm thấy nên khá đơn giản - xem tại đây:

https://stackoverflow.com/a/41708323/1624933


Hiện tại không thể định cấu hình nhiều nguồn gốc trong API Gateway, xem tại đây: https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors-console.html ), nhưng đề xuất (trong câu trả lời ở trên) là:

  • kiểm tra tiêu đề Origin được gửi bởi trình duyệt
  • kiểm tra nó dựa trên danh sách trắng nguồn gốc
  • nếu nó khớp, trả về Nguồn gốc đến dưới dạng tiêu đề Access-Control-Allow-Origin, nếu không thì trả về một trình giữ chỗ (gốc mặc định).

Giải pháp đơn giản rõ ràng là cho phép TẤT CẢ (*) như vậy:

exports.handler = async (event) => {
    const response = {
        statusCode: 200,
        headers: {
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
        },
        body: JSON.stringify([{

Nhưng có thể tốt hơn để làm điều này ở phía API Gateway (xem liên kết thứ 2 ở trên).


2
Access-Control-Allow-Credentials: truekhông được phép với ký tự đại diện Access-Control-Allow-Origin: *. Đặt một cụ thể <origin>thay thế.
Tom

@Tom, yea, không chắc tại sao lại ở đó, tôi không thể nhớ, nhưng tôi có thể đã sao chép nó từ các mặc định đã được thêm vào AWS? Cảm ơn đã chỉ ra rằng mặc dù.
timhc22

0

Câu trả lời hỗ trợ của Google về việc phân phát quảng cáo qua SSLngữ pháp trong chính RFC dường như cho thấy rằng bạn có thể phân cách các URL. Không chắc chắn mức độ được hỗ trợ tốt này trong các trình duyệt khác nhau.


'phân phát quảng cáo qua ssl' liên kết đến thông số w3.org/TR/cors/#access-control-allow-origin-response-header có thêm ghi chú: "Trong thực tế, việc sản xuất danh sách gốc hoặc bị vô hiệu hóa bị hạn chế hơn . Thay vì cho phép một danh sách nguồn gốc được phân tách bằng dấu cách, nó là một nguồn gốc duy nhất hoặc chuỗi "null".
spazm

Mặc dù điều quan trọng cần lưu ý là chi tiết đó, nhưng khi một đặc tả nói "Trong thực tế", điều đó không có nghĩa là nó chỉ hợp lệ để làm theo cách đó. Điều đó có nghĩa là nếu bạn làm theo cách đó, bạn có thể gặp vấn đề vì phần lớn những người thực hiện hoặc thực hiện thông số kỹ thuật không chính xác hoặc không đầy đủ. Thông số kỹ thuật này cho phép danh sách nguồn gốc được phân tách bằng không gian, mà bạn có thể thấy ở đây trong EBNF dưới origin-list: tools.ietf.org/html/rfc6454#section-7.1
Bob Aman

0

Nếu bạn thử rất nhiều ví dụ mã như tôi để làm cho nó hoạt động bằng CORS, điều đáng nói là bạn phải xóa bộ nhớ cache trước để thử nếu nó thực sự hoạt động, tương tự như các vấn đề như khi hình ảnh cũ vẫn còn, ngay cả khi nó đã xóa trên máy chủ (vì nó vẫn được lưu trong bộ nhớ cache của bạn).

Ví dụ: CTRL + SHIFT + DELtrong Google Chrome để xóa bộ nhớ cache của bạn.

Điều này đã giúp tôi sử dụng mã này sau khi thử nhiều .htaccessgiải pháp thuần túy và đây dường như là giải pháp duy nhất hoạt động (ít nhất là đối với tôi):

    Header add Access-Control-Allow-Origin "http://google.com"
    Header add Access-Control-Allow-Headers "authorization, origin, user-token, x-requested-with, content-type"
    Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"

    <FilesMatch "\.(ttf|otf|eot|woff)$">
        <IfModule mod_headers.c>
            SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.com|dev02.otherdomain.net)$" AccessControlAllowOrigin=$0
            Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        </IfModule>
    </FilesMatch>

Cũng lưu ý rằng nó được lan truyền rộng rãi rằng nhiều giải pháp nói rằng bạn phải gõ Header set ...nhưng nó là Header add .... Hy vọng điều này sẽ giúp ai đó gặp rắc rối tương tự trong một số giờ như tôi.


0

Câu trả lời dưới đây là cụ thể cho C #, nhưng khái niệm này nên được áp dụng cho tất cả các nền tảng khác nhau.

Để cho phép Yêu cầu nguồn gốc chéo từ api web, Bạn cần cho phép các yêu cầu Tùy chọn cho Ứng dụng của mình và Thêm chú thích bên dưới ở cấp điều khiển.

[EnableCors (UrlString, Header, Phương thức)] Bây giờ nguồn gốc chỉ có thể được truyền dưới dạng chuỗi. Vì vậy, nếu bạn muốn vượt qua nhiều URL trong yêu cầu, hãy chuyển nó dưới dạng giá trị được phân tách bằng dấu phẩy.

UrlString = " https: //a.hello.com,https: //b.hello.com "


0

Chỉ một nguồn gốc duy nhất có thể được chỉ định cho tiêu đề Access-Control-Allow-Origin. Nhưng bạn có thể đặt nguồn gốc trong phản hồi của bạn theo yêu cầu. Cũng đừng quên đặt tiêu đề Vary. Trong PHP tôi sẽ làm như sau:

    /**
     * Enable CORS for the passed origins.
     * Adds the Access-Control-Allow-Origin header to the response with the origin that matched the one in the request.
     * @param array $origins
     * @return string|null returns the matched origin or null
     */
    function allowOrigins($origins)
    {
        $val = $_SERVER['HTTP_ORIGIN'] ?? null;
        if (in_array($val, $origins, true)) {
            header('Access-Control-Allow-Origin: '.$val);
            header('Vary: Origin');

            return $val;
        }

        return null;
    }

  if (allowOrigins(['http://localhost', 'https://localhost'])) {
      echo your response here, e.g. token
  }

-2

Chúng tôi cũng có thể đặt tệp này trong tệp Global.asax cho ứng dụng Asp.net.

protected void Application_BeginRequest(object sender, EventArgs e)
    {

    // enable CORS
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "https://www.youtube.com");

    }
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.