带有 PHP 标头的跨域请求标头 (CORS)

IT技术 php javascript xmlhttprequest cors
2021-02-07 02:34:40

我有一个简单的 PHP 脚本,我正在尝试跨域 CORS 请求:

<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: *");
...

但我仍然收到错误:

请求头字段X-Requested-With不被允许Access-Control-Allow-Headers

我缺少什么吗?

6个回答

正确处理 CORS 请求有点复杂。这是一个响应更充分(和正确)的函数。

/**
 *  An example CORS-compliant method.  It will allow any GET, POST, or OPTIONS requests from any
 *  origin.
 *
 *  In a production environment, you probably want to be more restrictive, but this gives you
 *  the general idea of what is involved.  For the nitty-gritty low-down, read:
 *
 *  - https://developer.mozilla.org/en/HTTP_access_control
 *  - https://fetch.spec.whatwg.org/#http-cors-protocol
 *
 */
function cors() {
    
    // Allow from any origin
    if (isset($_SERVER['HTTP_ORIGIN'])) {
        // Decide if the origin in $_SERVER['HTTP_ORIGIN'] is one
        // you want to allow, and if so:
        header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
        header('Access-Control-Allow-Credentials: true');
        header('Access-Control-Max-Age: 86400');    // cache for 1 day
    }
    
    // Access-Control headers are received during OPTIONS requests
    if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
        
        if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
            // may also be using PUT, PATCH, HEAD etc
            header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
        
        if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
            header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
    
        exit(0);
    }
    
    echo "You have CORS!";
}

安全注意事项

根据批准的来源列表检查 HTTP_ORIGIN 标头。

如果来源未获批准,则您应该拒绝该请求。

请阅读规范。

TL; 博士

当浏览器想要执行跨站点请求时,它首先通过对 URL 的“预飞行”请求确认这是否正确。通过允许 CORS,您告诉浏览器来自此 URL 的响应可以与其他域共享。

CORS 不保护您的服务器。CORS 试图通过告诉浏览器与其他域共享响应的限制来保护您的用户。通常这种共享是完全禁止的,因此CORS是一种在浏览器正常安全策略中戳破洞的方法。这些漏洞应该尽可能小,所以总是根据某种内部列表检查 HTTP_ORIGIN。

这里有一些危险,特别是如果 URL 提供的数据通常受到保护。您有效地允许源自其他服务器的浏览器内容读取(并可能操纵)您服务器上的数据。

如果您打算使用 CORS,请仔细阅读协议(它非常小)并尝试了解您在做什么。为此,代码示例中提供了一个参考 URL。

标题安全

已经观察到 HTTP_ORIGIN 标头是不安全的,这是真的。事实上,对于该术语的不同含义,所有 HTTP 标头都是不安全的。除非标头包含可验证的签名/hmac,或者整个对话都通过 TLS 进行身份验证,否则标头只是“浏览器告诉我的东西”。

在这种情况下,浏览器会说“来自域 X 的对象想要从这个 URL 获得响应。可以吗?” CORS 的重点是能够回答“是的,我允许”。

唯一真正有效的!.. 只需更改 Access-Control-Allow-Origin: * TO Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}
2021-03-15 02:34:40
同意。在实践中,您可能不会只允许任何旧域使用您的 CORS 服务,您会将其限制为您决定信任的某个集合。
2021-03-19 02:34:40
请注意,将 HTTP Origin 值作为允许的来源发回将允许任何人向您发送带有 cookie 的请求,从而可能窃取登录您网站然后查看攻击者页面的用户的会话。您要么想发送“*”(这将禁止 cookie 从而防止会话窃取)或您希望站点工作的特定域。
2021-04-04 02:34:40
通过无条件地允许带有 的任何来源ACAC: true,您实际上是将同源策略抛到了窗外。从安全的角度来看,这个答案是糟糕的建议,应该被低估。
2021-04-04 02:34:40
确实,这$_SERVER['HTTP_ORIGIN]并不“安全”,因为您的应用程序无法验证请求的真实来源。但是,保护此标头浏览器的工作。您的应用并未试图阻止来自不同组织的人们使用它。相反,您的应用程序正在向浏览器确认此 URL 可以接受来自某些域的跨站点请求。
2021-04-08 02:34:40

我遇到了同样的错误,并在我的后端脚本中使用以下 PHP 修复了它:

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

header('Access-Control-Allow-Methods: GET, POST');

header("Access-Control-Allow-Headers: X-Requested-With");

Access-Control-Allow-Headers不允许*作为可接受的值,请参阅此处的 Mozilla 文档

您应该发送接受的标头而不是星号(首先X-Requested-With是错误所说的)。

更新:

*现在被接受的是Access-Control-Allow-Headers

根据MDN Web Docs 2021

*对于没有凭据的请求(没有 HTTP cookie 或 HTTP 身份验证信息的请求),该值仅计为特殊的通配符值。在带有凭据的请求中,它被视为*没有特殊语义的文字标头名称请注意, Authorization 标头不能使用通配符,并且始终需要明确列出。

截至 2021 年,*根据 MDN 文档,它现在似乎已被接受。
2021-04-02 02:34:40

互联网上的许多描述都没有提到指定Access-Control-Allow-Origin是不够的。这是一个对我有用的完整示例:

<?php
    if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
        header('Access-Control-Allow-Origin: *');
        header('Access-Control-Allow-Methods: POST, GET, DELETE, PUT, PATCH, OPTIONS');
        header('Access-Control-Allow-Headers: token, Content-Type');
        header('Access-Control-Max-Age: 1728000');
        header('Content-Length: 0');
        header('Content-Type: text/plain');
        die();
    }

    header('Access-Control-Allow-Origin: *');
    header('Content-Type: application/json');

    $ret = [
        'result' => 'OK',
    ];
    print json_encode($ret);
基本上它在这里说的足够了,只是如果请求方法是“选项”就不行了。
2021-03-10 02:34:40
如果已经在 apache 的虚拟主机中发送..那么只有这个代码工作..if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { die(); }
2021-03-17 02:34:40
不幸的是,我记不清了,我现在没有时间再次调查它,但据我所知,网络服务器/浏览器方面有一些基本假设使其无法正常工作。这是对我有用的最少代码。
2021-04-01 02:34:40
请解释为什么它是不够的,什么最小的例子足够了。
2021-04-03 02:34:40

我只是设法让 dropzone 和其他插件与此修复程序一起使用(angularjs + php 后端)

 header('Access-Control-Allow-Origin: *'); 
    header("Access-Control-Allow-Credentials: true");
    header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
    header('Access-Control-Max-Age: 1000');
    header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token , Authorization');

将此添加到您的 upload.php 或您将发送请求的位置(例如,如果您有 upload.html 并且您需要将文件附加到 upload.php,然后复制并粘贴这 4 行)。此外,如果您在 chrome/mozilla 中使用 CORS 插件/插件,请确保多次切换它们,以便启用 CORS