Canais criptografados
Um canal cujo nome começa com private-encrypted- possui criptografia de ponta a ponta. Seu servidor sela cada payload antes de publicá-lo, e clientes de navegador autorizados o descriptografam com uma chave do seu endpoint de autorização. O edge do Realtime e intermediários de rede veem apenas texto cifrado.
Gere e armazene uma chave mestra de 32 bytes. A chave mestra nunca aparece em uma solicitação API do Realtime, e o prefixo do nome do canal habilita o recurso. Bird não consegue recuperar uma chave perdida, e payloads selados com essa chave permanecem ilegíveis após você substituí-la.
Canais criptografados usam o mesmo endpoint e assinatura que os canais privados. A resposta de autorização também inclui a chave de descriptografia derivada do canal como shared_secret. Rejeitar uma inscrição impede que o cliente receba a chave.
Gerar uma chave mestra
Gere 32 bytes aleatórios, codifique-os como base64 e armazene o valor como o app secret:
Exemplo de código
openssl rand -base64 32Forneça-a ao SDK do seu servidor como parte da configuração do realtime, junto com a app key e o secret.
Publicar um evento criptografado
O SDK do servidor detecta o prefixo do canal, deriva a chave a partir da chave mestra e sela o payload JSON localmente. A solicitação de publicação contém o envelope selado.
import { BirdClient } from "@messagebird/sdk";
const bird = new BirdClient({
apiKey: process.env.BIRD_API_KEY,
realtime: {
key: process.env.BIRD_REALTIME_KEY,
secret: process.env.BIRD_REALTIME_SECRET,
encryptionMasterKey: process.env.BIRD_REALTIME_MASTER_KEY,
},
});
await bird.realtime.publish("rap_01krdgeqcxet5s7t44vh8rt9mg", {
event: "order.updated",
channels: ["private-encrypted-orders"],
data: { order_id: "ord_123", status: "shipped" },
});from bird import Bird
client = Bird(
realtime_key=os.environ["BIRD_REALTIME_KEY"],
realtime_secret=os.environ["BIRD_REALTIME_SECRET"],
realtime_encryption_master_key=os.environ["BIRD_REALTIME_MASTER_KEY"],
)
client.realtime.publish(
"rap_01krdgeqcxet5s7t44vh8rt9mg",
event="order.updated",
channels=["private-encrypted-orders"],
data={"order_id": "ord_123", "status": "shipped"},
)client, err := bird.NewClient(
option.WithAPIKey(os.Getenv("BIRD_API_KEY")),
option.WithRealtimeCredentials(os.Getenv("BIRD_REALTIME_KEY"), os.Getenv("BIRD_REALTIME_SECRET")),
option.WithRealtimeEncryptionMasterKey(os.Getenv("BIRD_REALTIME_MASTER_KEY")),
)
if err != nil {
log.Fatal(err)
}
_, err = client.Realtime.Publish(context.Background(), "rap_01krdgeqcxet5s7t44vh8rt9mg", bird.RealtimePublishParams{
Event: "order.updated",
Channels: []string{"private-encrypted-orders"},
Data: map[string]any{"order_id": "ord_123", "status": "shipped"},
})$bird = new Bird(getenv('BIRD_API_KEY'), realtime: new RealtimeOptions(
key: getenv('BIRD_REALTIME_KEY'),
secret: getenv('BIRD_REALTIME_SECRET'),
encryptionMasterKey: getenv('BIRD_REALTIME_MASTER_KEY'),
));
$bird->realtime->publish('rap_01krdgeqcxet5s7t44vh8rt9mg', (new RealtimePublish())
->setEvent('order.updated')
->setChannels(['private-encrypted-orders'])
->setData(['order_id' => 'ord_123', 'status' => 'shipped']));Um canal criptografado deve ser o único canal em uma única publicação. Cada canal criptografado deriva uma chave diferente, então outros canais não conseguiriam descriptografar o mesmo payload selado. Os SDKs rejeitam esse fan-out localmente, e o API retorna E23000 se receber um. Para publicar em vários canais criptografados, use um batch com um canal por evento.
Retornar o segredo compartilhado do seu endpoint de autenticação
Seu endpoint de autenticação aprova inscrições criptografadas da mesma forma que aprova inscrições privadas. Use o helper authorizeChannel do SDK e a resposta ganha o shared_secret automaticamente sempre que o nome do canal tiver o prefixo criptografado:
app.post("/bird/auth", async (req, res) => {
const { connection_id, channel_name } = req.body;
const user = getUserFromSession(req);
if (!user || !mayJoin(user, channel_name)) return res.sendStatus(403);
res.json(
await bird.realtime.authorizeChannel({
connectionId: connection_id,
channelName: channel_name,
}),
);
});@app.post("/bird/auth")
def bird_auth():
body = request.get_json()
user = get_user_from_session()
if user is None or not may_join(user, body["channel_name"]):
abort(403)
return client.realtime.authorize_channel(
connection_id=body["connection_id"],
channel_name=body["channel_name"],
)func birdAuth(w http.ResponseWriter, r *http.Request) {
var body struct {
ConnectionID string `json:"connection_id"`
ChannelName string `json:"channel_name"`
}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
user, ok := userFromSession(r)
if !ok || !mayJoin(user, body.ChannelName) {
http.Error(w, "forbidden", http.StatusForbidden)
return
}
auth, err := client.Realtime.AuthorizeChannel(bird.RealtimeChannelAuthorizationParams{
ConnectionID: body.ConnectionID,
ChannelName: body.ChannelName,
})
if err != nil {
http.Error(w, "authorization failed", http.StatusInternalServerError)
return
}
json.NewEncoder(w).Encode(auth)
}function birdAuth(string $connectionId, string $channelName, User $user): array
{
if (!mayJoin($user, $channelName)) {
http_response_code(403);
exit;
}
return $bird->realtime->authorizeChannel($connectionId, $channelName);
}O SDK deriva um shared_secret separado para cada canal. A autorização para private-encrypted-orders, portanto, não descriptografa private-encrypted-invoices. O segredo trafega na sua resposta de autorização e não é incluído no frame de inscrição enviado ao edge.
Inscrever-se e descriptografar no navegador
O cifrador usa o ponto de entrada @messagebird/realtime/encrypted separado. Importe-o e passe-o como a opção encryption do cliente:
Exemplo de código
import { BirdRealtime } from "@messagebird/realtime";
import { encryption } from "@messagebird/realtime/encrypted";
const bird = new BirdRealtime({
appKey: "your-app-key",
region: "us1",
authEndpoint: "/bird/auth",
encryption,
});
const orders = bird.subscribe("private-encrypted-orders");
orders.bind("order.updated", (data) => {
console.log(data); // decrypted: { order_id: "ord_123", status: "shipped" }
});Os bindings recebem texto plano. Inscrever-se sem a opção encryption lança um erro imediatamente, e uma resposta de autorização sem shared_secret falha na inscrição.
Apenas o cliente de navegador recebe canais criptografados atualmente. Os clientes Swift e Kotlin rejeitam inscrições private-encrypted- porque não implementam a descriptografia.
Rotacionar a chave mestra
Implante a nova chave em todos os publicadores e endpoints de autorização ao mesmo tempo. Durante a rotação:
- Novas publicações selam sob a nova chave.
- Um cliente de navegador inscrito que não conseguir descriptografar um evento se reautoriza uma vez e obtém o novo shared_secret.
- Instâncias usando chaves mestras diferentes podem publicar brevemente eventos que alguns clientes não conseguem descriptografar; coordene o rollout entre as instâncias.
Rotacione uma chave vazada ou perdida. A rotação protege payloads futuros, mas não consegue selar novamente eventos anteriores nem revogar cópias da chave antiga.
O que canais criptografados não fazem
- Clientes oficiais não suportam eventos de cliente. O trigger() do navegador lança um erro em canais criptografados porque o cliente não sela payloads de cliente para cliente. Não envie eventos de cliente em texto plano a partir de um cliente customizado.
- Presença e criptografia não podem ser combinadas. O prefixo presence-encrypted- não é suportado. Cache e criptografia funcionam juntos: canais private-encrypted-cache- armazenam o evento em cache selado, mas após uma rotação de chave a cópia em cache permanece selada sob a chave antiga até que a próxima publicação a substitua.
- Nomes de canal e nomes de evento não são criptografados. Apenas o payload é. Escolha nomes de canal que não revelem o que você está protegendo.
- O edge do Realtime não consegue inspecionar payloads. Nomes de canal e de evento permanecem visíveis, enquanto o payload permanece criptografado.
Próximos passos
- Autorização de canais é o mecanismo de assinatura sobre o qual este guia se baseia.
- Publicação de eventos cobre as próprias APIs de publicação e batch.
- Canais de cache explica o replay do último evento que private-encrypted-cache- combina.
Recursos relacionados
Continue com a documentação, guias e exemplos sobre este tópico. Os recursos estão em inglês.
Explore a funcionalidadeRealtimeSiga o percurso de aprendizagemBuild your first integrationGuia de implementaçãoSend your first realtime event
Experimente na prática e obtenha um resumo de implementação