A resposta de @ssnepenthe está certa ao dizer que o gancho que você está usando não é o item certo na solicitação de entrada.
As informações de solicitação estão disponíveis imediatamente para o PHP, para que você possa usar o gancho mais antigo disponível para verificá-las. E se você quiser fazer isso no contexto da API de solicitação, use o gancho mais antigo de uma solicitação da API REST. 'rest_pre_dispatch'
sugerido por @ssnepenthe está bem, talvez outra opção possa rest_authentication_errors
permitir que você retorne um erro caso algo esteja errado.
Mas Jack Johansson está certo ao dizer que os cabeçalhos HTTP (como o cabeçalho do referenciador usado no aswer de @ ssnepenthe) não são confiáveis, pois são facilmente alterados pelo cliente. Portanto, seria como colocar um guarda de segurança na frente de uma porta que apenas pergunta "é seguro deixá-lo entrar?" para quem quiser entrar: isso não vai funcionar.
Mas a solução proposta pela resposta de Jack Johansson (a nonce) também não é uma solução real: o ponto principal das nonces é mudar com o tempo, e um ponto de extremidade público da API não pode ter coisas que mudam com base no tempo. Além disso, os nonces do WP são confiáveis apenas quando há um usuário conectado, o que pode não ser o caso de uma API pública e, se um usuário está conectado, provavelmente não há razão para verificar o domínio recebido: você confia no usuário, não no máquina do usuário.
Então o que fazer?
Bem, mesmo que os cabeçalhos HTTP não sejam confiáveis, nem todas as informações disponíveis são $_SERVER
provenientes de cabeçalhos.
Normalmente, todos os $_SERVER
valores cujas chaves são iniciadas começam com HTTP_
cabeçalhos e precisam ser tratados como entrada não segura do usuário .
Mas, por exemplo, $_SERVER['REMOTE_ADDR']
contém o endereço IP usado para a conexão TCP com o servidor, o que significa que é confiável 1 .
O que também significa que:
- configurar corretamente o servidor para gerar o
$_SERVER['REMOTE_HOST']
valor (por exemplo, no Apache você precisará HostnameLookups On
dentro do seu httpd.conf
) esse valor
- usando
gethostbyaddr
para fazer uma pesquisa DNS reversa para resolver o nome de domínio do IP armazenado em$_SERVER['REMOTE_ADDR']
você poderia obter bastante confiável um nome de host que você pode usar para verificar contra uma whitelist (para o código, você pode adaptar o código de @ de ssnepenthe aswer onde você iria substituir $referer = $request->get_header('referer')
com $referer = gethostbyaddr($_SERVER['REMOTE_ADDR'])
).
Mas há um problema .
Se o servidor da web estiver protegido por um proxy reverso (solução bastante comum, na verdade), a conexão TCP com o servidor da web será realmente feita pelo proxy, assim $_SERVER['REMOTE_ADDR']
será o IP do proxy, e não o IP do cliente que enviou a solicitação originalmente.
O IP original da solicitação nesses casos geralmente está disponível como $_SERVER['HTTP_X_FORWARDED_FOR']
, mas ser um desses $_SERVER
valores que começa com HTTP_
ele não é realmente confiável.
Portanto, se seu servidor da web estiver protegido por um proxy reverso 2, mesmo $_SERVER['REMOTE_ADDR']
isso não seria útil para essa proteção e uma lista de permissões baseada em domínio só poderia ser implementada no nível do proxy.
Em suma, uma solução confiável para a proteção de endpoints da API deve ser implementada usando algum mecanismo de autenticação real (por exemplo, oAuth) ou deve ser feita agindo diretamente na configuração do servidor e não no nível do aplicativo.
Notas
1 Bem, em teoria, pode ser quebrado se alguém invadir seu ISP ou se um invasor agir de dentro da sua LAN, em ambos os casos, há muito pouco que você poderia fazer para estar seguro.
2 Se você não souber se possui um proxy reverso, poderá enviar uma solicitação do PC local e verificar se $_SERVER['REMOTE_ADDR']
no servidor corresponde ao IP do PC local e também se $_SERVER['HTTP_X_FORWARDED_FOR']
está presente e se corresponde ao IP do PC local.