Controle de Acesso do lado do servidor (CORS)

Esta tradução está incompleta. Ajude a traduzir este artigo em inglês

Os sistemas de controle de acesso realizam   identificação de autorizaçãoautenticação , aprovação de acesso e prestação de contas de entidades por meio de credenciais de login, incluindo  senhas , números de identificação pessoal (PINs),   varreduras biométricas e chaves físicas ou eletrônicas.

O controle de acesso é uma técnica de segurança que pode ser usada para regular quem ou o que pode exibir ou usar recursos em um ambiente de computação.

Os navegadores enviam Cabeçalhos HTTP específicos para solicitações entre sites iniciadas de dentro XMLHttpRequest ou da Fetch Api . Eles também esperam ver cabeçalhos HTTP específicos enviados de volta com respostas entre sites. Uma visão geral desses cabeçalhos, incluindo amostra de código JavaScript que inicia solicitações e processa respostas do servidor, além de uma discussão sobre cada cabeçalho, pode ser encontrada no artigo HTTP Access Control (CORS) article e deve ser lida como um artigo complementar para este. Este artigo aborda o processamento de solicitações de controle de acesso e a formulação de respostas de controle de acessoem PHP. O público-alvo deste artigo são programadores ou administradores de servidores. Embora os exemplos de código mostrados aqui estejam em PHP, conceitos semelhantes se aplicam ao ASP.net, Perl, Python, Java, etc .; em geral, esses conceitos podem ser aplicados a qualquer ambiente de programação do servidor que processa solicitações HTTP e formula dinamicamente respostas HTTP.

Discussão de cabeçalhos HTTP

O artigo que cobre os cabeçalhos HTTP usados por clientes e servidores deve ser considerado leitura de pré-requisito.

Amostras de código de trabalho

Os trechos de PHP (e as invocações de JavaScript para o servidor) nas seções subseqüentes são obtidos das amostras de código de trabalho postadas aqui. Eles funcionarão em navegadores que implementam sites cruzados XMLHttpRequest.

Solicitações simples entre sites

Solicitações simples de controle de acesso são iniciadas quando:

  • Um HTTP / 1.1 GET ou a POST é usado como método de solicitação. No caso de um POST, o Content-Type do corpo do pedido é uma de application/x-www-form-urlencoded, multipart/form-dataoutext/plain.
  • Nenhum cabeçalho personalizado é enviado com a solicitação HTTP (como X-Modified, etc.)

Nesse caso, as respostas podem ser enviadas de volta com base em algumas considerações.

  • Se o recurso em questão for amplamente acessado (como qualquer recurso HTTP acessado pelo GET), o envio do cabeçalho será suficiente, a menos que o recurso precise de credenciais, como informações de autenticação de cookies e HTTP. Access-Control-Allow-Origin: *
  • Se o recurso deve ser mantido restrito com base no domínio do solicitante, OU se o recurso precisar ser acessado com credenciais (ou define credenciais), Origin pode ser necessário filtrar pelo cabeçalho da solicitação ou, pelo menos, repetir o retorno do solicitante Origin ( por exemplo ). Além disso, o cabeçalho deverá ser enviado. Isso é discutido em uma seção subsequente . Access-Control-Allow-Origin: http://arunranga.com Access-Control-Allow-Credentials: true

A seção Solicitações de controle de acesso simples mostra as trocas de cabeçalho entre cliente e servidor. Aqui está um segmento de código PHP que lida com uma solicitação simples:

<?php

// Consideremos acesso apenas ao domínio arunranga.com
// Que achamos seguro acessar esse recurso como aplicattion / xml

if($_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>";
}
?>

O Origin item acima verifica se o cabeçalho enviado pelo navegador (obtido através de $ _SERVER ['HTTP_ORIGIN']]) corresponde a ' http://arunranga.com '. Se sim, ele retorna . Este exemplo pode ser visto em execução aqui . Access-Control-Allow-Origin: http://arunranga.com

Solicitações comprovadas

Solicitações de controle de acesso comprovadas ocorrem quando:

  • Um outro método que não GET ou POSTé utilizado, ou se POST é usado com um Content-Type diferente de um application/x-www-form-urlencoded, multipart/form-data ou text/plain. Por exemplo, se o Tipo de Conteúdo do corpo POST for application / xml, uma solicitação será comprovada.
  • Um cabeçalho personalizado (como X-PINGARUNER) é enviado com a solicitação.

A seção Solicitações de controle de acesso comprovado mostra uma troca de cabeçalho entre cliente e servidor. Um recurso do servidor que responde a uma solicitação de comprovação precisa poder fazer as seguintes determinações:

Aqui está um exemplo no PHP de manipulação de uma solicitação preflighted :

<?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") {
  // Diga ao cliente que apoiamos arunranga.com 
  // e que esse comprovante seja válido por 20 dias

  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") {
  //  Manipula o post primeiro obtendo o blob XML POST
  // e, em seguida, fazendo algo e enviando resultados para o cliente
 
  if($_SERVER['HTTP_ORIGIN'] == "http://arunranga.com") {
    $postData = file_get_contents('php://input');
    $document = simplexml_load_string($postData);
    
    // Faça algo com os dados POST 

    $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");
}
?>

Observe os cabeçalhos apropriados sendo enviados de volta em resposta à OPTIONS comprovação, bem como aos POST dados. Um recurso lida com a comprovação e com a solicitação real. Na resposta à OPTIONS solicitação, o servidor notifica o cliente de que a solicitação real pode realmente ser feita com o POST método e campos de cabeçalho como X-PINGARUNERpodem ser enviados com a solicitação real. Este exemplo pode ser visto em execução aqui .

Solicitações credenciadas

Solicitações de controle de acesso credenciadas - ou seja, solicitações acompanhadas de informações sobre cookies ou autenticação HTTP (e que esperam que os cookies sejam enviados com respostas) - podem ser simples ou comprovadas , dependendo dos métodos de solicitação utilizados.

Em um cenário de solicitação simples , a solicitação será enviada com cookies (por exemplo, se o withCredentials sinalizador estiver ativado XMLHttpRequest). Se o servidor responder com anexado à resposta credenciada, a resposta será aceita pelo cliente e exposta ao conteúdo da web. Em uma solicitação comprovada , Se o servidor responder com Access-Control-Allow-Credentials: true anexado à resposta credenciada, a resposta será aceita pelo cliente e exposta ao conteúdo da Web. Em uma Solicitação Comprovada, o servidor pode responder com Acesso-Controle-Permitir Credenciais: true à solicitação OPTIONS.

Aqui está um PHP que lida com solicitações credenciadas:

<?php

if($_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');

  // Primeiro, veja se existe um 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") {
  // Diga ao cliente que esse comprovante permanece válido por apenas 20 dias
  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");
}
?>

Observe que, no caso de solicitações credenciadas, o Access-Control-Allow-Origin: cabeçalho não deve ter um valor curinga de "*". Ele deve mencionar um domínio de origem válido. O exemplo acima pode ser visto em execução aqui .

Exemplos do Apache

Restringir o acesso a determinados URIs

Um truque útil é usar uma reescrita do Apache, variável de ambiente e cabeçalhos para aplicar Access-Control-Allow-*a determinados URIs. Isso é útil, por exemplo, para restringir solicitações de origem cruzada a GET /api(.*).jsonsolicitações sem credenciais:

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

Veja também