Para garantir a autenticidade de um webhook, é utilizada uma assinatura digital gerada a partir do payload da mensagem e uma chave secreta (secret-key). A secret-key é criada pela mobway no momento da configuração do webhook e deve ser mantida em sigilo.

Como a assinatura é gerada

A assinatura do webhook é gerada utilizando o método HMAC (Hash-based Message Authentication Code) com o algoritmo SHA-256. Esse método combina a secret-key com os dados enviados (payload) para criar uma assinatura única. Qualquer modificação no conteúdo ou no cabeçalho do webhook alterará a assinatura, tornando evidente qualquer tentativa de adulteração.

Exemplo de código (Python) para consumir o Webhook

O exemplo a seguir demonstra como criar uma interface para receber dados de veículos em tempo real via Webhook usando Python e a biblioteca Flask. Este aplicativo precisa ser hospedado online em uma URL que possa ser acessada pela mobway para o envio das informações.

from flask import Flask, request, jsonify, abort
import logging
import hmac
import hashlib
import threading
import asyncio
import json

app = Flask(__name__)

# chave secreta fornecida pela mobway
SECRET_KEY = 'SUA_SECRET_KEY_FORNECIDA_PELA_MOBWAY'

logging.basicConfig(level=logging.INFO)

def verify_signature(payload, signature):
    """
    Verifica a autenticidade da assinatura do webhook.
    
    Args:
        payload (str): O conteúdo do webhook recebido.
        signature (str): A assinatura HMAC recebida no cabeçalho do webhook.
    
    Returns:
        bool: True se a assinatura for válida, False caso contrário.
    """
    logging.info("Verificando assinatura...")
    computed_signature = hmac.new(SECRET_KEY.encode(), payload.encode(), hashlib.sha256).hexdigest()
    is_valid = hmac.compare_digest(computed_signature, signature)
    logging.info(f"Assinatura válida: {is_valid}")
    return is_valid

def process_data(data):
    """
    Processa os dados recebidos do webhook.
    
    Args:
        data (dict): Dados do payload em formato JSON.
    """
    logging.info(f"Processando dados: {data}")
    # Aqui você pode adicionar a lógica para tratar os dados recebidos

async def handle_request(payload, signature):
    """
    Lida com a requisição do webhook, verificando a assinatura e processando o payload.
    
    Args:
        payload (str): O conteúdo do webhook recebido.
        signature (str): A assinatura HMAC recebida no cabeçalho do webhook.
    """
    if not verify_signature(payload, signature):
        logging.warning("Assinatura inválida, abortando...")
        abort(403)
    
    logging.info("Assinatura verificada com sucesso, processando requisição...")
    data = json.loads(payload)
    thread = threading.Thread(target=process_data, args=(data,))
    thread.start()
    thread.join()

@app.route('/', methods=['GET'])
def home():
    """
    Rota básica para verificação de status do servidor.
    
    Returns:
        Response: Retorna uma mensagem de sucesso.
    """
    return jsonify({"status": "success"}), 200

@app.route('/webhook', methods=['POST'])
async def webhook():
    """
    Rota para receber os dados do webhook.
    
    Returns:
        Response: Retorna uma mensagem de sucesso após o processamento do webhook.
    """
    logging.info("Webhook recebido...")
    payload = request.get_data(as_text=True)
    signature = request.headers.get('X-Signature')
    await handle_request(payload, signature)
    logging.info("Webhook processado com sucesso!")
    return jsonify({"status": "success"}), 200

if __name__ == '__main__':
    logging.info("Iniciando aplicativo Flask...")
    app.run(host='0.0.0.0', port=5000, debug=True)

A rota /webhook, é onde o servidor espera receber os webhooks enviados pela mobway. Essa rota é configurada para aceitar apenas requisições HTTP do tipo POST. A função webhook associada a essa rota é assíncrona, o que permite ao servidor lidar com múltiplas requisições simultaneamente de maneira eficiente, sem bloquear a execução enquanto processa as requisições anteriores. Dentro da função webhook, o payload (os dados do webhook) e a assinatura digital são extraídos da requisição. A assinatura é enviada no cabeçalho da requisição sob o nome X-Signature. A função então delega a verificação da assinatura e o processamento dos dados para a função handle_request.

O servidor da mobway que envia os dados via webhook espera um código de resposta HTTP 200, indicando que os dados foram recebidos com sucesso. Caso qualquer outro código de erro seja retornado, o servidor tentará reenviar os dados sucessivamente até atingir um limite pré-definido. Para garantir que nenhum dado seja perdido, as informações são armazenadas, permitindo que sejam consultadas por outros meios, se necessário. Se o problema no recebimento dos dados persistir, o envio via webhook será interrompido, e a mobway entrará em contato para verificar e resolver a situação.

A função handle_request é responsável por validar a autenticidade da assinatura e processar os dados recebidos. Ela recebe o payload e a assinatura como parâmetros. Primeiramente, ela chama a função verify_signature para comparar a assinatura recebida com a assinatura esperada. A validação é feita utilizando HMAC com o algoritmo SHA-256, combinando o payload com a secret-key armazenada no servidor. Se a assinatura não for válida, a função aborta a operação, retornando um código de status HTTP 403, indicando que a requisição foi rejeitada por falta de autenticidade. Caso a assinatura seja válida, os dados são convertidos de uma string JSON para um dicionário e processados em uma thread separada.

A função verify_signature desempenha um papel crucial na segurança do webhook. Ela gera a assinatura localmente utilizando HMAC com SHA-256 e a secret-key, e em seguida, compara essa assinatura com a assinatura recebida na requisição.