Einrichten von Änderungsbenachrichtigungen, die Ressourcendaten enthalten (umfangreiche Benachrichtigungen)
Microsoft Graph ermöglicht Apps das Abonnieren und Empfangen von Benachrichtigungen über Änderungen an Ressourcen, an deren Verwendung sie interessiert sind. Sie können zwar grundlegende Änderungsbenachrichtigungen abonnieren, aber Ressourcen wie Microsoft Teams-Chatnachrichten und Anwesenheitsressourcen unterstützen beispielsweise umfangreiche Benachrichtigungen.
Zu den umfangreichen Benachrichtigungen gehören die geänderten Ressourcendaten, sodass Ihre App Geschäftslogik ausführen kann, ohne einen separaten API-Aufruf ausführen zu müssen, um die geänderte Ressource abzurufen. In diesem Artikel erfahren Sie, wie Sie umfangreiche Benachrichtigungen in Ihrer Anwendung einrichten.
Unterstützte Ressourcen
Umfangreiche Benachrichtigungen sind für die folgenden Ressourcen verfügbar.
Hinweis
Umfangreiche Benachrichtigungen für Abonnements für Endpunkte, die mit einem Sternchen (*) gekennzeichnet sind, sind nur auf dem /beta
Endpunkt verfügbar.
Ressource | Unterstützte Ressourcenpfade | Begrenzungen |
---|---|---|
Outlook-Ereignis | Änderungen an allen Ereignissen im Postfach eines Benutzers: /users/{id}/events |
Erfordert $select , dass nur eine Teilmenge der Eigenschaften in der rich-Benachrichtigung zurückgegeben wird. Weitere Informationen finden Sie unter Ändern von Benachrichtigungen für Outlook-Ressourcen. |
Outlook-Nachricht | Änderungen an allen Nachrichten im Postfach eines Benutzers: /users/{id}/messages Änderungen an Nachrichten im Posteingang eines Benutzers: /users/{id}/mailFolders/{id}/messages |
Erfordert $select , dass nur eine Teilmenge der Eigenschaften in der rich-Benachrichtigung zurückgegeben wird. Weitere Informationen finden Sie unter Ändern von Benachrichtigungen für Outlook-Ressourcen. |
Persönlicher Outlook-Kontakt | Änderungen an allen persönlichen Kontakten im Postfach eines Benutzers: /users/{id}/contacts Änderungen an allen persönlichen Kontakten im contactFolder eines Benutzers: /users/{id}/contactFolders/{id}/contacts |
Erfordert $select , dass nur eine Teilmenge der Eigenschaften in der rich-Benachrichtigung zurückgegeben wird. Weitere Informationen finden Sie unter Ändern von Benachrichtigungen für Outlook-Ressourcen. |
Teams-AnrufAufzeichnung | Alle Aufzeichnungen in einem organization:communications/onlineMeetings/getAllRecordings Alle Aufzeichnungen für eine bestimmte Besprechung: communications/onlineMeetings/{onlineMeetingId}/recordings Eine Anrufaufzeichnung, die in einer Besprechung verfügbar wird, die von einem bestimmten Benutzer organisiert wird: users/{id}/onlineMeetings/getAllRecordings Eine Anrufaufzeichnung, die in einer Besprechung verfügbar wird, in der eine bestimmte Teams-App installiert ist: appCatalogs/teamsApps/{id}/installedToOnlineMeetings/getAllRecordings * |
Maximale Abonnementkontingente: |
Teams callTranscript | Alle Transkripte in einem organization:communications/onlineMeetings/getAllTranscripts Alle Transkripte für eine bestimmte Besprechung: communications/onlineMeetings/{onlineMeetingId}/transcripts Ein Anruftranskript, das in einer Besprechung verfügbar wird, die von einem bestimmten Benutzer organisiert wird: users/{id}/onlineMeetings/getAllTranscripts Ein Anruftranskript, das in einer Besprechung verfügbar wird, in der eine bestimmte Teams-App installiert ist: appCatalogs/teamsApps/{id}/installedToOnlineMeetings/getAllTrancripts * |
Maximale Abonnementkontingente: |
Teams channel | Änderungen an Kanälen in allen Teams: /teams/getAllChannels Änderungen am Kanal in einem bestimmten Team: /teams/{id}/channels |
- |
Teams Chat | Änderungen an chatten im Mandanten: /chats Änderungen an einem bestimmten Chat: /chats/{id} |
- |
Teams chatMessage | Änderungen an Chatnachrichten in allen Kanälen in allen Teams: /teams/getAllMessages Änderungen an Chatnachrichten in einem bestimmten Kanal: /teams/{id}/channels/{id}/messages Änderungen an Chatnachrichten in allen Chats: /chats/getAllMessages Änderungen an Chatnachrichten in einem bestimmten Chat: /chats/{id}/messages Änderungen an Chatnachrichten in allen Chats, zu der ein bestimmter Benutzer gehört: /users/{id}/chats/getAllMessages |
Unterstützt nicht die Verwendung von $select , um nur ausgewählte Eigenschaften zurückzugeben. Die rich-Benachrichtigung besteht aus allen Eigenschaften des geänderten instance. |
Teams conversationMember | Änderungen an der Mitgliedschaft in einem bestimmten Team: /teams/{id}/members Änderungen an der Mitgliedschaft in einem bestimmten Chat: /chats/{id}/members |
- |
Teams onlineMeeting * | Änderungen an einer Onlinebesprechung: /communications/onlineMeetings(joinWebUrl='{encodedJoinWebUrl}')/meetingCallEvents * |
Unterstützt nicht die Verwendung von $select , um nur ausgewählte Eigenschaften zurückzugeben. Die rich-Benachrichtigung besteht aus allen Eigenschaften des geänderten instance. Pro Anwendung und Onlinebesprechung ist ein Abonnement zulässig. Weitere Informationen finden Sie unter Abrufen von Änderungsbenachrichtigungen für Aktualisierungen von Microsoft Teams-Besprechungsanrufereignissen. |
Teams-Anwesenheit | Änderungen an der Anwesenheit eines einzelnen Benutzers: /communications/presences/{id} Änderungen an der Anwesenheit mehrerer Benutzer: /communications/presences?$filter=id in ({id},{id}...) |
Das Abonnement für die Anwesenheit mehrerer Benutzer ist auf 650 verschiedene Benutzer beschränkt. Unterstützt nicht die Verwendung von $select , um nur ausgewählte Eigenschaften zurückzugeben. Die rich-Benachrichtigung besteht aus allen Eigenschaften des geänderten instance. Pro Anwendung und delegiertem Benutzer ist ein Abonnement zulässig. Weitere Informationen finden Sie unter Abrufen von Änderungsbenachrichtigungen für Anwesenheitsupdates in Microsoft Teams. |
Teams team | Änderungen an einem Team im Mandanten: /teams Änderungen an einem bestimmten Team: /teams/{id} |
- |
Ressourcendaten in Benachrichtigungs-Nutzlast
Umfangreiche Benachrichtigungen enthalten die folgenden Ressourcendaten in der Nutzlast:
- Die ID und der Typ der geänderten Ressourceninstanz, die in der Eigenschaft resourceData zurückgegeben werden.
- Alle Eigenschaftswerte dieser Ressourceninstanz, die wie im Abonnement angegeben verschlüsselt sind, werden in der Eigenschaft encryptedContent zurückgegeben.
- Oder je nach Ressource bestimmte Eigenschaften, die in der Eigenschaft resourceData zurückgegeben werden. Um nur bestimmte Eigenschaften abzurufen, geben Sie diese mithilfe eines
$select
Parameters als Teil der Ressourcen-URL im Abonnement an.
Erstellen eines Abonnements
Umfangreiche Benachrichtigungen werden auf die gleiche Weise wie grundlegende Änderungsbenachrichtigungen eingerichtet, mit der Ausnahme, dass Sie die folgenden Eigenschaften angeben müssen :
-
includeResourceData, das auf
true
gesetzt werden sollte, um Ressourcendaten explizit anzufordern. - encryptionCertificate , das nur den öffentlichen Schlüssel enthält, den Microsoft Graph zum Verschlüsseln der Ressourcendaten verwendet, die an Ihre App zurückgegeben werden. Aus Sicherheitsgründen verschlüsselt Microsoft Graph die Ressourcendaten, die in einer umfassenden Benachrichtigung zurückgegeben werden. Sie müssen beim Erstellen des Abonnements einen öffentlichen Verschlüsselungsschlüssel angeben. Weitere Informationen zum Erstellen und Verwalten von Verschlüsselungsschlüsseln finden Sie unter Entschlüsseln von Ressourcendaten aus Änderungsbenachrichtigungen.
- encryptionCertificateId, ist Ihre eigene Kennung für das Zertifikat. Verwenden Sie diese ID, um in jeder Änderungsbenachrichtigung zu ermitteln, welches Zertifikat für die Entschlüsselung verwendet werden soll.
Sie müssen auch beide Endpunkte überprüfen, wie unter Überprüfung des Benachrichtigungsendpunkts beschrieben. Wenn Sie die gleiche URL für beide Endpunkte verwenden, erhalten Sie und sollten auf zwei Validierungsanforderungen antworten.
Beispiel für eine Abonnementanfrage
Das folgende Beispiel abonniert Kanalnachrichten, die in Microsoft Teams erstellt oder aktualisiert werden.
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl": "https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/{id}/channels/{id}/messages",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
Abonnementantwort
HTTP/1.1 201 Created
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl": "https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/{id}/channels/{id}/messages",
"includeResourceData": true,
"encryptionCertificateId": "{custom ID}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secret client state}"
}
Benachrichtigungen zum Abonnementlebenszyklus
Bestimmte Ereignisse können den normalen Fluss von Änderungsbenachrichtigungen in einem vorhandenen Abonnement beeinträchtigen. Benachrichtigungen zum Abonnementlebenszyklus informieren Sie über Maßnahmen, die zur Aufrechterhaltung eines unterbrechungsfreien Flusses erforderlich sind. Im Gegensatz zu einer Ressourcenänderungsbenachrichtigung, die eine Änderung an einer Ressource instance informiert, bezieht sich eine Lebenszyklusbenachrichtigung auf das Abonnement selbst und seinen aktuellen Status im Lebenszyklus.
Weitere Informationen zum Empfangen und Reagieren auf Lebenszyklusbenachrichtigungen finden Sie unter Reduzieren fehlender Abonnements und Änderungsbenachrichtigungen.
Überprüfung der Echtheit von Benachrichtigungen
Bevor Sie Geschäftslogik basierend auf Ressourcendaten ausführen, die in Änderungsbenachrichtigungen enthalten sind, müssen Sie zunächst die Authentizität jeder Änderungsbenachrichtigung überprüfen. Andernfalls kann ein Drittanbieter Ihre App mit falschen Änderungsbenachrichtigungen spoofen und dazu bringen, dass ihre Geschäftslogik falsch ausgeführt wird, was zu einem Sicherheitsvorfall führen kann.
Für grundlegende Änderungsbenachrichtigungen, die keine Ressourcendaten enthalten, überprüfen Sie diese einfach basierend auf dem ClientState-Wert , wie unter Verarbeiten der Änderungsbenachrichtigung beschrieben. Diese Überprüfung ist akzeptabel, da Sie nachfolgende vertrauenswürdige Microsoft Graph-Aufrufe durchführen können, um Zugriff auf Ressourcendaten zu erhalten, sodass die Auswirkungen von Spoofingversuchen begrenzt sind.
Führen Sie für umfangreiche Benachrichtigungen eine gründlichere Überprüfung durch, bevor Sie die Daten verarbeiten.
In diesem Abschnitt untersuchen Sie die folgenden Validierungskonzepte:
Überprüfungstoken in der Änderungsbenachrichtigung
Eine Änderungsbenachrichtigung mit Ressourcendaten enthält die zusätzliche Eigenschaft validationTokens, die ein Array von JSON-Webtoken (JWT) enthält, das von Microsoft Graph generiert wird. Microsoft Graph generiert ein einzelnes Token für jedes unterschiedliche App- und Mandantenpaar, für das ein Element im Wertarray vorhanden ist. Beachten Sie, dass Änderungsbenachrichtigungen eine Mischung aus Elementen für verschiedene Apps und Mandanten enthalten können, die mit derselben notificationUrl abonniert haben.
Hinweis
Microsoft Graph sendet keine Validierungstoken für Änderungsbenachrichtigungen, die über Azure Event Hubs übermittelt werden, da der Abonnementdienst die notificationUrl für Event Hubs nicht überprüfen muss.
Im folgenden Beispiel enthält die Änderungsbenachrichtigung zwei Elemente für dieselbe App und für zwei verschiedene Mandanten. Daher enthält das validationTokens-Array zwei Token, die validiert werden müssen.
{
"value": [
{
"subscriptionId": "76619225-ff6b-4489-96ca-4ef547e78b22",
"tenantId": "aaaabbbb-0000-cccc-1111-dddd2222eeee",
"changeType": "created",
...
},
{
"subscriptionId": "5cfe2387-163c-4006-81bb-1b5e1e060afe",
"tenantId": "bbbbcccc-1111-dddd-2222-eeee3333ffff",
"changeType": "created",
...
}
],
"validationTokens": [
"eyJ0eXAiOiJKV1QiLCJhb...",
"cGlkYWNyIjoiMiIsImlkc..."
]
}
Das Änderungsbenachrichtigungsobjekt befindet sich in der Struktur des Ressourcentyps changeNotificationCollection.
So führen Sie die Validierung durch
Verwenden Sie die Microsoft Authentication Library (MSAL), um die Tokenüberprüfung oder eine Drittanbieterbibliothek für eine andere Plattform zu verarbeiten.
Beachten Sie die folgenden Prinzipien:
- Stellen Sie sicher, dass als Teil der Antwort auf die Änderungsbenachrichtigung immer ein
HTTP 202 Accepted
-Statuscode gesendet wird. - Reagieren Sie, bevor Sie die Änderungsbenachrichtigung überprüfen, auch wenn die Überprüfung später fehlschlägt. Das heißt, Sie erhalten sofort die Änderungsbenachrichtigung, unabhängig davon, ob Sie Benachrichtigungen zur späteren Verarbeitung in Warteschlangen speichern oder sie direkt verarbeiten.
- Das Akzeptieren einer Änderungsbenachrichtigung verhindert unnötige Zustellungswiederholungen und verhindert, dass potenzielle kriminelle Akteure herausfinden, ob sie die Validierung bestanden haben oder nicht. Sie können eine ungültige Änderungsbenachrichtigung jederzeit ignorieren, nachdem Sie sie erhalten haben.
Führen Sie insbesondere die Überprüfung für jedes JWT-Token in der validationTokens-Sammlung aus. Wenn Token fehlschlagen, betrachten Sie die Änderungsbenachrichtigung als verdächtig und untersuchen Sie sie weiter.
Führen Sie die folgenden Schritte aus, um Token und Apps zu validieren, die Token generieren:
Überprüfen Sie, ob das Token nicht abgelaufen ist.
Überprüfen Sie, ob das Token vom Microsoft Identity Platform ausgestellt wurde und dass das Token nicht manipuliert wurde.
- Beziehen Sie die Signaturschlüssel vom gemeinsamen Konfigurationsendpunkt:
https://login.microsoftonline.com/common/.well-known/openid-configuration
Ihre App kann diese Konfiguration für einige Zeit zwischenspeichern. Die Konfiguration wird häufig aktualisiert, da Signaturschlüssel täglich rotiert werden. - Überprüfen Sie die Signatur des JWT-Tokens mit diesen Schlüsseln.
Akzeptieren Sie keine Token, die von einer anderen Autorität ausgestellt wurden.
- Beziehen Sie die Signaturschlüssel vom gemeinsamen Konfigurationsendpunkt:
Überprüfen Sie, ob das Token für Ihre App, die Änderungsbenachrichtigungen abonniert, ausgestellt wurde.
Die folgenden Schritte sind Teil der Standardüberprüfungslogik in JWT-Token-Bibliotheken und können normalerweise als einzelner Funktionsaufruf ausgeführt werden.
- Überprüfen Sie, ob die "Zielgruppe" im Token mit Ihrer App-ID übereinstimmt.
- Wenn mehr als eine App Änderungsbenachrichtigungen erhält, überprüfen Sie, ob mehrere IDs vorhanden sind.
Kritisch: Stellen Sie sicher, dass die App, die das Token generiert hat, den Herausgeber der Microsoft Graph-Änderungsbenachrichtigung darstellt.
- Überprüfen Sie, ob die
azp
Eigenschaft im Token mit dem erwarteten Wert von0bf30f3b-4a52-48df-9a82-234910c4a086
übereinstimmt. - Durch diese Überprüfung wird sichergestellt, dass eine andere App, die nicht Microsoft Graph ist, die Änderungsbenachrichtigungen nicht gesendet hat.
- Überprüfen Sie, ob die
Beispiel für ein JWT-Token
Das folgende Beispiel zeigt die Eigenschaften, die im JWT-Token enthalten sind, die für die Überprüfung benötigt werden.
{
// aud is your app's id
"aud": "925bff9f-f6e2-4a69-b858-f71ea2b9b6d0",
"iss": "https://login.microsoftonline.com/9f4ebab6-520d-49c0-85cc-7b25c78d4a93/v2.0",
"iat": 1624649764,
"nbf": 1624649764,
"exp": 1624736464,
"aio": "E2ZgYGjnuFglnX7mtjJzwR5lYaWvAA==",
// azp represents the notification publisher and must always be the same value of 0bf30f3b-4a52-48df-9a82-234910c4a086
"azp": "0bf30f3b-4a52-48df-9a82-234910c4a086",
"azpacr": "2",
"oid": "1e7d79fa-7893-4d50-bdde-164260d9c5ba",
"rh": "0.AX0AtrpOnw1SwEmFzHslx41KkzsP8wtSSt9ImoIjSRDEoIZ9AAA.",
"sub": "1e7d79fa-7893-4d50-bdde-164260d9c5ba",
"tid": "9f4ebab6-520d-49c0-85cc-7b25c78d4a93",
"uti": "mIB4QKCeZE6hK71XUHJ3AA",
"ver": "2.0"
}
Beispiel: Überprüfen von Überprüfungstoken
// add Microsoft.IdentityModel.Protocols.OpenIdConnect and System.IdentityModel.Tokens.Jwt nuget packages to your project
public async Task<bool> ValidateToken(string token, string tenantId, IEnumerable<string> appIds)
{
var configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(
"https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration",
new OpenIdConnectConfigurationRetriever());
var openIdConfig = await configurationManager.GetConfigurationAsync();
var handler = new JwtSecurityTokenHandler();
try
{
handler.ValidateToken(token, new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
ValidIssuer = $"https://sts.windows.net/{tenantId}/",
ValidAudiences = appIds,
IssuerSigningKeys = openIdConfig.SigningKeys
}, out _);
return true;
}
catch (Exception ex)
{
Trace.TraceError($"{ex.Message}:{ex.StackTrace}");
return false;
}
}
Entschlüsseln von Ressourcendaten aus Änderungsbenachrichtigungen
Die resourceData-Eigenschaft einer Änderungsbenachrichtigung enthält nur die grundlegenden ID- und Typinformationen einer Ressourceninstanz. Die Eigenschaft encryptedData enthält die vollständigen Ressourcendaten, die von Microsoft Graph mit dem im Abonnement angegebenen öffentlichen Schlüssel verschlüsselt wurden. Die Eigenschaft enthält auch Werte, die für die Überprüfung und Entschlüsselung erforderlich sind. Diese Verschlüsselung wird durchgeführt, um die Sicherheit von Kundendaten zu erhöhen, auf die über Änderungsbenachrichtigungen zugegriffen wird. Es liegt in Ihrer Verantwortung, den privaten Schlüssel zu schützen, um sicherzustellen, dass ein Dritter die Kundendaten nicht entschlüsseln kann, auch wenn er es schafft, die ursprünglichen Änderungsbenachrichtigungen abzufangen.
In diesem Abschnitt lernen Sie die folgenden Konzepte kennen:
- Verwalten von Verschlüsselungsschlüsseln
- Entschlüsseln von Ressourcendaten
- Beispiel: Entschlüsseln einer Benachrichtigung mit verschlüsselten Ressourcendaten
Verwalten von Verschlüsselungsschlüsseln
Beziehen Sie ein Zertifikat mit einem Paar asymmetrischer Schlüssel.
Sie können ein selbstsigniertes Zertifikat verwenden, da Microsoft Graph den Zertifikataussteller nicht überprüft und den öffentlichen Schlüssel nur für die Verschlüsselung verwendet.
Verwenden Sie Azure Key Vault, um Zertifikate zu erstellen, zu rotieren und sicher zu verwalten. Stellen Sie sicher, dass die Schlüssel die folgenden Kriterien erfüllen:
- Der Schlüssel muss vom Typ
RSA
sein. - Die Schlüsselgröße muss zwischen 2.048 Bit und 4.096 Bits sein.
- Der Schlüssel muss vom Typ
Exportieren Sie das Zertifikat im Base64-codierten X.509-Format, und schließen Sie nur den öffentlichen Schlüssel ein.
Beim Erstellen eines Abonnements:
Geben Sie das Zertifikat in der encryptionCertificate-Eigenschaft an, indem Sie den Base64-codierten Inhalt verwenden, in den das Zertifikat exportiert wurde.
Geben Sie Ihre eigene Kennung in der Eigenschaft encryptionCertificateId an.
Mit dieser Kennung können Sie Ihre Zertifikate mit den empfangenen Änderungsbenachrichtigungen abgleichen und Zertifikate aus Ihrem Zertifikatspeicher abrufen. Die Kennung darf bis zu 128 Zeichen umfassen.
Verwalten Sie den privaten Schlüssel sicher, sodass Ihr Verarbeitungscode für Änderungsbenachrichtigungen auf den privaten Schlüssel zugreifen kann, um Ressourcendaten zu entschlüsseln.
Rotierende Schlüssel
Ändern Sie Ihre asymmetrischen Schlüssel regelmäßig, um das Risiko einer Gefährdung eines privaten Schlüssels zu minimieren. Befolgen Sie diese Schritte, um ein neues Schlüsselpaar einzuführen:
Beziehen Sie ein neues Zertifikat mit einem neuen Paar asymmetrischer Schlüssel. Verwenden Sie es für alle neuen Abonnements, die erstellt werden.
Aktualisieren Sie vorhandene Abonnements mit dem neuen Zertifikatschlüssel.
- Machen Sie dieses Update als Teil der regulären Abonnementverlängerung.
- Oder listen Sie alle Abonnements auf und geben Sie den Schlüssel an. Verwenden Sie den Patch-Vorgang für das Abonnement, und aktualisieren Sie die encryptionCertificate- und encryptionCertificateId-Eigenschaften.
Beachten Sie die folgenden Prinzipien:
- Für einige Zeit kann das alte Zertifikat noch für die Verschlüsselung verwendet werden. Ihre App muss sowohl auf alte als auch auf neue Zertifikate zugreifen können, um Inhalte entschlüsseln zu können.
- Verwenden Sie die encryptionCertificateId-Eigenschaft in jeder Änderungsbenachrichtigung, um den zu verwendenden richtigen Schlüssel zu identifizieren.
- Verwerfen des alten Zertifikats nur, wenn keine aktuellen Änderungsbenachrichtigungen angezeigt werden, die darauf verweisen.
Entschlüsseln von Ressourcendaten
Um die Leistung zu optimieren, verwendet Microsoft Graph einen zweistufigen Verschlüsselungsprozess:
- Es generiert einen symmetrischen Single-Use-Schlüssel und verwendet ihn zum Verschlüsseln von Ressourcendaten.
- Es verwendet den öffentlichen asymmetrischen Schlüssel (den Sie beim Abonnieren angegeben haben), um den symmetrischen Schlüssel zu verschlüsseln, und bezieht ihn in jede Änderungsbenachrichtigung über dieses Abonnement ein.
Nehmen Sie immer an, dass der symmetrische Schlüssel für jedes Element in der Änderungsbenachrichtigung unterschiedlich ist.
Um Ressourcendaten zu entschlüsseln, sollte Ihre App die umgekehrten Schritte ausführen und die Eigenschaften unter encryptedContent in jeder Änderungsbenachrichtigung verwenden:
Verwenden Sie die Eigenschaft encryptionCertificateId um das zu verwendende Zertifikat zu identifizieren.
Initialisieren Sie eine RSA-Kryptografiekomponente mit dem privaten Schlüssel. Eine einfache Möglichkeit zum Initialisieren einer RSA-Komponente besteht darin, die RSACertificateExtensions.GetRSAPrivateKey(X509Certificate2)-Methode mit einem X509Certificate2-instance zu verwenden, der den unter Verwalten von Verschlüsselungsschlüsseln beschriebenen privaten Schlüssel enthält.
Entschlüsseln Sie den symmetrischen Schlüssel, der in der Eigenschaft dataKey jedes Elements in der Änderungsbenachrichtigung bereitgestellt wird.
Verwenden Sie Optimal Asymmetric Encryption Padding (OAEP) für den Entschlüsselungsalgorithmus.
Verwenden Sie den symmetrischen Schlüssel, um die HMAC-SHA256-Signatur des Werts in Daten zu berechnen.
Vergleichen Sie es mit dem Wert in dataSignature. Wenn sie nicht übereinstimmen, gehen Sie davon aus, dass die Nutzlast manipuliert ist, und entschlüsseln Sie sie nicht.
Verwenden Sie den symmetrischen Schlüssel mit einem Advanced Encryption Standard (AES) (z. B. .NET Aes), um den Inhalt der Daten zu entschlüsseln.
Verwenden Sie die folgenden Entschlüsselungsparameter für den AES-Algorithmus:
- Padding: PKCS7
- Cipher-Modus: CBC
Stellen Sie den "Initialisierungsvektor" ein, indem Sie die ersten 16 Bytes des zur Entschlüsselung verwendeten symmetrischen Schlüssels kopieren.
Der entschlüsselte Wert ist eine JSON-Zeichenfolge, die die Ressourceninstanz in der Änderungsbenachrichtigung darstellt.
Beispiel: Entschlüsseln einer Benachrichtigung mit verschlüsselten Ressourcendaten
Das folgende JSON-Beispiel zeigt eine Änderungsbenachrichtigung, die verschlüsselte Eigenschaftswerte einer chatMessage-instance in einer Kanalnachricht enthält. Der @odata.id
Wert gibt die instance an.
{
"value": [
{
"subscriptionId": "76222963-cc7b-42d2-882d-8aaa69cb2ba3",
"changeType": "created",
// Other properties typical in a resource change notification
"resource": "teams('d29828b8-c04d-4e2a-b2f6-07da6982f0f0')/channels('19:f127a8c55ad949d1a238464d22f0f99e@thread.skype')/messages('1565045424600')/replies('1565047490246')",
"resourceData": {
"id": "1565293727947",
"@odata.type": "#Microsoft.Graph.ChatMessage",
"@odata.id": "teams('88cbc8fc-164b-44f0-b6a6-b59b4a1559d3')/channels('19:8d9da062ec7647d4bb1976126e788b47@thread.tacv2')/messages('1565293727947')/replies('1565293727947')"
},
"encryptedContent": {
"data": "{encrypted data that produces a full resource}",
"dataSignature": "<HMAC-SHA256 hash>",
"dataKey": "{encrypted symmetric key from Microsoft Graph}",
"encryptionCertificateId": "MySelfSignedCert/DDC9651A-D7BC-4D74-86BC-A8923584B0AB",
"encryptionCertificateThumbprint": "07293748CC064953A3052FB978C735FB89E61C3D"
}
}
],
"validationTokens": [
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSU..."
]
}
Eine vollständige Beschreibung der Daten, die beim Senden von Änderungsbenachrichtigungen gesendet werden, finden Sie unter changeNotificationCollection-Ressourcentyp.
Entschlüsseln des symmetrischen Schlüssels
Dieser Abschnitt enthält einige nützliche Codefragmente, die C# und .NET für jede Entschlüsselungsstufe verwenden.
// Initialize with the private key that matches the encryptionCertificateId.
X509Certificate2 certificate = <instance of X509Certificate2 matching the encryptionCertificateId property>;
RSA rsa = certificate.GetRSAPrivateKey();
byte[] encryptedSymmetricKey = Convert.FromBase64String(<value from dataKey property>);
// Decrypt using OAEP padding.
byte[] decryptedSymmetricKey = rsa.Decrypt(encryptedSymmetricKey, fOAEP: true);
// Can now use decryptedSymmetricKey with the AES algorithm.
Vergleichen von Datensignaturen mit HMAC-SHA256
byte[] decryptedSymmetricKey = <the aes key decrypted in the previous step>;
byte[] encryptedPayload = <the value from the data property, still encrypted>;
byte[] expectedSignature = <the value from the dataSignature property>;
byte[] actualSignature;
using (HMACSHA256 hmac = new HMACSHA256(decryptedSymmetricKey))
{
actualSignature = hmac.ComputeHash(encryptedPayload);
}
if (actualSignature.SequenceEqual(expectedSignature))
{
// Continue with decryption of the encryptedPayload.
}
else
{
// Do not attempt to decrypt encryptedPayload. Assume notification payload has been tampered with and investigate.
}
Entschlüsseln des Inhalts der Ressourcendaten
Aes aesProvider = Aes.Create();
aesProvider.Key = decryptedSymmetricKey;
aesProvider.Padding = PaddingMode.PKCS7;
aesProvider.Mode = CipherMode.CBC;
// Obtain the initialization vector from the symmetric key itself.
int vectorSize = 16;
byte[] iv = new byte[vectorSize];
Array.Copy(decryptedSymmetricKey, iv, vectorSize);
aesProvider.IV = iv;
byte[] encryptedPayload = Convert.FromBase64String(<value from data property>);
string decryptedResourceData;
// Decrypt the resource data content.
using (var decryptor = aesProvider.CreateDecryptor())
{
using (MemoryStream msDecrypt = new MemoryStream(encryptedPayload))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
decryptedResourceData = srDecrypt.ReadToEnd();
}
}
}
}
// decryptedResourceData now contains a JSON string that represents the resource.