O plug-in hmac-auth gera assinaturas infalsificáveis para requisições HTTP com base no algoritmo HMAC e as utiliza para autenticação de identidade.
Tipo de plug-in
Autenticação e autorização.
Campos
Configuração de autenticação
|
Campo |
Tipo de dados |
Obrigatório |
Valor padrão |
Descrição |
|
consumers |
array of object |
Sim |
- |
Chamadores do serviço usados para autenticar requisições. |
|
date_offset |
number |
Não |
- |
Deslocamento máximo de tempo permitido para o cliente, em segundos. O sistema analisa a hora UTC do cliente no cabeçalho de requisição |
|
global_auth |
array of string |
Não (obrigatório apenas para configurações no nível da instância) |
- |
Aplicável somente no nível da instância. Se definido como true, a autenticação entra em vigor globalmente. Se definido como false, aplica-se apenas aos nomes de domínio e rotas configurados. Sem configuração, a autenticação torna-se global apenas quando não há nomes de domínio ou rotas definidos. |
Campos em consumers:
|
Campo |
Tipo de dados |
Obrigatório |
Valor padrão |
Descrição |
|
key |
string |
Sim |
- |
Chave de acesso do consumidor. |
|
secret |
string |
Sim |
- |
Segredo usado para gerar a assinatura. |
|
name |
string |
Sim |
- |
Nome do consumidor. |
(Opcional) Configuração de autorização
|
Campo |
Tipo de dados |
Obrigatório |
Valor padrão |
Descrição |
|
allow |
array of string |
Não (obrigatório para configurações fora do nível de instância) |
- |
Configurável apenas nos níveis de rota ou nome de domínio. Especifica quais consumidores podem acessar requisições correspondentes, permitindo controle granular de permissões. |
Configurações de autorização e autenticação não podem coexistir na mesma regra.
Em requisições autenticadas, o sistema adiciona o cabeçalho
X-Mse-Consumerpara identificar o chamador.
Exemplos
Configure autenticação globalmente e defina autorização para rotas
O exemplo a seguir ativa a autenticação hmac-auth para rotas ou domínios específicos. O campo key deve ser único.
Aplique as seguintes configurações de plug-in no nível da instância:
global_auth: false
consumers:
- key: appKey-example-1
secret: appSecret-example-1
name: consumer-1
- key: appKey-example-2
secret: appSecret-example-2
name: consumer-2
Aplique a seguinte configuração de plug-in às rotas route-a e route-b:
allow:
- consumer1
Aplique a seguinte configuração de plug-in aos nomes de domínio *.example.com e test.com:
allow:
- consumer2
Neste exemplo, as rotas
route-aeroute-bcorrespondem às especificadas durante a criação das rotas do gateway. Se uma requisição do cliente corresponder a uma dessas rotas, apenas o chamador cujonamesejaconsumer1terá acesso ao gateway. O sistema bloqueia outros chamadores.Os nomes de domínio
*.example.cometest.comservem para corresponder aos domínios nas requisições. Se uma requisição do cliente coincidir com um desses domínios, o chamador comnameigual aconsumer2poderá acessar o gateway. Demais chamadores não terão permissão de acesso.
Ative o plug-in traffic-tag para gateways
global_auth: true
consumers:
- key: appKey-example-1
secret: appSecret-example-1
name: consumer-1
- key: appKey-example-2
secret: appSecret-example-2
name: consumer-2
Mecanismo de assinatura
Preparação da configuração
Configure as seguintes credenciais para gerar e validar assinaturas:
key: usada no cabeçalho de requisição
x-ca-key.secret: usada para gerar a assinatura da requisição.
Gerar uma assinatura no cliente
Processo
O cliente gera uma assinatura executando estas etapas:
Extraia os dados principais da requisição original para compor a string de assinatura.
Criptografe a string de assinatura com o
secretconfigurado para produzir a assinatura.Adicione todos os cabeçalhos relacionados à assinatura à requisição HTTP original.
Extrair a string de assinatura
O cliente extrai dados essenciais da requisição HTTP e os combina em uma string de assinatura no seguinte formato:
HTTPMethod
Accept
Content-MD5
Content-Type
Date
Headers
PathAndParameters
Esses campos são separados por \n. Se o campo Headers estiver vazio, o \n não é necessário. Para outros campos vazios, mantenha o \n. A assinatura diferencia maiúsculas de minúsculas.
Regras de extração para cada campo:
HTTPMethod: método HTTP, como POST. Use letras maiúsculas.
Accept: valor do cabeçalho de requisição Accept. Pode estar vazio. Defina explicitamente o cabeçalho Accept, pois alguns clientes HTTP usam
*/*como padrão, o que causa falha na verificação da assinatura.-
Content-MD5: valor do cabeçalho Content-MD5. Pode estar vazio. Calcule-o apenas quando a requisição contiver um corpo que não seja de formulário. Exemplo em Java:
String content-MD5 = Base64.encodeBase64(MD5(bodyStream.getbytes("UTF-8"))); Content-Type: valor do cabeçalho Content-Type. Pode estar vazio.
Date: valor do cabeçalho Date, usado para verificação de deslocamento de tempo. Pode estar vazio se
date_offsetnão estiver configurado.-
Headers: cabeçalhos incluídos na assinatura. Regras de concatenação:
-
Ordene as chaves dos cabeçalhos alfabeticamente e concatene-as da seguinte forma:
HeaderKey1 + ":" + HeaderValue1 + "\n"\+ HeaderKey2 + ":" + HeaderValue2 + "\n"\+ ... HeaderKeyN + ":" + HeaderValueN + "\n" Se o valor de um cabeçalho estiver vazio, use HeaderKey + ":" + "\n" para a assinatura. Mantenha a chave e os dois pontos (:).
As chaves de cabeçalho usadas na assinatura são separadas por vírgulas (,) e inseridas no cabeçalho
X-Ca-Signature-Headers.Não use os seguintes cabeçalhos no cálculo da assinatura: X-Ca-Signature, X-Ca-Signature-Headers, Accept, Content-MD5, Content-Type e Date.
-
-
PathAndParameters: contém o caminho, parâmetros de consulta e de formulário.
Path + "?" + Key1 + "=" + Value1 + "&" + Key2 + "=" + Value2 + ... "&" + KeyN + "=" + ValueN
As chaves dos parâmetros de consulta e de formulário são ordenadas alfabeticamente e depois concatenadas conforme descrito acima.
Se os parâmetros de consulta e de formulário estiverem vazios, utilize apenas o caminho, sem adicionar informações de assinatura.
Para parâmetros de array com a mesma chave mas valores diferentes, apenas o primeiro valor é considerado no cálculo da assinatura.
Exemplo de extração da string de assinatura
Requisição HTTP inicial:
POST /http2test/test?param1=test HTTP/1.1
host:api.aliyun.com
accept:application/json; charset=utf-8
ca_version:1
content-type:application/x-www-form-urlencoded; charset=utf-8
x-ca-timestamp:1525872629832
date:Wed, 09 May 2018 13:30:29 GMT+00:00
user-agent:ALIYUN-ANDROID-DEMO
x-ca-nonce:c9f15cbf-f4ac-4a6c-b54d-f51abf4b5b44
content-length:33
username=xiaoming&password=123456789
String de assinatura gerada:
POST
application/json; charset=utf-8
application/x-www-form-urlencoded; charset=utf-8
Wed, 09 May 2018 13:30:29 GMT+00:00
x-ca-key:203753385
x-ca-nonce:c9f15cbf-f4ac-4a6c-b54d-f51abf4b5b44
x-ca-signature-method:HmacSHA256
x-ca-timestamp:1525872629832
/http2test/test?param1=test&password=123456789&username=xiaoming
Calcular a assinatura
Após gerar a string de assinatura, o cliente a criptografa e codifica para obter a assinatura final.
Neste código, stringToSign representa a string de assinatura extraída, secret vem da configuração do plug-in e sign é a assinatura final.
Mac hmacSha256 = Mac.getInstance("HmacSHA256");
byte[] secretBytes = secret.getBytes("UTF-8");
hmacSha256.init(new SecretKeySpec(secretBytes, 0, secretBytes.length, "HmacSHA256"));
byte[] result = hmacSha256.doFinal(stringToSign.getBytes("UTF-8"));
String sign = Base64.encodeBase64String(result);
A stringToSign é decodificada em um array de bytes UTF-8, criptografada com o algoritmo HMAC e então codificada em Base64 para gerar a assinatura.
Adicionar a assinatura
Inclua os seguintes cabeçalhos nas requisições enviadas ao Cloud-native API Gateway para verificação da assinatura:
x-ca-key: a AppKey. Obrigatório.
x-ca-signature-method: algoritmo de assinatura. Opcional. Valores válidos: HmacSHA256 e HmacSHA1. Valor padrão: HmacSHA256.
x-ca-signature-headers: todas as chaves de cabeçalho da assinatura, separadas por vírgulas (,). Opcional.
x-ca-signature: a assinatura. Obrigatório.
Exemplo de requisição HTTP com assinatura:
POST /http2test/test?param1=test HTTP/1.1
host:api.aliyun.com
accept:application/json; charset=utf-8
ca_version:1
content-type:application/x-www-form-urlencoded; charset=utf-8
x-ca-timestamp:1525872629832
date:Wed, 09 May 2018 13:30:29 GMT+00:00
user-agent:ALIYUN-ANDROID-DEMO
x-ca-nonce:c9f15cbf-f4ac-4a6c-b54d-f51abf4b5b44
x-ca-key:203753385
x-ca-signature-method:HmacSHA256
x-ca-signature-headers:x-ca-timestamp,x-ca-key,x-ca-nonce,x-ca-signature-method
x-ca-signature:xfX+bZxY2yl7EB/qdoDy9v/uscw3Nnj1pgoU+Bm6xdM=
content-length:33
username=xiaoming&password=123456789
Verifique a assinatura no servidor
Processo
O servidor valida a assinatura do cliente seguindo estas etapas:
Extraia os dados principais da requisição para obter a string de assinatura.
Leia a
keyda requisição e localize osecretcorrespondente.Criptografe a string de assinatura com o
secretpara gerar uma assinatura.Compare a assinatura gerada no servidor com a assinatura do cliente presente na requisição.
Solucionar erros de assinatura
Quando a verificação da assinatura falha, o servidor retorna o StringToSign do lado do servidor no cabeçalho de resposta X-Ca-Error-Message. Compare-o com o StringToSign do cliente para identificar a discrepância.
Se os dois valores coincidirem, verifique o AppSecret utilizado no cálculo da assinatura.
Como cabeçalhos HTTP não aceitam quebras de linha, as quebras de linha no StringToSign são substituídas por #.
X-Ca-Error-Message: Server StringToSign:`GET#application/json##application/json##X-Ca-Key:200000#X-Ca-Timestamp:1589458000000#/app/v1/config/keys?keys=TEST`
Códigos de erro
|
Código de status HTTP |
Mensagem de erro |
Motivo |
|
400 |
Invalid Signature. |
A assinatura em x-ca-signature não corresponde à assinatura calculada pelo servidor. |
|
400 |
Invalid Content-MD5. |
O cabeçalho de requisição Content-MD5 é inválido. |
|
400 |
Invalid Date. |
O deslocamento de tempo do cabeçalho de requisição Date excede o date_offset configurado. |
|
401 |
Invalid Key. |
O cabeçalho de requisição x-ca-key está ausente ou é inválido. |
|
401 |
Empty Signature. |
O cabeçalho de requisição x-ca-signature está vazio. |
|
403 |
Unauthorized Consumer. |
O chamador da requisição não possui permissões de acesso. |
|
413 |
Request Body Too Large. |
O corpo da requisição excede 32 MB. |
|
413 |
Payload Too Large. |
O corpo da requisição ultrapassa o DownstreamConnectionBufferLimits configurado para o gateway. Aumente o DownstreamConnectionBufferLimits na página de configuração de parâmetros. |
Aumentar o DownstreamConnectionBufferLimits eleva significativamente o uso de memória do gateway. Proceda com cautela.