Subscribers: Segurança e Chaves
Assinatura do subscritor
Todas as requisições feitas para os subscritores de eventos são assinadas por um mecanismo que permite aos subscritores a verificação da procedência da mensagem. A assinatura é um token gerado pelo Sensedia Events Hub a partir de uma chave de conhecimento mútuo (entre o Events Hub e o subscritor) que é enviada durante o cadastro de subscritores (veja sobre o envio abaixo).
A assinatura gerada será um JWT (JSON Web Token) com o algoritmo HS256 (HMAC com SHA-256), feita com os seguintes valores:
Header:
{
"typ": "JWT",
"alg": "HS256"
}
Payload:
{
"iss": "staging",
"sub": "7f08e914-3e64-4acb-9a1e-d21f9cbabcba",
"jti": "266dd6d0-4f21-4191-aa05-2d9833fd8eee",
"c_hash": "0d320d3ab6b8165bc347c1ffabbe1bfd6dbe1b436df23131a8f855f35834c2cc",
"iat": 1603894744
}
em que:
-
iss
é ocustomerName
; -
sub
é osubscriberId
; -
jti
é otransactionId
; -
c_hash
é o conteúdo do corpo em SHA-256; e -
iat
é o timestamp do envio, usando fuso horário UTC.
Chave de assinatura
Uma chave de conhecimento mútuo deve ser informada na criação de um subscritor no Events Hub (veja sobre a criação de subscritores aqui). A subscrição em eventos só é possível após inserir a chave no campo Key e clicar em VALIDATE KEY.
Caso a chave não seja informada dentro do tempo, clique no ícone (que aparecerá na tela) para reiniciar a contagem do tempo. Uma vez validada, a chave fica armazenada de forma segura e não pode ser recuperada. |
Token JWT
O subscritor sempre receberá a assinatura em um header de requisição identificado por x-CLIENTE-webhooks-signature
— sendo o conteúdo trafegado sempre em Base64 — independe de ele usá-la ou não para verificação ou se optar por utilizar os mecanismos de segurança disponíveis abaixo neste documento.
Ou seja, o Events Hub sempre irá trafegar a assinatura nas requisições aos subscritores, como neste exemplo de header:
{
"Content-Type": "application/json",
"x-sensedia-webhooks-signature": "Y2E4MWNiMTYtNDNlNC0zZTk2LWFhZWEtNDg2MWU3NzkxZGM3"
}
O usuário pode validar a assinatura JWT em seu código. No exemplo abaixo, usamos Java:
// Validar assinatura JWT
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
public static Claims decodeJWT(String jwt, byte[] subscriberKey) {
//This line will throw an exception if it is not a signed JWS (as expected)
Claims claims = Jwts.parser().setSigningKey(subscriberKey).parseClaimsJws(jwt).getBody();
return claims;
}
A chave subscriberKey do código acima é a chave mútua enviada pelo POST descrito acima.
|
Opções de tokens de segurança
Além da assinatura, que é sempre trafegada, o Events Hub disponibiliza também a opção de envio de um token para requisitos de segurança dos receptores dos eventos.
Após o subscritor ter cadastrado sua chave mútua para a geração da assinatura, ele pode optar por receber suas requisições com a adição de um token. Há duas opções de token: estático e dinâmico (sendo que o primeiro não expira e o segundo sim). Ambos deverão ser tokens hash em formato SHA-256 e em Base64.
Em ambos os casos, o subscritor também contará com a chave de assinatura para a validação e garantia da requisição.
Se o token for configurado para ser trafegado no header, tanto a assinatura quanto o token estarão presentes (o token sob o nome que for configurado pelo usuário, que no exemplo abaixo é security-token
):
{
"x-sensedia-webhooks-signature": "ZXlKMGVYQWlPaUpLVjFRaUxDSmhiR2NpT2lKSVV6STFOaUo5LmV5SnBjM01pT2lKemRHRm5hVzVuSWl3aWMzVmlJam9pTW1JMFlUVTJZV0V0WkdVeU55MDBPVEl6TFdFeVltTXRNbVkyTVRBMU0yVmpNamcwSWl3aWFuUnBJam9pWXprNU56UmxNekV0TURRNU1TMDBPREJoTFRrelpUWXRabVJqWlRFek1EaGlNR0V3SWl3aVkxOW9ZWE5vSWpvaVl6bGtNMkZqT0RJMU1UYzFNR1psTWpNd01EQTVPR1ptTVRWaFlUYzJOVEprTVRWbE5UQmpOemxoWXpSaVlqaGhOMlEwWWpobE1URXdOekpqTlRoaVl5SXNJbWxoZENJNk1UWXhPRFF3TlRnMU9YMC56UTVYTnpEaE5ZdU5DTVd1a0ktckZxeTkzbFFoYnRXalc2ZDNpT3dlUV9B",
"security-token": "YWJjZGVmZmYtYXNkYXNkLWFzZC12c2JkZmRnZGYtNG1hc2Rkd2V1Z3VkYQ"
}
Você pode configurar apenas um token por subscritor. |
Token estático
Ao optar por receber suas requisições adicionando um token estático (que não expira), ele pode ser cadastrado diretamente no Events Hub. Então, é necessário informar o valor do token que será trafegado em todas as requisições.
Vale ressaltar que essa é a abordagem mais simples e que incorre em menos recursos e codificação do lado do subscritor (em comparação ao token dinâmico). No entanto, é mais suscetível a ataques (como um simples ataque de repetição, por exemplo).
O token deve ser configurado na etapa SECURITY de cadastro ou edição de um subscriber, por meio dos seguintes campos:
-
Type: tipo do token (escolher Static).
-
Location: onde o token deverá ser passado na requisição (opções: header ou query param).
-
Name: nome com o qual o valor do token será passado.
-
Token SHA-256: valor do token. Se desejar, é possível gerar um token randômico pelo ícone .
Token dinâmico
O token dinâmico oferece maior segurança no tráfego de mensagens entre o Events Hub e os subscritores em relação ao token estático. O token dinâmico tem um período de expiração e é totalmente gerenciado pelo subscritor.
Quando tokens dinâmicos são utilizados, o subscritor terá que dispor de mais recursos e ficará com boa parte da responsabilidade de uptime do ecossistema. Isso porque o Events Hub será totalmente dependente do subscritor para obter os tokens, o que pode causar o não recebimento de mensagens. Contudo, o dinamismo do mecanismo dificulta possíveis ataques, configurando-se como uma opção mais segura.
Optando por essa abordagem, o subscritor necessariamente terá que disponibilizar uma interface para que o Events Hub obtenha o token. Essa interface deverá prover um HTTP POST que será responsável por gerar os tokens.
Vale ressaltar que, nessa abordagem, o subscriber sempre deve validar a assinatura que será trafegada também na requisição de token pelo Events Hub. |
A interface deverá receber:
Header:
{
"content-type": "application/json",
"x-CLIENTE-webhooks-signature": "xxxxxxx"
}
Body:
{
"type": "token"
}
A interface deverá responder:
Header:
{
"content-type": "application/json"
}
Body:
{
"access_token": "<Token de acesso (hash em SHA-256 e Base64)>",
"expires_in": "<Tempo de expiração do token em segundos>"
}
O token deve ser configurado na etapa SECURITY de cadastro ou edição de um subscriber, por meio dos seguintes campos:
-
Type: tipo do token (escolher Dynamic).
-
Location: onde o token deverá ser passado na requisição (opções: header ou query param).
-
Name: nome com o qual o valor do token será passado.
-
URL OAuth: URL de geração do valor do token.
Não há refresh dos tokens dinâmicos cadastrados. Os tokens são reutilizados durante o tempo definido pelo usuário. |
Share your suggestions with us!
Click here and then [+ Submit idea]