Webhooks
Configure destinos de webhook para receber alertas de segurança do c/side via requisições HTTP POST com verificação de assinatura HMAC.
Como os webhooks funcionam
Os webhooks permitem que você receba notificações do c/side como requisições HTTP POST para uma URL que você especificar. Quando um trigger dispara, o c/side envia um payload JSON para o seu endpoint de webhook contendo detalhes sobre o evento.
Você pode configurar webhooks em três formatos:
- JSON - payload JSON padrão para integrações personalizadas
- Slack - pré-formatado para canais Slack
- Discord - pré-formatado para canais Discord
Adicionando um destino de webhook
Para adicionar um webhook como destino em uma notification config:
- Abra o painel e navegue até Team Settings > Notifications
- Crie uma nova notification config ou edite uma existente
- Em Send To, clique em Add destination e selecione Webhook
- No painel de Configuration, preencha:
- Endpoint URL: a URL onde você deseja receber as notificações de webhook (ex.:
https://example.com/cside/notify) - Secret: uma chave secreta usada para assinar as requisições de webhook (usada para verificação HMAC)
- Format: escolha JSON, Slack ou Discord
- Endpoint URL: a URL onde você deseja receber as notificações de webhook (ex.:
- Clique em Save ou Save & Test
O payload do webhook
Toda requisição de webhook contém um payload JSON estruturado com os seguintes campos:
event"alert.created"
sent_atstring
dataAlertCreatedObject
domain_idstring
destination_idstring
Events
Abaixo estão os IDs de eventos e seus payloads enviados com os webhooks.
Event IDs
| ID | Nome | Objeto data |
|---|---|---|
| alert.created | Alert Created | Alert Object |
Objetos de evento
type"URL"|"HASH"|"IP"|"DOMAIN"|"HOSTNAME"
domainstring
targetstring
action"alert"
Verificação HMAC
Toda requisição de webhook inclui um header x-cside-signature contendo um hash HMAC SHA256 do corpo da requisição, assinado com o secret que você forneceu ao criar o destino de webhook.
Você deve sempre verificar essa assinatura para confirmar que a requisição veio do c/side e prevenir ataques de replay.
Como verificar a assinatura
Se você está usando JavaScript, use nosso pacote JavaScript para verificação integrada.
Para outras linguagens, calcule o hash HMAC SHA256 do corpo bruto da requisição usando seu secret de webhook e compare-o com o valor do header x-cside-signature.
async function verifyHmac(body: string, signature: string, secret: string) {
const encoder = new TextEncoder();
const encodedBody = encoder.encode(body);
const key = await crypto.subtle.importKey(
"raw",
encoder.encode(secret),
{ name: "HMAC", hash: "SHA-256" },
false,
["sign"]
);
const signatureBuffer = await crypto.subtle.sign("HMAC", key, encodedBody);
const finalSig = Array.from(new Uint8Array(signatureBuffer))
.map((byte) => byte.toString(16).padStart(2, "0"))
.join("");
return signature.toLowerCase() === finalSig;
}fn verify_hmac(body: &str, signature: &str, secret: &str) -> Result<(), &'static str> {
let mut mac = HmacSha256::new_from_slice(secret.as_bytes()).map_err(|_| "Invalid secret")?;
mac.update(body.as_bytes());
let result = mac.finalize();
let code_bytes = result.into_bytes();
let final_sig = hex::encode(code_bytes);
if signature.to_lowercase() == final_sig {
Ok(())
} else {
Err("Invalid signature")
}
}
// Add to Cargo.toml:
// [dependencies]
// hmac = "0.12"
// sha2 = "0.10"
// hex = "0.4"package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"strings"
)
func verifyHmac(body, signature, secret string) bool {
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(body))
finalSig := hex.EncodeToString(h.Sum(nil))
return strings.ToLower(signature) == finalSig
}defmodule HmacVerifier do
def verify_hmac(body, signature, secret) do
final_sig =
:crypto.mac(:hmac, :sha256, secret, body)
|> Base.encode16(case: :lower)
String.downcase(signature) == final_sig
end
endimport hmac
import hashlib
import secrets
def verify_hmac(body: str, signature: str, secret: str) -> bool:
final_sig = hmac.new(
secret.encode('utf-8'),
body.encode('utf-8'),
hashlib.sha256
).hexdigest()
return signature.lower() == final_sigThanks for your feedback!