directory search
Guides Access control CORS Authentication Browser detection using the user agent Caching Caching FAQ Compression Conditional requests Connection management in HTTP 1.x Content negotiation Content negotiation: List of default Accept values Cookies CSP Messages Overview Protocol upgrade mechanism Proxy servers and tunneling Proxy servers and tunneling: Proxy Auto-Configuration (PAC) file Public Key Pinning Range requests Redirections Resources and specifications Resources and URIs Response codes Server-Side Access Control Session Guides: Basics Basics of HTTP Choosing between www and non-www URLs Data URIs Evolution of HTTP Identifying resources on the Web MIME Types MIME types: Complete list of MIME types CSP Content-Security-Policy Content-Security-Policy-Report-Only CSP: base-uri CSP: block-all-mixed-content CSP: child-src CSP: connect-src CSP: default-src CSP: font-src CSP: form-action CSP: frame-ancestors CSP: frame-src CSP: img-src CSP: manifest-src CSP: media-src CSP: object-src CSP: plugin-types CSP: referrer CSP: report-uri CSP: require-sri-for CSP: sandbox CSP: script-src CSP: style-src CSP: upgrade-insecure-requests CSP: worker-src Headers Accept Accept-Charset Accept-Encoding Accept-Language Accept-Ranges Access-Control-Allow-Credentials Access-Control-Allow-Headers Access-Control-Allow-Methods Access-Control-Allow-Origin Access-Control-Expose-Headers Access-Control-Max-Age Access-Control-Request-Headers Access-Control-Request-Method Age Allow Authorization Cache-Control Connection Content-Disposition Content-Encoding Content-Language Content-Length Content-Location Content-Range Content-Type Cookie Cookie2 Date DNT ETag Expect Expires Forwarded From Headers Host If-Match If-Modified-Since If-None-Match If-Range If-Unmodified-Since Keep-Alive Large-Allocation Last-Modified Location Origin Pragma Proxy-Authenticate Proxy-Authorization Public-Key-Pins Public-Key-Pins-Report-Only Range Referer Referrer-Policy Retry-After Server Set-Cookie Set-Cookie2 SourceMap Strict-Transport-Security TE Tk Trailer Transfer-Encoding Upgrade-Insecure-Requests User-Agent User-Agent: Firefox Vary Via Warning WWW-Authenticate X-Content-Type-Options X-DNS-Prefetch-Control X-Forwarded-For X-Forwarded-Host X-Forwarded-Proto X-Frame-Options X-XSS-Protection Methods CONNECT DELETE GET HEAD Methods OPTIONS PATCH POST PUT Status 100 Continue 101 Switching Protocols 200 OK 201 Created 202 Accepted 203 Non-Authoritative Information 204 No Content 205 Reset Content 206 Partial Content 300 Multiple Choices 301 Moved Permanently 302 Found 303 See Other 304 Not Modified 307 Temporary Redirect 308 Permanent Redirect 400 Bad Request 401 Unauthorized 403 Forbidden 404 Not Found 405 Method Not Allowed 406 Not Acceptable 407 Proxy Authentication Required 408 Request Timeout 409 Conflict 410 Gone 411 Length Required 412 Precondition Failed 413 Payload Too Large 414 URI Too Long 415 Unsupported Media Type 416 Range Not Satisfiable 417 Expectation Failed 426 Upgrade Required 428 Precondition Required 429 Too Many Requests 431 Request Header Fields Too Large 451 Unavailable For Legal Reasons 500 Internal Server Error 501 Not Implemented 502 Bad Gateway 503 Service Unavailable 504 Gateway Timeout 505 HTTP Version Not Supported 511 Network Authentication Required Status
characters

浏览器发送特定的HTTP标头,用于从内部XMLHttpRequest或获取API发起的跨站点请求。它还希望看到具有跨站点响应的特定HTTP标头。HTTP访问控制(CORS)文章中提供了这些头文件的概述,包括启动请求和处理来自服务器的响应的示例JavaScript代码以及对每个头文件的讨论,应该将其作为配套文章这个。本文介绍处理访问控制请求和制定访问控制响应在PHP中。本文的目标受众是服务器程序员或管理员。尽管这里显示的代码示例是用PHP编写的,但类似的概念适用于ASP.net,Perl,Python,Java等。通常,这些概念可以应用于处理HTTP请求并动态地制定HTTP响应的任何服务器端编程环境。

讨论HTTP标头

这篇文章涵盖了客户端和服务器使用的HTTP标头,并且应该被视为读取前提条件。

工作代码示例

后续章节中的PHP片段(以及对服务器的JavaScript调用)取自此处发布的工作代码示例。这些将在实现跨站点的浏览器中工作XMLHttpRequest

简单的跨网站请求

简单访问控制请求在以下情况下启动:

  • 一个HTTP/1.1 GET或者一个POST被用作请求方法。在POST的情况下,Content-Type请求体的是一种application/x-www-form-urlencodedmultipart/form-datatext/plain.

  • 没有自定义标头与HTTP请求一起发送(例如X-Modified等)

在这种情况下,可以根据一些考虑将回复发送回去。

  • 如果有问题的资源被广泛访问(就像GET访问的任何HTTP资源一样),那么发送回头Access-Control-Allow-Origin: *就足够了,除非资源需要诸如Cookie和HTTP认证信息之类的凭证。

  • 如果资源应该基于请求者域保持限制,或者如果资源需要使用凭据访问(或设置凭证),则Origin可能需要按请求头进行过滤,或者至少回应请求者Origin(例如Access-Control-Allow-Origin: http://arunranga.com)。此外,Access-Control-Allow-Credentials: true标题将不得不发送。这将在后面的章节中讨论。

简单访问控制请求部分显示客户端和服务器之间的头部交换。这是处理简单请求的PHP代码段:

<?php// We'll be granting access to only the arunranga.com domain // which we think is safe to access this resource as application/xmlif($_SERVER['HTTP_ORIGIN'] == "http://arunranga.com") {    header('Access-Control-Allow-Origin: http://arunranga.com');    header('Content-type: application/xml');    readfile('arunerDotNetResource.xml');} else {    
  header('Content-Type: text/html');
  echo "<html>";
  echo "<head>";
  echo "   <title>Another Resource</title>";
  echo "</head>";
  echo "<body>",       "<p>This resource behaves two-fold:";
  echo "<ul>",         "<li>If accessed from <code>http://arunranga.com</code> it returns an XML document</li>";
  echo   "<li>If accessed from any other origin including from simply typing in the URL into the browser's address bar,";
  echo   "you get this HTML document</li>", 
       "</ul>",     "</body>",   "</html>";}?>

上面的内容检查Origin浏览器发送的头文件(通过$ _SERVER'HTTP_ORIGIN'获得)是否匹配' http://arunranga.com '。如果是,它会返回Access-Control-Allow-Origin: http://arunranga.com

预先请求的请求

预冲的访问控制请求在下列情况下发生:

  • 以外的方法,GETPOST使用,或如果POST使用具有Content-Type 比其它的一个application/x-www-form-urlencodedmultipart/form-datatext/plain。举例来说,如果Content-Type所述的POST体是application/xml,请求预检。

  • 自定义标题(例如X-PINGARUNER)与请求一起发送。

Preflighted访问控制请求部分显示客户端和服务器之间的头部交换。响应预检请求的服务器资源需要能够做出以下决定:

  • 基于Origin(如果有的话)过滤。

  • 响应于OPTIONS请求(这是预检请求),包括与发送必要的值Access-Control-Allow-MethodsAccess-Control-Allow-Headers(如果需要,为了任何附加头的应用程序的工作),并且,如果证书是必要的这一资源,Access-Control-Allow-Credentials

  • 对实际请求的回应,包括处理POST数据等。

以下是处理预发光请求的PHP示例:

<?php 

if($_SERVER['REQUEST_METHOD'] == "GET") {  header('Content-Type: text/plain');
  echo "This HTTP resource is designed to handle POSTed XML input";
  echo "from arunranga.com and not be retrieved with GET"; } elseif($_SERVER['REQUEST_METHOD'] == "OPTIONS") {  // Tell the Client we support invocations from arunranga.com and   // that this preflight holds good for only 20 days  if($_SERVER['HTTP_ORIGIN'] == "http://arunranga.com") {    header('Access-Control-Allow-Origin: http://arunranga.com');    header('Access-Control-Allow-Methods: POST, GET, OPTIONS');    header('Access-Control-Allow-Headers: X-PINGARUNER');    header('Access-Control-Max-Age: 1728000');    header("Content-Length: 0");    header("Content-Type: text/plain");    //exit(0);  } else {    header("HTTP/1.1 403 Access Forbidden");    header("Content-Type: text/plain");
    echo "You cannot repeat this request";  }} elseif($_SERVER['REQUEST_METHOD'] == "POST") {  // Handle POST by first getting the XML POST blob,   // and then doing something to it, and then sending results to the client 
  if($_SERVER['HTTP_ORIGIN'] == "http://arunranga.com") {
    $postData = file_get_contents('php://input');
    $document = simplexml_load_string($postData);    
    // do something with POST data

    $ping = $_SERVER['HTTP_X_PINGARUNER'];         
    header('Access-Control-Allow-Origin: http://arunranga.com');    header('Content-Type: text/plain');
    echo // some string response after processing  } else {    die("POSTing Only Allowed from arunranga.com");  }} else {    die("No Other Methods Allowed");}?>

请注意,为了响应OPTIONS预检和POST数据,将返回相应的标题。因此一个资源处理预检和实际请求。在对OPTIONS请求的响应中,服务器通知客户端实际的请求确实可以用该POST方法进行,并且诸如头部字段X-PINGARUNER可以与实际请求一起发送。这个例子可以在这里看到。

认证请求

凭证访问控制请求 - 即伴随有Cookie或HTTP身份验证信息的请求(并且期望Cookie与响应一起发送) - 可以是简单或预检,具体取决于所使用的请求方法。

在简单请求方案中,请求将以Cookie发送(例如,如果withCredentials标志设置为开启XMLHttpRequest)。如果服务器响应Access-Control-Allow-Credentials: true附加的凭证响应,则响应被客户端接受并暴露给Web内容。在预检请求,服务器可以响应Access-Control-Allow-Credentials: trueOPTIONS请求。

以下是一些处理凭证请求的PHP:

<?phpif($_SERVER['REQUEST_METHOD'] == "GET") {  header('Access-Control-Allow-Origin: http://arunranga.com');  header('Access-Control-Allow-Credentials: true');  header('Cache-Control: no-cache');  header('Pragma: no-cache');  header('Content-Type: text/plain');  // First See if There Is a Cookie     if (!isset($_COOKIE["pageAccess"])) {    setcookie("pageAccess", 1, time()+2592000);
    echo 'I do not know you or anyone like you so I am going to';
    echo 'mark you with a Cookie :-)';    
  } else {
    $accesses = $_COOKIE['pageAccess'];    setcookie('pageAccess', ++$accesses, time()+2592000);
    echo 'Hello -- I know you or something a lot like you!';
    echo 'You have been to ', $_SERVER['SERVER_NAME'], ';
    echo 'at least ', $accesses-1, ' time(s) before!';  }  } elseif($_SERVER['REQUEST_METHOD'] == "OPTIONS") {  // Tell the Client this preflight holds good for only 20 days  if($_SERVER['HTTP_ORIGIN'] == "http://arunranga.com") {    header('Access-Control-Allow-Origin: http://arunranga.com');    header('Access-Control-Allow-Methods: GET, OPTIONS');    header('Access-Control-Allow-Credentials: true');    header('Access-Control-Max-Age: 1728000');    header("Content-Length: 0");    header("Content-Type: text/plain");  } else {    header("HTTP/1.1 403 Access Forbidden");    header("Content-Type: text/plain");
    echo "You cannot repeat this request";  }} else {  die("This HTTP Resource can ONLY be accessed with GET or OPTIONS");}?>

请注意,对于有证书请求的情况,Access-Control-Allow-Origin:标头不得有通配符值“*”。它必须提到一个有效的原始域。上面的例子可以看到在这里运行。

Apache示例

限制对某些URI的访问

一个有用的技巧是使用Apache重写,环境变量和标头来应用于Access-Control-Allow-*某些URI。例如,这对于将GET /api(.*).json请求的跨请求限制为没有凭证的请求很有用:

RewriteRule ^/api(.*)\.json$ /api$1.json [CORS=True]Header set Access-Control-Allow-Origin "*" env=CORS
Header set Access-Control-Allow-Methods "GET" env=CORS
Header set Access-Control-Allow-Credentials "false" env=CORS

另请参阅

  • Examples of Access Control in Action

  • HTTP Access Control covering the HTTP headers

  • XMLHttpRequest

  • Fetch API

Previous article: Next article: