Làm thế nào để bỏ qua Access-Control-Cho phép-Origin?


197

Tôi đang thực hiện cuộc gọi ajax đến máy chủ của riêng mình trên nền tảng mà họ đặt để ngăn chặn các cuộc gọi ajax này (nhưng tôi cần nó để lấy dữ liệu từ máy chủ của mình để hiển thị dữ liệu được truy xuất từ ​​cơ sở dữ liệu của máy chủ của tôi). Tập lệnh ajax của tôi đang hoạt động, nó có thể gửi dữ liệu tới tập lệnh php của máy chủ của tôi để cho phép nó xử lý. Tuy nhiên, nó không thể lấy lại dữ liệu đã xử lý vì nó bị chặn bởi"Access-Control-Allow-Origin"

Tôi không có quyền truy cập vào nguồn / lõi của nền tảng đó. vì vậy tôi không thể xóa tập lệnh mà nó không cho phép tôi làm như vậy. (P / SI đã sử dụng Bảng điều khiển của Google Chrome và phát hiện ra lỗi này)

Mã Ajax như dưới đây:

 $.ajax({
     type: "GET",
     url: "http://example.com/retrieve.php",
     data: "id=" + id + "&url=" + url,
     dataType: 'json',   
     cache: false,
     success: function(data)
      {
        var friend = data[1];              
        var blog = data[2];           
        $('#user').html("<b>Friends: </b>"+friend+"<b><br> Blogs: </b>"+blog);

      } 
  });

hoặc có một JSONmã tương đương với tập lệnh ajax ở trên? Tôi nghĩ JSONlà được phép.

Tôi hy vọng ai đó có thể giúp tôi ra.


tất cả các câu trả lời cho câu hỏi của bạn cho đến nay đã giải thích một cách để viết lại mã máy chủ của bạn để ajax sẽ hoạt động. Không ai trong số họ nói về việc bỏ qua, như bạn đã hỏi cụ thể trong câu hỏi của bạn. Bạn đã tìm thấy dù sao để thực sự bỏ qua tiêu đề này? Tôi thực sự nghi ngờ rằng sẽ có một.
Moradnejad

không có cách nào để vượt qua nó nhưng bạn có thể đặt một tập tin vào phần phụ trợ của bạn để thực hiện yêu cầu. Vì vậy, bạn gọi mỗi ajax tệp trên máy chủ của riêng bạn, tệp đó tải dữ liệu từ lấy.php và gửi lại cho javascript của bạn. Trong trường hợp đó, không có quy tắc CORS nào chặn bạn.
Jona Paulus

Câu trả lời:


367

Đặt cái này lên trên lấy.

header('Access-Control-Allow-Origin: *');  

Lưu ý rằng điều này vô hiệu hóa hiệu quả bảo vệ CORS và khiến người dùng của bạn bị tấn công. Nếu bạn không hoàn toàn chắc chắn rằng bạn cần cho phép tất cả các nguồn gốc, bạn nên khóa nó xuống một nguồn gốc cụ thể hơn:

header('Access-Control-Allow-Origin: https://www.example.com')

Vui lòng tham khảo câu trả lời ngăn xếp sau để hiểu rõ hơn về Access-Control-Allow-Origin

https://stackoverflow.com/a/10636765/413670


54
Đó là không an toàn. Kiểm tra câu trả lời của tôi ở phía dưới.
Cướp

3
tnx, nhưng bạn không nên cho phép truy cập vào tất cả các nguồn gốc như được đề cập bởi @RobQuist trong bình luận của mình và trong câu trả lời của anh ấy đã cung cấp một cách tiếp cận tốt hơn
Rafay 13/12/13

2
Vì vậy, tôi đã tìm thấy trang này vì tôi thực sự cần phải 'bỏ qua' Kiểm soát truy cập trên máy chủ. Giải pháp ở đây không bỏ qua bất cứ điều gì mà chỉ đơn giản là cấu hình đúng Control Control trên máy chủ của chính anh ta. Trong trường hợp bất kỳ ai ở ngoài đó thực sự cần phải bỏ qua điều này, họ có thể sử dụng file_get_contents của PHP ($ remote_url);. Rõ ràng có nhiều cách để làm điều này nhưng đây là cách tôi đã làm nó.
Shawn Whinnery

1
@ShawnWhinnery về cơ bản là hành động "ủy quyền". Giải pháp tốt nếu bạn thực sự muốn tải động dữ liệu từ một trang web khác mà bạn không kiểm soát được.
Rob

1
muốn chạy tập lệnh PHP từ lõi dotnet - đã chuyển tập lệnh php sang URL khác của tôi nhưng đang gặp lỗi tập lệnh chéo trang. đã thêm mã mà bạn đã hiển thị lên đầu PHP và hoạt động hoàn hảo. Cảm ơn!
raddevus

291

Được rồi, nhưng tất cả các bạn đều biết rằng * là ký tự đại diện và cho phép tập lệnh chéo trang từ mọi miền?

Bạn muốn gửi nhiều Access-Control-Allow-Origintiêu đề cho mọi trang web được phép - nhưng thật không may, nó chính thức không được hỗ trợ để gửi nhiều Access-Control-Allow-Origintiêu đề hoặc để đặt nhiều nguồn gốc.

Bạn có thể giải quyết điều này bằng cách kiểm tra nguồn gốc và gửi lại cái đó trong tiêu đề, nếu nó được cho phép:

$origin = $_SERVER['HTTP_ORIGIN'];
$allowed_domains = [
    'http://mysite1.com',
    'https://www.mysite2.com',
    'http://www.mysite2.com',
];

if (in_array($origin, $allowed_domains)) {
    header('Access-Control-Allow-Origin: ' . $origin);
}

Đó là an toàn hơn nhiều. Bạn có thể muốn chỉnh sửa kết hợp và thay đổi nó thành một chức năng thủ công với một số biểu thức chính quy hoặc một cái gì đó tương tự. Ít nhất điều này sẽ chỉ gửi lại 1 tiêu đề và bạn sẽ chắc chắn đó là tiêu đề mà yêu cầu đến từ đó. Xin lưu ý rằng tất cả các tiêu đề HTTP có thể bị giả mạo, nhưng tiêu đề này là để bảo vệ khách hàng. Đừng bảo vệ dữ liệu của bạn với những giá trị đó. Nếu bạn muốn biết thêm, hãy đọc một chút về CORS và CSRF.

Tại sao nó an toàn hơn?

Cho phép truy cập từ các vị trí khác sau đó trang web đáng tin cậy của riêng bạn cho phép đánh dấu phiên cao. Tôi sẽ đi với một ví dụ nhỏ - hình ảnh Facebook cho phép nguồn gốc ký tự đại diện - điều này có nghĩa là bạn có thể tạo trang web của riêng mình ở đâu đó và thực hiện cuộc gọi AJAX (hoặc mở iframe) lên facebook. Điều này có nghĩa là bạn có thể lấy thông tin đăng nhập trên facebook của một khách truy cập trang web của bạn. Thậm chí tệ hơn - bạn có thể POSTyêu cầu tập lệnh và đăng dữ liệu trên facebook của ai đó - ngay khi họ đang duyệt trang web của bạn.

Hãy rất thận trọng khi sử dụng các ACAOtiêu đề!


12
Tôi nghĩ bạn cần đặt http: // trước mỗi mục trong danh sách. Ít nhất tôi đã làm cho một trang web tôi đang làm việc.
blak3r

2
Đáng buồn thay, điều này dường như không hoạt động. Tôi tin rằng chỉ có một ngoại lệ có thể được cung cấp cho mỗi cuộc gọi đến tiêu đề ().
lewsid

5
@Shanimal & lewsid -> Tôi đoán dấu phẩy ngăn cách không thực sự hoạt động. Tham khảo: w3.org/TR/cors
Rob

3
Để xử lý danh sách các tên miền, đây là câu trả lời có liên quan: stackoverflow.com/a/1850482/766177
Valentin Despa

13
Điều này là vô nghĩa khi thêm 4 tiêu đề như vậy bởi vì mỗi cuộc gọi để header()thay thế tiêu đề trước đó cùng loại. Vì vậy, thực sự tất cả những gì bạn đang làm là thiết lập tiêu đề cuối cùng. Các entry của nhãn hiệu nói rằng bạn có thể đặt một tham số thứ hai của falseđể ngăn chặn tiêu đề trước bị ghi đè.
BadHorsie

31

Cảnh báo , Chrome (và các trình duyệt khác) sẽ phàn nàn rằng nhiều tiêu đề ACAO được đặt nếu bạn làm theo một số câu trả lời khác.

Lỗi sẽ là một cái gì đó như XMLHttpRequest cannot load ____. The 'Access-Control-Allow-Origin' header contains multiple values '____, ____, ____', but only one is allowed. Origin '____' is therefore not allowed access.

Thử cái này:

$http_origin = $_SERVER['HTTP_ORIGIN'];

$allowed_domains = array(
  'http://domain1.com',
  'http://domain2.com',
);

if (in_array($http_origin, $allowed_domains))
{  
    header("Access-Control-Allow-Origin: $http_origin");
}

6
Đây là một giải pháp thậm chí tốt hơn mà tôi đã đăng.
Cướp

7

Tôi đã khắc phục vấn đề này khi gọi Trình điều khiển MVC3. Tôi đã thêm:

Response.AddHeader("Access-Control-Allow-Origin", "*"); 

trước khi của tôi

return Json(model, JsonRequestBehavior.AllowGet);

Và tôi $.ajaxcũng phàn nàn rằng nó không chấp nhận tiêu đề Kiểu nội dung trong cuộc gọi ajax của tôi, vì vậy tôi đã nhận xét nó khi tôi biết JSON của nó được chuyển đến Hành động.

Mong rằng sẽ giúp.


2

Đó là một ý tưởng thực sự tồi để sử dụng *, khiến bạn mở rộng để tạo kịch bản chéo trang web. Về cơ bản, bạn luôn muốn có tên miền của riêng mình, nằm trong phạm vi cài đặt SSL hiện tại của bạn và các tên miền bổ sung tùy chọn. Bạn cũng muốn tất cả chúng được gửi dưới dạng một tiêu đề. Phần sau đây sẽ luôn cho phép tên miền của riêng bạn trong cùng phạm vi SSL như trang hiện tại và tùy ý cũng có thể bao gồm bất kỳ số lượng tên miền bổ sung nào. Nó sẽ gửi tất cả chúng dưới dạng một tiêu đề và ghi đè lên (các) tiêu đề trước đó nếu có thứ gì khác đã gửi chúng để tránh bất kỳ cơ hội nào trình duyệt càu nhàu về việc nhiều tiêu đề kiểm soát truy cập được gửi.

class CorsAccessControl
{
    private $allowed = array();

    /**
     * Always adds your own domain with the current ssl settings.
     */
    public function __construct()
    {
        // Add your own domain, with respect to the current SSL settings.
        $this->allowed[] = 'http'
            . ( ( array_key_exists( 'HTTPS', $_SERVER )
                && $_SERVER['HTTPS'] 
                && strtolower( $_SERVER['HTTPS'] ) !== 'off' ) 
                    ? 's' 
                    : null )
            . '://' . $_SERVER['HTTP_HOST'];
    }

    /**
     * Optionally add additional domains. Each is only added one time.
     */
    public function add($domain)
    {
        if ( !in_array( $domain, $this->allowed )
        {
            $this->allowed[] = $domain;
        }
    /**
     * Send 'em all as one header so no browsers grumble about it.
     */
    public function send()
    {
        $domains = implode( ', ', $this->allowed );
        header( 'Access-Control-Allow-Origin: ' . $domains, true ); // We want to send them all as one shot, so replace should be true here.
    }
}

Sử dụng:

$cors = new CorsAccessControl();

// If you are only authorizing your own domain:
$cors->send();

// If you are authorizing multiple domains:
foreach ($domains as $domain)
{
    $cors->add($domain);
}
$cors->send();

Bạn có được ý tưởng.


1

Bạn đã thử thực sự thêm tiêu đề Access-Control-Allow-Origin vào phản hồi được gửi từ máy chủ của bạn chưa? Giống như Access-Control-Allow-Origin: *?


1
Đó là một tiêu đề HTTP mà máy chủ của bạn gửi để thông báo cho trình duyệt rằng bạn có thể tiết lộ kết quả cho tập lệnh gọi mặc dù thực tế là miền gốc của tập lệnh không khớp với miền của máy chủ. Đọc về chia sẻ tài nguyên nguồn gốc chéo !
Daniel Brockman
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.