CORS (Cross-Origin Resource Sharing) é um mecanismo de segurança crucial para aplicações web modernas. Vamos explorar tudo sobre CORS em PHP, com exemplos práticos incluindo configuração via .htaccess.
O que é CORS?
CORS é um mecanismo que permite que recursos restritos em uma página web sejam solicitados de outro domínio fora do domínio ao qual pertence o recurso que será solicitado.
Por que CORS é importante?
- Segurança: Evita requisições não autorizadas entre domínios diferentes
- Flexibilidade: Permite APIs serem consumidas por diferentes front-ends
- Controle: Define exatamente quais origens, métodos e headers são permitidos
Configurando CORS no PHP
Método básico com headers PHP
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
header("Access-Control-Allow-Credentials: true");
// Sua lógica de aplicação continua aqui...
Versão mais segura (origem específica)
<?php
$allowedOrigins = [
"https://seusite.com",
"https://app.seusite.com",
"http://localhost:3000"
];
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($origin, $allowedOrigins)) {
header("Access-Control-Allow-Origin: $origin");
}
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Max-Age: 86400"); // Cache por 24 horas
// Tratamento para requisições OPTIONS (preflight)
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
header("HTTP/1.1 200 OK");
exit();
}
Configurando CORS via .htaccess
Para quem usa Apache, o .htaccess pode ser uma forma mais limpa de gerenciar CORS:
Configuração básica no .htaccess
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
Header set Access-Control-Allow-Headers "Content-Type, Authorization"
</IfModule>
Configuração avançada no .htaccess
<IfModule mod_headers.c>
SetEnvIf Origin "^(https?://(localhost:\d+|(.*\.)?seusite\.com)(:\d+)?)$" CRS=$0
Header always set Access-Control-Allow-Origin "%{CRS}e" env=CRS
Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Header always set Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With"
Header always set Access-Control-Allow-Credentials "true"
Header always set Access-Control-Max-Age "86400"
# Resposta para requisições OPTIONS (preflight)
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
</IfModule>
Lidando com Credenciais
Quando você precisa enviar cookies ou autenticação via CORS:
<?php
header("Access-Control-Allow-Origin: https://seusite.com");
header("Access-Control-Allow-Credentials: true");
// Para ler cookies em requisições cross-origin
session_set_cookie_params([
'samesite' => 'None',
'secure' => true,
'httponly' => true
]);
session_start();
Exemplo Completo: API PHP com CORS
<?php
// config_cors.php
function handleCORS() {
$allowedOrigins = [
"https://seusite.com",
"https://app.seusite.com",
"http://localhost:3000"
];
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($origin, $allowedOrigins)) {
header("Access-Control-Allow-Origin: $origin");
header("Access-Control-Allow-Credentials: true");
} else {
header("Access-Control-Allow-Origin: null");
}
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");
header("Access-Control-Max-Age: 86400");
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
header("HTTP/1.1 200 OK");
exit();
}
}
// api.php
require 'config_cors.php';
handleCORS();
header("Content-Type: application/json");
$response = [
'status' => 'success',
'data' => [
'message' => 'API funcionando com CORS configurado!',
'timestamp' => time()
]
];
echo json_encode($response);
Problemas Comuns e Soluções
- Erro “No ‘Access-Control-Allow-Origin’ header”
- Verifique se o header está sendo enviado
- Confira se o domínio de origem está na lista de permitidos
- Cookies não são enviados
- Certifique-se que
Access-Control-Allow-Credentials: true
- Configure os cookies com
SameSite=None
eSecure
- Headers personalizados bloqueados
- Adicione todos os headers necessários em
Access-Control-Allow-Headers
- Métodos HTTP não permitidos
- Inclua todos os métodos necessários em
Access-Control-Allow-Methods
Boas Práticas
- Nunca use
*
paraAccess-Control-Allow-Origin
quando estiver usando credenciais - Limite os métodos HTTP permitidos apenas aos necessários
- Considere usar um middleware para gerenciar CORS em aplicações grandes
- Para APIs públicas, documente claramente as políticas CORS
Testando sua Configuração CORS
Você pode testar usando curl:
curl -H "Origin: http://seusite.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: X-Requested-With" \
-X OPTIONS --verbose http://suaapi.com/endpoint
Ou via JavaScript:
fetch('http://suaapi.com/endpoint', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token'
},
body: JSON.stringify({test: 'data'})
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
Conclusão
Configurar corretamente o CORS é essencial para a segurança e funcionalidade de suas aplicações web. Com PHP, você tem flexibilidade para implementar tanto soluções simples quanto configurações complexas e granulares. O uso do .htaccess pode simplificar a manutenção, especialmente em ambientes compartilhados.
Lembre-se: segurança primeiro! Sempre restrinja as permissões ao mínimo necessário para o funcionamento da sua aplicação.
Quer um bônus secreto? Aqui vai uma pérola para debug em produção:
// debug_cors.php (remover depois!) file_put_contents('cors_log.txt', date('Y-m-d H:i:s') . " - " . ($_SERVER['HTTP_ORIGIN'] ?? 'NO_ORIGIN') . "\n", FILE_APPEND );
Isso cria um log simplão pra ver quais origens estão batendo na sua API (útil quando o cliente diz “não funciona” mas esquece te dizer qual domínio está usando 😅).