目录搜索
GuidesAccess control CORSAuthenticationBrowser detection using the user agentCachingCaching FAQCompressionConditional requestsConnection management in HTTP 1.xContent negotiationContent negotiation: List of default Accept valuesCookiesCSPMessagesOverviewProtocol upgrade mechanismProxy servers and tunnelingProxy servers and tunneling: Proxy Auto-Configuration (PAC) filePublic Key PinningRange requestsRedirectionsResources and specificationsResources and URIsResponse codesServer-Side Access ControlSessionGuides: BasicsBasics of HTTPChoosing between www and non-www URLsData URIsEvolution of HTTPIdentifying resources on the WebMIME TypesMIME types: Complete list of MIME typesCSPContent-Security-PolicyContent-Security-Policy-Report-OnlyCSP: base-uriCSP: block-all-mixed-contentCSP: child-srcCSP: connect-srcCSP: default-srcCSP: font-srcCSP: form-actionCSP: frame-ancestorsCSP: frame-srcCSP: img-srcCSP: manifest-srcCSP: media-srcCSP: object-srcCSP: plugin-typesCSP: referrerCSP: report-uriCSP: require-sri-forCSP: sandboxCSP: script-srcCSP: style-srcCSP: upgrade-insecure-requestsCSP: worker-srcHeadersAcceptAccept-CharsetAccept-EncodingAccept-LanguageAccept-RangesAccess-Control-Allow-CredentialsAccess-Control-Allow-HeadersAccess-Control-Allow-MethodsAccess-Control-Allow-OriginAccess-Control-Expose-HeadersAccess-Control-Max-AgeAccess-Control-Request-HeadersAccess-Control-Request-MethodAgeAllowAuthorizationCache-ControlConnectionContent-DispositionContent-EncodingContent-LanguageContent-LengthContent-LocationContent-RangeContent-TypeCookieCookie2DateDNTETagExpectExpiresForwardedFromHeadersHostIf-MatchIf-Modified-SinceIf-None-MatchIf-RangeIf-Unmodified-SinceKeep-AliveLarge-AllocationLast-ModifiedLocationOriginPragmaProxy-AuthenticateProxy-AuthorizationPublic-Key-PinsPublic-Key-Pins-Report-OnlyRangeRefererReferrer-PolicyRetry-AfterServerSet-CookieSet-Cookie2SourceMapStrict-Transport-SecurityTETkTrailerTransfer-EncodingUpgrade-Insecure-RequestsUser-AgentUser-Agent: FirefoxVaryViaWarningWWW-AuthenticateX-Content-Type-OptionsX-DNS-Prefetch-ControlX-Forwarded-ForX-Forwarded-HostX-Forwarded-ProtoX-Frame-OptionsX-XSS-ProtectionMethodsCONNECTDELETEGETHEADMethodsOPTIONSPATCHPOSTPUTStatus100 Continue101 Switching Protocols200 OK201 Created202 Accepted203 Non-Authoritative Information204 No Content205 Reset Content206 Partial Content300 Multiple Choices301 Moved Permanently302 Found303 See Other304 Not Modified307 Temporary Redirect308 Permanent Redirect400 Bad Request401 Unauthorized403 Forbidden404 Not Found405 Method Not Allowed406 Not Acceptable407 Proxy Authentication Required408 Request Timeout409 Conflict410 Gone411 Length Required412 Precondition Failed413 Payload Too Large414 URI Too Long415 Unsupported Media Type416 Range Not Satisfiable417 Expectation Failed426 Upgrade Required428 Precondition Required429 Too Many Requests431 Request Header Fields Too Large451 Unavailable For Legal Reasons500 Internal Server Error501 Not Implemented502 Bad Gateway503 Service Unavailable504 Gateway Timeout505 HTTP Version Not Supported511 Network Authentication RequiredStatus
文字

浏览器发送特定的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

上一篇:下一篇: