Pseudonymisierung

Übersicht über das Konzept

Pseudonymisierung (auch bekannt als Tokenisierung) ist eine De-Identifikationstechnik, bei der sensible Daten einheitlich durch Ersatzwerte (auch als Tokens bezeichnet) ersetzt werden. Dies steht im Gegensatz zu anderen De-Identifikationstechniken, wie zum Beispiel dem Entfernen oder der Generalisierung, da die Ersatzwerte ihre referentiellen Eigenschaften innerhalb des de-identifizierten Datensatzes beibehalten. Darüber hinaus können diese Ersatzwerte, abhängig davon, welche Transformation zu ihrer Erzeugung verwendet wird, von einem autorisierten Nutzer in ihre ursprünglichen sensiblen Werte zurückversetzt werden.

Transformationsbeispiel

Betrachten wir das folgende Beispiel, um den Nutzen der Pseudonymisierung zu verstehen.

Angenommen, wir haben die folgenden Daten:

Mitarbeiter-ID Datum Vergütung
11111 2015 10 $
11111 2016 20 $
22222 2016 15 $

Vielleicht möchten wir wissen, wie sich die Mitarbeitervergütung im Laufe der Zeit verändert hat, um Mitarbeiter zu identifizieren, die Ausreißer sind. Wenn wir einen Ausreißer finden, möchten wir die Einkommensunterschiede korrigieren. Außerdem möchten wir dies tun, ohne die vertraulichen Vergütungsdaten von Personen preiszugeben.

Wenn die einzige Möglichkeit der Identifikation einer Person die "Mitarbeiter-ID" ist, muss die entsprechende Spalte de-identifiziert werden.

Wir können dann eine Pseudonymisierungstransformation auf "Mitarbeiter-ID" anwenden. Beachten Sie zwei Optionen für Pseudonymisierungstransformationen: CryptoHashConfig und CryptoReplaceFfxFpeConfig. Da wir den eigentlichen Mitarbeiter, der ein Ausreißer ist, entdecken möchten, benötigen wir eine umkehrbare Transformation. Das beschränkt unsere Auswahl auf CryptoReplaceFfxFpeConfig.

Als Nächstes konfigurieren wir die Transformation:

"cryptoReplaceFfxFpeConfig": {
  "cryptoKey": {
    "unwrapped": {
      "key": "YWJjZGVmZ2hpamtsbW5vcA=="
    }
  },
  "commonAlphabet": "NUMERIC"
}

So wenden wir diese Transformation über die Methode content.deidentify auf "Mitarbeiter-ID" an:

Protokoll

JSON-Eingabe:

POST https://dlp.googleapis.com/v2/projects/[PROJECT_ID]/content:deidentify?key={YOUR_API_KEY}

{
  "deidentifyConfig":{
    "recordTransformations":{
      "fieldTransformations":[
        {
          "primitiveTransformation":{
            "cryptoReplaceFfxFpeConfig":{
              "cryptoKey":{
                "unwrapped":{
                  "key":"YWJjZGVmZ2hpamtsbW5vcA=="
                }
              },
              "commonAlphabet":"NUMERIC"
            }
          },
          "fields":[
            {
              "name":"Employee ID"
            }
          ]
        }
      ]
    }
  },
  "item":{
    "table":{
      "headers":[
        {
          "name":"Employee ID"
        },
        {
          "name":"Date"
        },
        {
          "name":"Compensation"
        }
      ],
      "rows":[
        {
          "values":[
            {
              "stringValue":"11111"
            },
            {
              "stringValue":"2015"
            },
            {
              "stringValue":"$10"
            }
          ]
        },
        {
          "values":[
            {
              "stringValue":"11111"
            },
            {
              "stringValue":"2016"
            },
            {
              "stringValue":"$20"
            }
          ]
        },
        {
          "values":[
            {
              "stringValue":"22222"
            },
            {
              "stringValue":"2016"
            },
            {
              "stringValue":"$15"
            }
          ]
        }
      ]
    }
  }
}

JSON-Ausgabe:

{
  "item":{
    "table":{
      "headers":[
        {
          "name":"Employee ID"
        },
        {
          "name":"Date"
        },
        {
          "name":"Compensation"
        }
      ],
      "rows":[
        {
          "values":[
            {
              "stringValue":"28777"
            },
            {
              "stringValue":"2015"
            },
            {
              "stringValue":"$10"
            }
          ]
        },
        {
          "values":[
            {
              "stringValue":"28777"
            },
            {
              "stringValue":"2016"
            },
            {
              "stringValue":"$20"
            }
          ]
        },
        {
          "values":[
            {
              "stringValue":"39344"
            },
            {
              "stringValue":"2016"
            },
            {
              "stringValue":"$15"
            }
          ]
        }
      ]
    }
  },
  "overview":{
    "transformedBytes":"15",
    "transformationSummaries":[
      {
        "field":{
          "name":"Employee ID"
        },
        "results":[
          {
            "count":"3",
            "code":"SUCCESS"
          }
        ],
        "fieldTransformations":[
          {
            "fields":[
              {
                "name":"Employee ID"
              }
            ],
            "primitiveTransformation":{
              "cryptoReplaceFfxFpeConfig":{
                "cryptoKey":{
                  "unwrapped":{
                    "key":"YWJjZGVmZ2hpamtsbW5vcA=="
                  }
                },
                "commonAlphabet":"NUMERIC"
              }
            }
          }
        ],
        "transformedBytes":"15"
      }
    ]
  }
}

Java


import com.google.cloud.dlp.v2.DlpServiceClient;
import com.google.common.io.BaseEncoding;
import com.google.privacy.dlp.v2.ContentItem;
import com.google.privacy.dlp.v2.CryptoKey;
import com.google.privacy.dlp.v2.CryptoReplaceFfxFpeConfig;
import com.google.privacy.dlp.v2.CryptoReplaceFfxFpeConfig.FfxCommonNativeAlphabet;
import com.google.privacy.dlp.v2.DeidentifyConfig;
import com.google.privacy.dlp.v2.DeidentifyContentRequest;
import com.google.privacy.dlp.v2.DeidentifyContentResponse;
import com.google.privacy.dlp.v2.FieldId;
import com.google.privacy.dlp.v2.FieldTransformation;
import com.google.privacy.dlp.v2.InfoType;
import com.google.privacy.dlp.v2.InfoTypeTransformations;
import com.google.privacy.dlp.v2.InfoTypeTransformations.InfoTypeTransformation;
import com.google.privacy.dlp.v2.InspectConfig;
import com.google.privacy.dlp.v2.KmsWrappedCryptoKey;
import com.google.privacy.dlp.v2.LocationName;
import com.google.privacy.dlp.v2.PrimitiveTransformation;
import com.google.privacy.dlp.v2.RecordTransformations;
import com.google.privacy.dlp.v2.Table;
import com.google.privacy.dlp.v2.Table.Row;
import com.google.privacy.dlp.v2.Value;
import com.google.protobuf.ByteString;
import java.io.IOException;
import java.util.Arrays;

public class DeIdentifyTableWithFpe {

  public static void main(String[] args) throws Exception {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "your-project-id";
    String kmsKeyName =
        "projects/YOUR_PROJECT/"
            + "locations/YOUR_KEYRING_REGION/"
            + "keyRings/YOUR_KEYRING_NAME/"
            + "cryptoKeys/YOUR_KEY_NAME";
    String wrappedAesKey = "YOUR_ENCRYPTED_AES_256_KEY";
    Table tableToDeIdentify = Table.newBuilder()
        .addHeaders(FieldId.newBuilder().setName("Employee ID").build())
        .addHeaders(FieldId.newBuilder().setName("Date").build())
        .addHeaders(FieldId.newBuilder().setName("Compensation").build())
        .addRows(Row.newBuilder()
            .addValues(Value.newBuilder().setStringValue("11111").build())
            .addValues(Value.newBuilder().setStringValue("2015").build())
            .addValues(Value.newBuilder().setStringValue("$10").build())
            .build())
        .addRows(Row.newBuilder()
            .addValues(Value.newBuilder().setStringValue("11111").build())
            .addValues(Value.newBuilder().setStringValue("2016").build())
            .addValues(Value.newBuilder().setStringValue("$20").build())
            .build())
        .addRows(Row.newBuilder()
            .addValues(Value.newBuilder().setStringValue("22222").build())
            .addValues(Value.newBuilder().setStringValue("2016").build())
            .addValues(Value.newBuilder().setStringValue("$15").build())
            .build())
        .build();
    deIdentifyTableWithFpe(projectId, tableToDeIdentify, kmsKeyName, wrappedAesKey);
  }

  public static void deIdentifyTableWithFpe(
      String projectId, Table tableToDeIdentify, String kmsKeyName, String wrappedAesKey)
      throws IOException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests. After completing all of your requests, call
    // the "close" method on the client to safely clean up any remaining background resources.
    try (DlpServiceClient dlp = DlpServiceClient.create()) {
      // Specify what content you want the service to de-identify.
      ContentItem contentItem = ContentItem.newBuilder().setTable(tableToDeIdentify).build();

      // Specify an encrypted AES-256 key and the name of the Cloud KMS key that encrypted it
      KmsWrappedCryptoKey kmsWrappedCryptoKey =
          KmsWrappedCryptoKey.newBuilder()
              .setWrappedKey(ByteString.copyFrom(BaseEncoding.base64().decode(wrappedAesKey)))
              .setCryptoKeyName(kmsKeyName)
              .build();
      CryptoKey cryptoKey = CryptoKey.newBuilder().setKmsWrapped(kmsWrappedCryptoKey).build();

      // Specify how the content should be encrypted.
      CryptoReplaceFfxFpeConfig cryptoReplaceFfxFpeConfig =
          CryptoReplaceFfxFpeConfig.newBuilder()
              .setCryptoKey(cryptoKey)
              // Set of characters in the input text. For more info, see
              // https://cloud.google.com/dlp/docs/reference/rest/v2/organizations.deidentifyTemplates#DeidentifyTemplate.FfxCommonNativeAlphabet
              .setCommonAlphabet(FfxCommonNativeAlphabet.NUMERIC)
              .build();
      PrimitiveTransformation primitiveTransformation =
          PrimitiveTransformation.newBuilder()
              .setCryptoReplaceFfxFpeConfig(cryptoReplaceFfxFpeConfig)
              .build();

      // Specify field to be encrypted.
      FieldId fieldId = FieldId.newBuilder().setName("Employee ID").build();

      // Associate the encryption with the specified field.
      FieldTransformation fieldTransformation =
          FieldTransformation.newBuilder()
              .setPrimitiveTransformation(primitiveTransformation)
              .addFields(fieldId)
              .build();
      RecordTransformations transformations =
          RecordTransformations.newBuilder().addFieldTransformations(fieldTransformation).build();

      DeidentifyConfig deidentifyConfig =
          DeidentifyConfig.newBuilder().setRecordTransformations(transformations).build();

      // Combine configurations into a request for the service.
      DeidentifyContentRequest request =
          DeidentifyContentRequest.newBuilder()
              .setParent(LocationName.of(projectId, "global").toString())
              .setItem(contentItem)
              .setDeidentifyConfig(deidentifyConfig)
              .build();

      // Send the request and receive response from the service.
      DeidentifyContentResponse response = dlp.deidentifyContent(request);

      // Print the results.
      System.out.println(
          "Table after format-preserving encryption: " + response.getItem().getTable());
    }
  }
}

Nach der Transformation sieht die Tabelle so aus:

Mitarbeiter-ID Datum Vergütung
28777 2015 10 $
28777 2016 20 $
39344 2016 15 $

Diese Transformation entspricht unseren Bedürfnissen, da die tatsächlichen Mitarbeiter-IDs entfernt und identische IDs einheitlich ersetzt werden, sodass Einträge, die zu einem bestimmten Mitarbeiter gehören, weiterhin verknüpft bleiben. Zum Beispiel wurde die Mitarbeiter-ID "11111" in den ersten zwei Einträgen einheitlich durch "28777" ersetzt. Der zu analysierende Wert der resultierenden Daten wurde beibehalten, während gleichzeitig die Privatsphäre geschützt wurde.

Umkehrbeispiel

Zum Veranschaulichen der Umkehrung gehen wir zurück zum vorherigen Beispiel. Nehmen wir an, dass bei der Analyse herauskommt, dass der Mitarbeiter mit der ID "28777" einen höheren Lohn erhalten haben sollte und die Dateneigentümer (etwa Manager des Unternehmens) die Vergütung für diesen Mitarbeiter anpassen möchte. Dazu benötigen sie die tatsächliche Mitarbeiter-ID. Zur Umkehrung von "28777" in die tatsächliche ID verwenden wir die Methode content.reidentify, wie im folgenden JSON-Beispiel gezeigt:

Protokoll

JSON-Eingabe:

POST https://dlp.googleapis.com/v2/projects/[PROJECT_ID]/content:reidentify?key={YOUR_API_KEY}

{
  "reidentifyConfig":{
    "recordTransformations":{
      "fieldTransformations":[
        {
          "primitiveTransformation":{
            "cryptoReplaceFfxFpeConfig":{
              "cryptoKey":{
                "unwrapped":{
                  "key":"YWJjZGVmZ2hpamtsbW5vcA=="
                }
              },
              "commonAlphabet":"NUMERIC"
            }
          },
          "fields":[
            {
              "name":"Employee ID"
            }
          ]
        }
      ]
    }
  },
  "item":{
    "table":{
      "headers":[
        {
          "name":"Employee ID"
        }
      ],
      "rows":[
        {
          "values":[
            {
              "stringValue":"28777"
            }
          ]
        }
      ]
    }
  }
}

JSON-Ausgabe:

{
  "item":{
    "table":{
      "headers":[
        {
          "name":"Employee ID"
        }
      ],
      "rows":[
        {
          "values":[
            {
              "stringValue":"11111"
            }
          ]
        }
      ]
    }
  },
  "overview":{
    "transformedBytes":"5",
    "transformationSummaries":[
      {
        "field":{
          "name":"Employee ID"
        },
        "results":[
          {
            "count":"1",
            "code":"SUCCESS"
          }
        ],
        "fieldTransformations":[
          {
            "fields":[
              {
                "name":"Employee ID"
              }
            ],
            "primitiveTransformation":{
              "cryptoReplaceFfxFpeConfig":{
                "cryptoKey":{
                  "unwrapped":{
                    "key":"YWJjZGVmZ2hpamtsbW5vcA=="
                  }
                },
                "commonAlphabet":"NUMERIC"
              }
            }
          }
        ],
        "transformedBytes":"5"
      }
    ]
  }
}

Java


import com.google.cloud.dlp.v2.DlpServiceClient;
import com.google.common.io.BaseEncoding;
import com.google.privacy.dlp.v2.ContentItem;
import com.google.privacy.dlp.v2.CryptoKey;
import com.google.privacy.dlp.v2.CryptoReplaceFfxFpeConfig;
import com.google.privacy.dlp.v2.CryptoReplaceFfxFpeConfig.FfxCommonNativeAlphabet;
import com.google.privacy.dlp.v2.CustomInfoType;
import com.google.privacy.dlp.v2.CustomInfoType.SurrogateType;
import com.google.privacy.dlp.v2.DeidentifyConfig;
import com.google.privacy.dlp.v2.FieldId;
import com.google.privacy.dlp.v2.FieldTransformation;
import com.google.privacy.dlp.v2.InfoType;
import com.google.privacy.dlp.v2.InfoTypeTransformations;
import com.google.privacy.dlp.v2.InfoTypeTransformations.InfoTypeTransformation;
import com.google.privacy.dlp.v2.InspectConfig;
import com.google.privacy.dlp.v2.KmsWrappedCryptoKey;
import com.google.privacy.dlp.v2.LocationName;
import com.google.privacy.dlp.v2.PrimitiveTransformation;
import com.google.privacy.dlp.v2.RecordTransformations;
import com.google.privacy.dlp.v2.ReidentifyContentRequest;
import com.google.privacy.dlp.v2.ReidentifyContentResponse;
import com.google.privacy.dlp.v2.Table;
import com.google.privacy.dlp.v2.Table.Row;
import com.google.privacy.dlp.v2.Value;
import com.google.protobuf.ByteString;
import java.io.IOException;

public class ReIdentifyTableWithFpe {

  public static void main(String[] args) throws Exception {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "your-project-id";
    String kmsKeyName =
        "projects/YOUR_PROJECT/"
            + "locations/YOUR_KEYRING_REGION/"
            + "keyRings/YOUR_KEYRING_NAME/"
            + "cryptoKeys/YOUR_KEY_NAME";
    String wrappedAesKey = "YOUR_ENCRYPTED_AES_256_KEY";
    Table tableToReIdentify = Table.newBuilder()
        .addHeaders(FieldId.newBuilder().setName("Employee ID").build())
        .addRows(
            Row.newBuilder().addValues(
                Value.newBuilder().setStringValue("28777").build())
                .build())
        .build();
    reIdentifyTableWithFpe(projectId, tableToReIdentify, kmsKeyName, wrappedAesKey);
  }

  public static void reIdentifyTableWithFpe(
      String projectId, Table tableToReIdentify, String kmsKeyName, String wrappedAesKey)
      throws IOException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests. After completing all of your requests, call
    // the "close" method on the client to safely clean up any remaining background resources.
    try (DlpServiceClient dlp = DlpServiceClient.create()) {
      // Specify what content you want the service to re-identify.
      ContentItem contentItem = ContentItem.newBuilder().setTable(tableToReIdentify).build();

      // Specify an encrypted AES-256 key and the name of the Cloud KMS key that encrypted it.
      KmsWrappedCryptoKey kmsWrappedCryptoKey =
          KmsWrappedCryptoKey.newBuilder()
              .setWrappedKey(ByteString.copyFrom(BaseEncoding.base64().decode(wrappedAesKey)))
              .setCryptoKeyName(kmsKeyName)
              .build();
      CryptoKey cryptoKey = CryptoKey.newBuilder().setKmsWrapped(kmsWrappedCryptoKey).build();

      // Specify how to un-encrypt the previously de-identified information.
      CryptoReplaceFfxFpeConfig cryptoReplaceFfxFpeConfig =
          CryptoReplaceFfxFpeConfig.newBuilder()
              .setCryptoKey(cryptoKey)
              // Set of characters in the input text. For more info, see
              // https://cloud.google.com/dlp/docs/reference/rest/v2/organizations.deidentifyTemplates#DeidentifyTemplate.FfxCommonNativeAlphabet
              .setCommonAlphabet(FfxCommonNativeAlphabet.NUMERIC)
              .build();
      PrimitiveTransformation primitiveTransformation =
          PrimitiveTransformation.newBuilder()
              .setCryptoReplaceFfxFpeConfig(cryptoReplaceFfxFpeConfig)
              .build();

      // Specify field to be decrypted.
      FieldId fieldId = FieldId.newBuilder().setName("Employee ID").build();

      // Associate the decryption with the specified field.
      FieldTransformation fieldTransformation =
          FieldTransformation.newBuilder()
              .setPrimitiveTransformation(primitiveTransformation)
              .addFields(fieldId)
              .build();
      RecordTransformations transformations =
          RecordTransformations.newBuilder().addFieldTransformations(fieldTransformation).build();

      DeidentifyConfig reidentifyConfig =
          DeidentifyConfig.newBuilder().setRecordTransformations(transformations).build();

      // Combine configurations into a request for the service.
      ReidentifyContentRequest request =
          ReidentifyContentRequest.newBuilder()
              .setParent(LocationName.of(projectId, "global").toString())
              .setItem(contentItem)
              .setReidentifyConfig(reidentifyConfig)
              .build();

      // Send the request and receive response from the service
      ReidentifyContentResponse response = dlp.reidentifyContent(request);

      // Print the results
      System.out.println("Table after re-identification: " + response.getItem().getValue());
    }
  }
}

Wie in der JSON-Ausgabe gezeigt, erhalten wir in der Rückgabe die echte Mitarbeiter-ID: "11111".

Kontexte

Bei der Transformation strukturierter Daten (Tabellendaten mit Einträgen und Feldern) mit einer Pseudonymisierungstransformation wie CryptoReplaceFfxFpeConfig kann ein context angegeben werden. Wenn angegeben, definiert context ein Feld, dessen Wert in einem bestimmten Eintrag als "Tweak" genommen wird. Zum Beispiel kann in der folgenden Tabelle "Patienten-ID" als Kontext gewählt werden und in dem Fall wird für den ersten Eintrag "4672" und für den zweiten Eintrag "3246" als Tweak verwendet.

Damit der Zweck der Angabe eines Kontextes deutlicher wird, nehmen wir zuerst an, dass das Feld "Name" in der folgenden Tabelle ohne Verwendung eines Kontextes transformiert wird. In diesem Fall wird jeder identische Name durch dasselbe Token ersetzt. Dies bedeutet, dass sich zwei gleiche Tokens auf denselben Namen beziehen. Das kann jedoch unerwünscht sein, da hierdurch sensible Beziehungen zwischen Einträgen aufgedeckt werden können. Hier können wir einen Kontext verwenden, um diese Beziehungen aufzuheben. In diesem Fall gelten die Beziehungen nur für die Tokens, die mit einem identischen Tweak generiert wurden.

Betrachten Sie zum Beispiel die folgende Tabelle.

Rechnungsnummer Patienten-ID Name
223 4672 John  
224 3246 Debra  
225 3529 Nate  
226 4098 Debra  
     

Wenn Sie diese Transformation auf "Name" anwenden, ohne einen Kontext anzugeben, entsteht die folgende transformierte Tabelle (die genauen Token-Werte hängen vom angegebenen cryptoKey ab):

Rechnungsnummer Patienten-ID Name
223 4672 gCUv  
224 3246 Eusyw  
225 3529 dsla  
226 4098 Eusyw  
     

Beachten Sie, dass in der obigen Tabelle Einträge mit dem Namen "Debra" ein identisches Token haben. Zum Aufheben dieser Beziehung können wir "Patienten-ID" als Kontext angeben und die Transformation an der ursprünglichen Tabelle ausführen. Dadurch ergibt sich die folgende transformierte Tabelle (die genauen Tokenwerte hängen vom angegebenen cryptoKey ab):

Rechnungsnummer Patienten-ID Name
223 4672 Agca  
224 3246 vSHig  
225 3529 kqHX  
226 4098 CUgv  
     

Beachten Sie nun, wie "Debra" durch verschiedene Tokens ersetzt wurde, da die beiden Einträge unterschiedliche Patienten-IDs haben.

Ersatzanmerkungen

In den obigen Beispielen werden strukturierte (tabellarische) Daten verwendet. Dies macht eine Umkehrung einfach, da das umzukehrende Token leicht identifiziert werden kann. Wenn das Token jedoch im Freitext vorhanden ist, muss für die Ausführung der Umkehrung zuerst das Token gesucht werden. Reversible Transformationen ermöglichen dies über das Feld surrogateInfoType. Weitere Informationen finden Sie unter CryptoReplaceFfxFpeConfig.

Dieses Feld erleichtert zusammen mit dem benutzerdefinierten infoType SurrogateType die Prüfung von freiem Text auf Tokens.

Codebeispiel für die De-Identifikation im Freitext

Hier ein Beispiel. Wir verwenden die Methode content.deidentify, um eine im Freitext gefundene Telefonnummer mithilfe eines Tokens zu transformieren.

Protokoll

JSON-Eingabe:

POST https://dlp.googleapis.com/v2/projects/velvety-study-196101/content:deidentify?key={YOUR_API_KEY}

{
  "deidentifyConfig":{
    "infoTypeTransformations":{
      "transformations":[
        {
          "infoTypes":[
            {
              "name":"PHONE_NUMBER"
            }
          ],
          "primitiveTransformation":{
            "cryptoReplaceFfxFpeConfig":{
              "cryptoKey":{
                "unwrapped":{
                  "key":"YWJjZGVmZ2hpamtsbW5vcA=="
                }
              },
              "commonAlphabet":"NUMERIC",
              "surrogateInfoType":{
                "name":"PHONE_TOKEN"
              }
            }
          }
        }
      ]
    }
  },
  "inspectConfig":{
    "infoTypes":[
      {
        "name":"PHONE_NUMBER"
      }
    ],
    "minLikelihood":"UNLIKELY"
  },
  "item":{
    "value":"My phone number is 4359916732"
  }
}

Nachdem der JSON-Code an die angegebene URL gesendet wurde, gibt Cloud DLP die folgende Ausgabe zurück.

JSON-Ausgabe:

{
 "item": {
  "value": "My phone number is PHONE_TOKEN(10):9617256398"
 },
 "overview": {
  "transformedBytes": "10",
  "transformationSummaries": [
   {
    "infoType": {
     "name": "PHONE_NUMBER"
    },
    "transformation": {
     "cryptoReplaceFfxFpeConfig": {
      "cryptoKey": {
       "unwrapped": {
        "key": "YWJjZGVmZ2hpamtsbW5vcA=="
       }
      },
      "commonAlphabet": "NUMERIC",
      "surrogateInfoType": {
       "name": "PHONE_TOKEN"
      }
     }
    },
    "results": [
     {
      "count": "1",
      "code": "SUCCESS"
     }
    ],
    "transformedBytes": "10"
   }
  ]
 }
}

Java


import com.google.cloud.dlp.v2.DlpServiceClient;
import com.google.common.io.BaseEncoding;
import com.google.privacy.dlp.v2.ContentItem;
import com.google.privacy.dlp.v2.CryptoKey;
import com.google.privacy.dlp.v2.CryptoReplaceFfxFpeConfig;
import com.google.privacy.dlp.v2.CryptoReplaceFfxFpeConfig.FfxCommonNativeAlphabet;
import com.google.privacy.dlp.v2.DeidentifyConfig;
import com.google.privacy.dlp.v2.DeidentifyContentRequest;
import com.google.privacy.dlp.v2.DeidentifyContentResponse;
import com.google.privacy.dlp.v2.InfoType;
import com.google.privacy.dlp.v2.InfoTypeTransformations;
import com.google.privacy.dlp.v2.InfoTypeTransformations.InfoTypeTransformation;
import com.google.privacy.dlp.v2.InspectConfig;
import com.google.privacy.dlp.v2.KmsWrappedCryptoKey;
import com.google.privacy.dlp.v2.LocationName;
import com.google.privacy.dlp.v2.PrimitiveTransformation;
import com.google.protobuf.ByteString;
import java.io.IOException;
import java.util.Arrays;

public class DeIdentifyTextWithFpe {

  public static void main(String[] args) throws Exception {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "your-project-id";
    String textToDeIdentify = "I'm Gary and my email is gary@example.com";
    String kmsKeyName =
        "projects/YOUR_PROJECT/"
            + "locations/YOUR_KEYRING_REGION/"
            + "keyRings/YOUR_KEYRING_NAME/"
            + "cryptoKeys/YOUR_KEY_NAME";
    String wrappedAesKey = "YOUR_ENCRYPTED_AES_256_KEY";
    deIdentifyTextWithFpe(projectId, textToDeIdentify, kmsKeyName, wrappedAesKey);
  }

  public static void deIdentifyTextWithFpe(
      String projectId, String textToDeIdentify, String kmsKeyName, String wrappedAesKey)
      throws IOException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests. After completing all of your requests, call
    // the "close" method on the client to safely clean up any remaining background resources.
    try (DlpServiceClient dlp = DlpServiceClient.create()) {
      // Specify what content you want the service to de-identify.
      ContentItem contentItem = ContentItem.newBuilder().setValue(textToDeIdentify).build();

      // Specify the type of info you want the service to de-identify.
      // See https://cloud.google.com/dlp/docs/infotypes-reference for complete list of info types.
      InfoType infoType = InfoType.newBuilder().setName("PHONE_NUMBER").build();
      InspectConfig inspectConfig =
          InspectConfig.newBuilder().addAllInfoTypes(Arrays.asList(infoType)).build();

      // Specify an encrypted AES-256 key and the name of the Cloud KMS key that encrypted it.
      KmsWrappedCryptoKey kmsWrappedCryptoKey =
          KmsWrappedCryptoKey.newBuilder()
              .setWrappedKey(ByteString.copyFrom(BaseEncoding.base64().decode(wrappedAesKey)))
              .setCryptoKeyName(kmsKeyName)
              .build();
      CryptoKey cryptoKey = CryptoKey.newBuilder().setKmsWrapped(kmsWrappedCryptoKey).build();

      // Specify how the info from the inspection should be encrypted.
      InfoType surrogateInfoType = InfoType.newBuilder().setName("PHONE_TOKEN").build();
      CryptoReplaceFfxFpeConfig cryptoReplaceFfxFpeConfig =
          CryptoReplaceFfxFpeConfig.newBuilder()
              .setCryptoKey(cryptoKey)
              // Set of characters in the input text. For more info, see
              // https://cloud.google.com/dlp/docs/reference/rest/v2/organizations.deidentifyTemplates#DeidentifyTemplate.FfxCommonNativeAlphabet
              .setCommonAlphabet(FfxCommonNativeAlphabet.NUMERIC)
              .setSurrogateInfoType(surrogateInfoType)
              .build();
      PrimitiveTransformation primitiveTransformation =
          PrimitiveTransformation.newBuilder()
              .setCryptoReplaceFfxFpeConfig(cryptoReplaceFfxFpeConfig)
              .build();
      InfoTypeTransformation infoTypeTransformation =
          InfoTypeTransformation.newBuilder()
              .setPrimitiveTransformation(primitiveTransformation)
              .build();
      InfoTypeTransformations transformations =
          InfoTypeTransformations.newBuilder().addTransformations(infoTypeTransformation).build();

      DeidentifyConfig deidentifyConfig =
          DeidentifyConfig.newBuilder().setInfoTypeTransformations(transformations).build();

      // Combine configurations into a request for the service.
      DeidentifyContentRequest request =
          DeidentifyContentRequest.newBuilder()
              .setParent(LocationName.of(projectId, "global").toString())
              .setItem(contentItem)
              .setInspectConfig(inspectConfig)
              .setDeidentifyConfig(deidentifyConfig)
              .build();

      // Send the request and receive response from the service.
      DeidentifyContentResponse response = dlp.deidentifyContent(request);

      // Print the results.
      System.out.println(
          "Text after format-preserving encryption: " + response.getItem().getValue());
    }
  }
}

Python

def deidentify_free_text_with_fpe_using_surrogate(
    project,
    input_str,
    alphabet="NUMERIC",
    info_type="PHONE_NUMBER",
    surrogate_type="PHONE_TOKEN",
    unwrapped_key="YWJjZGVmZ2hpamtsbW5vcA==",
):
    """Uses the Data Loss Prevention API to deidentify sensitive data in a
       string using Format Preserving Encryption (FPE).
       The encryption is performed with an unwrapped key.
    Args:
        project: The Google Cloud project id to use as a parent resource.
        input_str: The string to deidentify (will be treated as text).
        alphabet: The set of characters to replace sensitive ones with. For
            more information, see https://cloud.google.com/dlp/docs/reference/
            rest/v2beta2/organizations.deidentifyTemplates#ffxcommonnativealphabet
        info_type: The name of the info type to de-identify
        surrogate_type: The name of the surrogate custom info type to use. Can
            be essentially any arbitrary string, as long as it doesn't appear
            in your dataset otherwise.
        unwrapped_key: The base64-encoded AES-256 key to use.
    Returns:
        None; the response from the API is printed to the terminal.
    """
    # Import the client library
    import google.cloud.dlp

    # Instantiate a client
    dlp = google.cloud.dlp_v2.DlpServiceClient()

    # Convert the project id into a full resource id.
    parent = dlp.project_path(project)

    # The unwrapped key is base64-encoded, but the library expects a binary
    # string, so decode it here.
    import base64

    unwrapped_key = base64.b64decode(unwrapped_key)

    # Construct de-identify config
    transformation = {
        "info_types": [{"name": info_type}],
        "primitive_transformation": {
            "crypto_replace_ffx_fpe_config": {
                "crypto_key": {
                    "unwrapped": {"key": unwrapped_key}
                },
                "common_alphabet": alphabet,
                "surrogate_info_type": {"name": surrogate_type},
            }
        }
    }

    deidentify_config = {
        "info_type_transformations": {
            "transformations": [transformation]
        }
    }

    # Construct the inspect config, trying to finding all PII with likelihood
    # higher than UNLIKELY
    inspect_config = {
        "info_types": [{"name": info_type}],
        "min_likelihood": "UNLIKELY"
    }

    # Convert string to item
    item = {"value": input_str}

    # Call the API
    response = dlp.deidentify_content(
        parent,
        inspect_config=inspect_config,
        deidentify_config=deidentify_config,
        item=item,
    )

    # Print results
    print(response.item.value)

Cloud DLP hat die Telefonnummer erfolgreich de-identifiziert (9617256398).

Codebeispiel für die Re-Identifikation im Freitext

In diesem zweiten Beispiel kehren wir den transformierten Text aus dem ersten Beispiel mithilfe der Methode content.reidentify wieder in die ursprüngliche Zahl um.

Protokoll

Weitere Informationen zur Verwendung der Cloud DLP API mit JSON finden Sie in der JSON-Kurzanleitung.

JSON-Eingabe:

POST https://dlp.googleapis.com/v2/projects/[PROJECT_ID]/content:reidentify?key={YOUR_API_KEY}

{
 "reidentifyConfig": {
  "infoTypeTransformations": {
   "transformations": [
    {
     "infoTypes": [
      {
       "name": "PHONE_TOKEN"
      }
     ],
     "primitiveTransformation": {
      "cryptoReplaceFfxFpeConfig": {
       "cryptoKey": {
        "unwrapped": {
         "key": "YWJjZGVmZ2hpamtsbW5vcA=="
        }
       },
       "commonAlphabet": "NUMERIC",
       "surrogateInfoType": {
        "name": "PHONE_TOKEN"
       }
      }
     }
    }
   ]
  }
 },
 "inspectConfig": {
  "customInfoTypes": [
   {
    "infoType": {
     "name": "PHONE_TOKEN"
    },
    "surrogateType": {
    }
   }
  ]
 },
 "item": {
  "value": "My phone number is PHONE_TOKEN(10):9617256398"
 }
}

JSON-Ausgabe:

{
  "item":{
    "value":"My phone number is 4359916732"
  },
  "overview":{
    "transformedBytes":"26",
    "transformationSummaries":[
      {
        "infoType":{
          "name":"PHONE_TOKEN"
        },
        "transformation":{
          "cryptoReplaceFfxFpeConfig":{
            "cryptoKey":{
              "unwrapped":{
                "key":"YWJjZGVmZ2hpamtsbW5vcA=="
              }
            },
            "commonAlphabet":"NUMERIC",
            "surrogateInfoType":{
              "name":"PHONE_TOKEN"
            }
          }
        },
        "results":[
          {
            "count":"1",
            "code":"SUCCESS"
          }
        ],
        "transformedBytes":"26"
      }
    ]
  }
}

Java


import com.google.cloud.dlp.v2.DlpServiceClient;
import com.google.common.io.BaseEncoding;
import com.google.privacy.dlp.v2.ContentItem;
import com.google.privacy.dlp.v2.CryptoKey;
import com.google.privacy.dlp.v2.CryptoReplaceFfxFpeConfig;
import com.google.privacy.dlp.v2.CryptoReplaceFfxFpeConfig.FfxCommonNativeAlphabet;
import com.google.privacy.dlp.v2.CustomInfoType;
import com.google.privacy.dlp.v2.CustomInfoType.SurrogateType;
import com.google.privacy.dlp.v2.DeidentifyConfig;
import com.google.privacy.dlp.v2.InfoType;
import com.google.privacy.dlp.v2.InfoTypeTransformations;
import com.google.privacy.dlp.v2.InfoTypeTransformations.InfoTypeTransformation;
import com.google.privacy.dlp.v2.InspectConfig;
import com.google.privacy.dlp.v2.KmsWrappedCryptoKey;
import com.google.privacy.dlp.v2.LocationName;
import com.google.privacy.dlp.v2.PrimitiveTransformation;
import com.google.privacy.dlp.v2.ReidentifyContentRequest;
import com.google.privacy.dlp.v2.ReidentifyContentResponse;
import com.google.protobuf.ByteString;
import java.io.IOException;

public class ReIdentifyTextWithFpe {

  public static void main(String[] args) throws Exception {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "your-project-id";
    String textToReIdentify = "My phone number is PHONE_TOKEN(10):9617256398";
    String kmsKeyName =
        "projects/YOUR_PROJECT/"
            + "locations/YOUR_KEYRING_REGION/"
            + "keyRings/YOUR_KEYRING_NAME/"
            + "cryptoKeys/YOUR_KEY_NAME";
    String wrappedAesKey = "YOUR_ENCRYPTED_AES_256_KEY";
    reIdentifyTextWithFpe(projectId, textToReIdentify, kmsKeyName, wrappedAesKey);
  }

  public static void reIdentifyTextWithFpe(
      String projectId, String textToReIdentify, String kmsKeyName, String wrappedAesKey)
      throws IOException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests. After completing all of your requests, call
    // the "close" method on the client to safely clean up any remaining background resources.
    try (DlpServiceClient dlp = DlpServiceClient.create()) {
      // Specify what content you want the service to re-identify.
      ContentItem contentItem = ContentItem.newBuilder().setValue(textToReIdentify).build();

      // Specify the type of info the inspection will re-identify. This must use the same custom
      // into type that was used as a surrogate during the initial encryption.
      InfoType surrogateInfoType = InfoType.newBuilder().setName("PHONE_NUMBER").build();

      CustomInfoType customInfoType =
          CustomInfoType.newBuilder()
              .setInfoType(surrogateInfoType)
              .setSurrogateType(SurrogateType.getDefaultInstance())
              .build();
      InspectConfig inspectConfig =
          InspectConfig.newBuilder().addCustomInfoTypes(customInfoType).build();

      // Specify an encrypted AES-256 key and the name of the Cloud KMS key that encrypted it.
      KmsWrappedCryptoKey kmsWrappedCryptoKey =
          KmsWrappedCryptoKey.newBuilder()
              .setWrappedKey(ByteString.copyFrom(BaseEncoding.base64().decode(wrappedAesKey)))
              .setCryptoKeyName(kmsKeyName)
              .build();
      CryptoKey cryptoKey = CryptoKey.newBuilder().setKmsWrapped(kmsWrappedCryptoKey).build();

      // Specify how to un-encrypt the previously de-identified information.
      CryptoReplaceFfxFpeConfig cryptoReplaceFfxFpeConfig =
          CryptoReplaceFfxFpeConfig.newBuilder()
              .setCryptoKey(cryptoKey)
              // Set of characters in the input text. For more info, see
              // https://cloud.google.com/dlp/docs/reference/rest/v2/organizations.deidentifyTemplates#DeidentifyTemplate.FfxCommonNativeAlphabet
              .setCommonAlphabet(FfxCommonNativeAlphabet.NUMERIC)
              .setSurrogateInfoType(surrogateInfoType)
              .build();
      PrimitiveTransformation primitiveTransformation =
          PrimitiveTransformation.newBuilder()
              .setCryptoReplaceFfxFpeConfig(cryptoReplaceFfxFpeConfig)
              .build();
      InfoTypeTransformation infoTypeTransformation =
          InfoTypeTransformation.newBuilder()
              .setPrimitiveTransformation(primitiveTransformation)
              .addInfoTypes(surrogateInfoType)
              .build();
      InfoTypeTransformations transformations =
          InfoTypeTransformations.newBuilder().addTransformations(infoTypeTransformation).build();

      DeidentifyConfig reidentifyConfig =
          DeidentifyConfig.newBuilder().setInfoTypeTransformations(transformations).build();

      // Combine configurations into a request for the service.
      ReidentifyContentRequest request =
          ReidentifyContentRequest.newBuilder()
              .setParent(LocationName.of(projectId, "global").toString())
              .setItem(contentItem)
              .setInspectConfig(inspectConfig)
              .setReidentifyConfig(reidentifyConfig)
              .build();

      // Send the request and receive response from the service
      ReidentifyContentResponse response = dlp.reidentifyContent(request);

      // Print the results
      System.out.println("Text after re-identification: " + response.getItem().getValue());
    }
  }
}

Python

def reidentify_free_text_with_fpe_using_surrogate(
    project,
    input_str,
    alphabet="NUMERIC",
    surrogate_type="PHONE_TOKEN",
    unwrapped_key="YWJjZGVmZ2hpamtsbW5vcA==",
):
    """Uses the Data Loss Prevention API to reidentify sensitive data in a
    string that was encrypted by Format Preserving Encryption (FPE) with
    surrogate type. The encryption is performed with an unwrapped key.
    Args:
        project: The Google Cloud project id to use as a parent resource.
        input_str: The string to deidentify (will be treated as text).
        alphabet: The set of characters to replace sensitive ones with. For
            more information, see https://cloud.google.com/dlp/docs/reference/
            rest/v2beta2/organizations.deidentifyTemplates#ffxcommonnativealphabet
        surrogate_type: The name of the surrogate custom info type to used
            during the encryption process.
        unwrapped_key: The base64-encoded AES-256 key to use.
    Returns:
        None; the response from the API is printed to the terminal.
    """
    # Import the client library
    import google.cloud.dlp

    # Instantiate a client
    dlp = google.cloud.dlp_v2.DlpServiceClient()

    # Convert the project id into a full resource id.
    parent = dlp.project_path(project)

    # The unwrapped key is base64-encoded, but the library expects a binary
    # string, so decode it here.
    import base64

    unwrapped_key = base64.b64decode(unwrapped_key)

    # Construct Deidentify Config
    transformation = {
        "primitive_transformation": {
            "crypto_replace_ffx_fpe_config": {
                "crypto_key": {
                    "unwrapped": {"key": unwrapped_key}
                },
                "common_alphabet": alphabet,
                "surrogate_info_type": {"name": surrogate_type},
            }
        }
    }

    reidentify_config = {
        "info_type_transformations": {
            "transformations": [transformation]
        }
    }

    inspect_config = {
        "custom_info_types": [
            {"info_type": {"name": surrogate_type}, "surrogate_type": {}}        ]
    }

    # Convert string to item
    item = {"value": input_str}

    # Call the API
    response = dlp.reidentify_content(
        parent,
        inspect_config=inspect_config,
        reidentify_config=reidentify_config,
        item=item,
    )

    # Print results
    print(response.item.value)

Cloud DLP hat die Telefonnummer erfolgreich reidentifiziert (4359916732).

Ressourcen

Weitere Informationen zur Verwendung von Cloud DLP zum Pseudonymisieren, De-Identifizieren und Re-Identifizieren sensibler Daten finden Sie unter Sensible Daten in Textinhalten de-identifizieren.