Tópico

Validação HMAC

A validação HMAC é como a FastOG verifica se cada solicitação de imagem OG baseada em assinatura veio do seu próprio servidor — URLs assinadas mantêm seus créditos seguros. Cadastre-se, escolha um plano de API Dinâmica e crie sua chave de API e segredo HMAC no painel; renderizações de API pagas são limpas. Esta página aborda as regras do lado do servidor por trás das imagens Open Graph dinâmicas, desde a assinatura canônica da consulta até a comparação em tempo constante.

Visão geral

A validação de assinatura HMAC-SHA256 foi adicionada ao endpoint /api/v1/og para impedir o uso não autorizado da cota da API. Isso garante que apenas solicitações do site legítimo possam gerar imagens OG.

Arquitetura

Autenticação em duas camadas:

  1. Assinatura HMAC (primeira) — Valida se a requisição se originou de uma fonte confiável (o site)
  2. Chave de API (segunda) — Identifica a conta do usuário para o controle de cota de renderização

Middleware único (ApiKeyAuth): verifica a assinatura (parâmetros de consulta) e resolve a chave de API para o controle de cota de renderização em uma única passada — falhe rapidamente em assinaturas inválidas.

Parâmetros de consulta, não cabeçalhos: Como as imagens OG são buscadas pelos rastreadores de redes sociais (LinkedIn, Twitter, Facebook) que não enviam cabeçalhos personalizados, a assinatura é passada nos parâmetros de consulta da URL:

GET /api/v1/og?title=Hello&key=sk_quick_123abc&s=<hmac>

Implementação

Arquivos Criados/Modificados

  • app/Http/Middleware/HmacSignature.php - Novo middleware validando assinaturas HMAC (parâmetros de consulta)
  • routes/api.php - Middleware HMAC adicionado à rota OG
  • bootstrap/app.php - Alias do middleware hmac registrado
  • app/Models/ApiKey.php - Campo hmac_secret adicionado (segredos por usuário)
  • app/Http/Controllers/DashboardController.php - Gera segredo HMAC na criação da chave de API
  • database/migrations/2026_08_03_214931_add_hmac_secret_to_api_keys_table.php - Migração para a coluna hmac_secret
  • resources/js/Pages/Dashboard/ApiKeys.svelte - Mostra o segredo HMAC ao usuário (uma única vez)
  • docs/hmac-signature-guide.md - Guia de implementação para o cliente
  • tests/Feature/HmacSignatureTest.php - 8 testes passando

Algoritmo de Assinatura

method = HTTP method (e.g., "GET")
path  = request path (e.g., "/api/v1/og")
query = the request's DECODED query params

canonical = every param except `s`, keys sorted (array values sorted too),
            each `key=value` RFC-3986 encoded (unreserved-only), joined with "&"
message   = method + "/" + path + "\n" + canonical
signature = HMAC-SHA256(message, hmac_secret)

Query parameters:
  key=<apiKey>
  s=<signature>
  (no timestamp)

key faz parte da consulta canônica, então a assinatura está vinculada à chave de API. Alterar qualquer parâmetro (título, template, imagem, …) ou a própria chave muda o canônico → incompatibilidade de assinatura → 401 → sem renderização, sem contagem de cota. Parâmetros idênticos → assinatura idêntica → URL idêntica → armazenável em cache na borda para sempre, reproduzida sem contagem.

Recursos de Segurança

  • Assinatura com endereçamento por conteúdo - Qualquer alteração de parâmetro → 401 → sem renderização, sem contagem de cota (a própria URL é a prova)
  • Sem timestamp - URLs são incorporadas em HTML público e armazenadas em cache para sempre; elas precisam sobreviver além de 5 minutos
  • Comparação em tempo constante (hash_equals()) - Previne ataques de timing
  • Chave de API na mensagem - A assinatura está vinculada à chave; trocar as chaves falha
  • Específica ao caminho - A assinatura é válida apenas para o caminho exato
  • Específica ao método - A assinatura GET não funciona para POST
  • Segredos por usuário - Cada chave de API tem seu próprio segredo HMAC, podendo ser revogado de forma independente (rotacionar = interruptor de emergência para URLs vazadas)

Configuração

Gerar Segredo (Automático)

O segredo HMAC é gerado automaticamente ao criar uma chave de API no painel de controle (dashboard). Ele é exibido uma única vez junto com a chave de API e nunca mais é mostrado novamente.

Geração manual (se necessário):

bash
openssl rand -hex 32

Esquema do Banco de Dados

sql
ALTER TABLE api_keys ADD COLUMN hmac_secret VARCHAR(64)
  COMMENT 'HMAC-SHA256 secret for signing OG image URLs (hex, 64 chars)';

Variáveis de Ambiente

Nenhuma variável de ambiente global é necessária — os segredos são armazenados por usuário na tabela api_keys.

Exemplo de Uso (Backend do Site)

javascript
// Node.js example - generate signed OG image URL
const crypto = require("crypto");

// RFC-3986 encode (encodeURIComponent leaves !'()* unencoded).
const enc = (s) =>
    encodeURIComponent(s).replace(
        /[!'()*]/g,
        (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase(),
    );

function generateOgImageUrl(baseUrl, params, apiKey, hmacSecret) {
    const all = { ...params, key: apiKey };

    // Canonical: every param (except s), sorted, RFC-3986 encoded, joined with "&".
    const pairs = [];
    for (const [k, v] of Object.entries(all)) {
        for (const vv of Array.isArray(v) ? [...v].sort() : [v])
            pairs.push(`${enc(k)}=${enc(vv)}`);
    }
    pairs.sort();
    const canonical = pairs.join("&");

    const message = `GET/api/v1/og\n${canonical}`;
    const signature = crypto
        .createHmac("sha256", hmacSecret)
        .update(message)
        .digest("hex");

    const url = new URL(baseUrl);
    for (const [k, v] of Object.entries(all)) {
        const isArray = Array.isArray(v);
        for (const vv of isArray ? v : [v])
            url.searchParams.append(isArray ? `${k}[]` : k, vv);
    }
    url.searchParams.set("s", signature);
    return url.toString();
}

// Usage in meta tag
const ogUrl = generateOgImageUrl(
    "https://fastog.com/api/v1/og",
    { title: "Como criar um SaaS", template: "blog" },
    "sk_quick_123abc",
    process.env.HMAC_SECRET,
);

// <meta property="og:image" content="{ogUrl}" />

Respostas de Erro

Status Código Descrição
401 missing_signature Parâmetro de consulta key ou s ausente
401 invalid_signature A assinatura não corresponde à consulta canônica (adulterada ou segredo incorreto)

Testes

Execute os testes:

bash
php artisan test --filter HmacSignatureTest

Todos os 8 testes passam:

  • ✅ Requisição sem assinatura é rejeitada
  • ✅ Requisição com parâmetro de chave ausente é rejeitada
  • ✅ Parâmetro de conteúdo adulterado (título alterado) é rejeitado
  • ✅ Parâmetro adicionado é rejeitado
  • ✅ Assinatura inválida é rejeitada
  • ✅ Assinatura válida passa na verificação HMAC
  • ✅ Assinatura é específica do caminho
  • ✅ Assinatura é específica do método
  • ✅ Chaves de API diferentes têm segredos diferentes

Impacto no Desempenho

  • Desprezível - O cálculo de HMAC-SHA256 leva ~0,1ms por requisição
  • Sem chamadas de rede adicionais - A validação é local
  • Falha rápida - Assinaturas inválidas são rejeitadas antes da consulta da chave de API

Considerações de Segurança

  1. Nunca exponha o segredo no código do lado do cliente - Assine apenas no servidor
  2. Use HTTPS - O HMAC protege contra requisições não autorizadas, o HTTPS protege contra ataques MITM
  3. Rotacione os segredos periodicamente - Especialmente se comprometidos (exige regenerar a chave de API)
  4. Monitore assinaturas com falha - Falhas repetidas podem indicar ataques
  5. Isolamento por usuário - Cada chave de API tem seu próprio segredo HMAC; o comprometimento de uma não afeta as demais

Referências

Referência Completa da API

Experimente grátis — sem necessidade de cadastro

Visualize e teste imagens OG dinâmicas em segundos.

Abrir o Testador de Imagens OG Grátis

A BeCaSimulations site