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 é o customerName;

  • sub é o subscriberId;

  • jti é o transactionId;

  • 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.

subscribers create security
Caso a chave não seja informada dentro do tempo, clique no ícone icon refresh (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 icon token.

    subscribers create security static

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.

    subscribers create security dynamic

Não há refresh dos tokens dinâmicos cadastrados. Os tokens são reutilizados durante o tempo definido pelo usuário.
Thanks for your feedback!
EDIT

Share your suggestions with us!
Click here and then [+ Submit idea]