Usando o WP 4.8.2
Qual é a melhor maneira de verificar o URL solicitante ao processar uma solicitação com a rest-api?
Por exemplo, um site recebe uma solicitação e você deseja verificar se veio de um URL 'permitido'. E falhe se o URL não for permitido.
Isso não funciona:
function my_check_request_url( $request, $url ) {
$bits = parse_url( $url );
if ( $bits['host'] != 'example.com' )
$request = false;
return $request;
}
add_filter( 'rest_request_from_url', 'my_check_request_url', 10, 2 );
$request
e os$url
vars se parecem com viavar_dump
ou similar, acho que a inspeção das entradas e saídas sempre leva a uma resposta adequada.Respostas:
Esse filtro definitivamente não é o que você está procurando. Esse filtro é acionado antes de retornar o resultado, o
WP_REST_Request::from_url()
que parece ser um método de fábrica usado apenas internamente para manipular incorporações.Uma opção melhor é retornar uma
WP_Error
instância norest_pre_dispatch
filtro .Algumas advertências:
Conforme mencionado por @milo, o referenciador não é confiável e não deve ser usado para uma verificação de segurança.
Além disso, não é garantido que seja definido.
Com aqueles fora do caminho, aqui está um exemplo de como você pode usar o
rest_pre_dispatch
filtro para causar falha na solicitação se for de um referenciador incorreto:fonte
Tudo o que você recebe do cliente é considerado como entrada do usuário e não deve ser confiável. Como o cabeçalho pode ser facilmente manipulado e abusado, minha sugestão é não usar esse método se você estiver contando com ele para obter dados confidenciais.
Se os pedidos vierem de uma página, você poderá ter outra abordagem. Caso contrário, qualquer pessoa poderá enviar uma solicitação para a API do nada e alterar o referenciador.
Digamos que você tenha várias páginas filtradas como "Permitidas" . Você pode criar um aviso apenas para essas páginas e validá-las em sua solicitação.
Se um nounce existir e for válido, a solicitação será permitida. Caso contrário, bloqueie-o.
fonte
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 possarest_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 comHTTP_
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:
$_SERVER['REMOTE_HOST']
valor (por exemplo, no Apache você precisaráHostnameLookups On
dentro do seuhttpd.conf
) esse valorgethostbyaddr
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 comHTTP_
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.fonte