Canali crittografati
Un canale il cui nome inizia con private-encrypted- è crittografato end-to-end. Il tuo server cifra ogni payload prima di pubblicarlo, e i client browser autorizzati lo decifrano con una chiave ottenuta dal tuo endpoint di autorizzazione. L'edge Realtime e gli intermediari di rete vedono solo testo cifrato.
Genera e conserva una master key di 32 byte. La master key non compare mai in una richiesta Realtime API, e il prefisso nel nome del canale attiva la funzionalità. Bird non può recuperare una chiave persa, e i payload cifrati con quella chiave restano illeggibili dopo la sostituzione.
I canali crittografati usano lo stesso endpoint e la stessa firma dei canali privati. La risposta di autorizzazione include anche la chiave di decifratura derivata del canale come shared_secret. Rifiutare una sottoscrizione impedisce al client di ricevere la chiave.
Generare una master key
Genera 32 byte casuali, codificali in base64 e conserva il valore come l'app secret:
Esempio di codice
openssl rand -base64 32Passalo al tuo server SDK come parte della configurazione realtime, accanto all'app key e al secret.
Pubblicare un evento crittografato
Il server SDK rileva il prefisso del canale, deriva la chiave dalla master key e cifra il payload JSON localmente. La richiesta di pubblicazione contiene l'envelope cifrato.
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']));Un canale crittografato deve essere l'unico canale in una singola pubblicazione. Ogni canale crittografato deriva una chiave diversa, quindi gli altri canali non potrebbero decifrare lo stesso payload cifrato. Gli SDK rifiutano questo fan-out localmente, e il API restituisce E23000 se ne riceve uno. Per pubblicare su più canali crittografati, usa un batch con un canale per evento.
Restituire il shared secret dal tuo endpoint di autenticazione
Il tuo endpoint di autenticazione approva le sottoscrizioni crittografate come approva quelle private. Usa l'helper authorizeChannel di SDK e la risposta ottiene il shared_secret automaticamente ogni volta che il nome del canale porta il prefisso encrypted:
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);
}SDK deriva un shared_secret separato per ogni canale. L'autorizzazione per private-encrypted-orders quindi non decifra private-encrypted-invoices. Il secret viaggia nella tua risposta di autorizzazione e non è incluso nel frame di sottoscrizione inviato all'edge.
Sottoscrivere e decifrare nel browser
Il cifrario usa l'entry point separato @messagebird/realtime/encrypted. Importalo e passalo come opzione encryption del client:
Esempio di codice
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" }
});I binding ricevono testo in chiaro. Sottoscrivere senza l'opzione encryption genera immediatamente un errore, e una risposta di autorizzazione senza shared_secret fa fallire la sottoscrizione.
Solo il client browser attualmente riceve canali crittografati. I client Swift e Kotlin rifiutano le sottoscrizioni private-encrypted- perché non implementano la decifratura.
Ruotare la master key
Distribuisci la nuova chiave a tutti i publisher e gli endpoint di autorizzazione contemporaneamente. Durante la rotazione:
- Le nuove pubblicazioni cifrano con la nuova chiave.
- Un client browser sottoscritto che non riesce a decifrare un evento si ri-autorizza una volta e recupera il nuovo shared_secret.
- Istanze che usano master key diverse possono pubblicare brevemente eventi che alcuni client non riescono a decifrare: coordina il rollout tra le istanze.
Ruota una chiave compromessa o persa. La rotazione protegge i payload futuri ma non può ricifrare eventi precedenti né revocare copie della vecchia chiave.
Cosa non fanno i canali crittografati
- I client ufficiali non supportano i client event. Il browser trigger() genera un errore sui canali crittografati perché il client non cifra i payload client-to-client. Non inviare client event in chiaro da un client personalizzato.
- Presence e crittografia non possono essere combinati. Il prefisso presence-encrypted- non è supportato. Cache e crittografia funzionano insieme: i canali private-encrypted-cache- memorizzano l'evento in cache cifrato, anche se dopo una rotazione della chiave la copia in cache resta cifrata con la vecchia chiave finché la pubblicazione successiva non la sostituisce.
- I nomi dei canali e i nomi degli eventi non sono crittografati. Solo il payload lo è. Scegli nomi di canale che non rivelino ciò che stai proteggendo.
- L'edge Realtime non può ispezionare i payload. I nomi dei canali e degli eventi restano visibili, mentre il payload resta crittografato.
Prossimi passi
- Autorizzazione dei canali è il meccanismo di firma su cui si basa questa guida.
- Pubblicazione degli eventi copre le API di pubblicazione e batch.
- Canali cache spiega il replay dell'ultimo evento che private-encrypted-cache- combina.
Risorse correlate
Prosegui con la documentazione, le guide e gli esempi per questo argomento. Le risorse sono in inglese.
Esplora la funzionalitàRealtimeSegui il percorso di apprendimentoBuild your first integrationGuida all'implementazioneSend your first realtime event
Prova l'esercitazione e ottieni un brief di implementazione