
In der Softwareentwicklung ist es ein Standardvorgang, Daten aus dem Produktionssystem zu verwenden und diese in einer anderen Umgebung wiederherzustellen. Diese andere Umgebung ist in den meisten Fällen eine Test, Entwicklung oder Staging Umgebung. Sie werden verwendet, damit Entwicklerteams Probleme beheben können ohne direkt die Produktionsumgebung zu tangieren. Sie dienen quasi dazu, verschiedene Szenarien, Versionen und Funktionen zu testen. Natürlich erfinden wir hiermit jetzt nicht das Rad neu, denn die Idee, Tests in einer Entwicklungs- oder Staging Umgebung durchzuführen ist nichts Neues. Seit Jahrzehnten ist es Standard, Kopien von Produktionsdaten zu erstellen und diese in Nicht-Produktionsumgebungen wiederherzustellen. Doch vermehrt treten auch hier immer wieder Probleme auf. Sei es zum Beispiel bei großen Datenmengen, da diese erfahrungsgemäß eine enorme Zeit im Wiederherstellungsprozess beanspruchen. Sie blockieren damit auch die Netzwerkbandbreite und vermehren zudem die Kosten für Speicherung und Datenpflege.
Daten sind das wichtigste Gut Ihres Unternehmens!
Wenn Sie sich bemühen, die Produktion zu sperren aber dennoch Daten aus der besagten Produktion in weniger sicherere Umgebungen einschleusen, haben Sie diese Arbeit umsonst getan. Es werden jährlich Milliarden von Dollar in die Sicherung von physischen Rechenzentren gesteckt, nur damit Entwickler die Daten von einer Produktionsumgebung in unsicheres Terrain übertragen und wiederherstellen. Es gibt mittlerweile viele Möglichkeiten und Optionen, Daten in andere Umgebungen zu verschieben. Beispielsweise die Datenmaskierung, Datenverschleierung oder die Datenverschlüsselung. Die beste und sicherste Option ist trotz allem die Daten NICHT zu verschieben.
Mittlerweile ist man soweit, den Gedanken “nicht in der Produktionsumgebung zu testen” zu überdenken und zu hinterfragen. Mit einer CI/CD (Continuous Integration und Continuous Development) ist dies zum Beispiel sogar möglich. Dafür brauchen Sie keine echten Produktionsdaten. Sie brauchen Daten, die wie Produktionsdaten aussehen. Sogenannte Dummy-Daten. Das können beispielsweise Fake Kundennamen oder abgewandelte Adressen / Informationen sein. Mittels Simulationen können Sie Statistiken kreieren, die den Statistiken aus Ihrer Produktionsumgebung ähneln. Damit erreichen beispielsweise Abfragepläne die gleiche Form wie ursprünglich in der Produktion, ohne das tatsächliche Datenvolumen zu besitzen.
Einige Anonymisierungsvorgänge stellen wir Ihnen nachfolgend vor, damit Sie das Risiko nicht mehr eingehen müssen.
Anonymisierung von CSV-Daten
Bei der Anonymisierung von CSV-Daten werden lediglich zwei Felder explizit maskiert. Zum Einen ist das der vollständige Name zum Anderen die Email-Adresse. Im ersten Moment klingt das nach einer Kleinigkeit, allerdings besteht die Schwierigkeit in der Bewahrung der semantischen Beziehung und Verteilungen im Zieldatensatz. Da es auch oftmals in CSV Datensätzen zu mehreren Zeilen pro Nutzer kommen kann, müssen wir die Zuordnung von Profilinformationen pflegen.
In diesem Beispiel nutzen wir Python 2.7. und müssen entsprechend das unicodecsv Modul mit pip installieren. Weiterhin benötigen wir noch die Fake-Bibliothek zum Test. Nutzen Sie dafür folgenden Befehl:
$ pip install fake-factory unicodecsv
Mit dem folgenden Beispiel zeigen wir Ihnen, wie eine recht simple anonymize_rows
Funktion die Zuordnung der Felder beibehält und unterdessen Fake Daten generiert. Dann gehen wir damit noch einen Schritt weiter und lesen Daten aus einer Quell CSV-Datei und schreiben anonymisierte Daten in die Ziel CSV-Datei. Das Ergebnis sollte dann eine Datei sein, die in Bezug auf Zeilenlänge, Felder und Co. sehr ähnlich ist. Lediglich Name und Emailadresse wurden ersetzt.
Verwenden Sie dafür folgenden Code:
import unicodecsv as csv
from faker import Factory
from collections import defaultdict
def anonymize_rows(rows):
"""
Rows is an iterable of dictionaries that contain name and
email fields that need to be anonymized.
"""
# Load the faker and its providers
faker = Factory.create()
# Create mappings of names & emails to faked names & emails.
names = defaultdict(faker.name)
emails = defaultdict(faker.email)
# Iterate over the rows and yield anonymized rows.
for row in rows:
# Replace the name and email fields with faked fields.
row['name'] = names[row['name']]
row['email'] = emails[row['email']]
# Yield the row back to the caller
yield row
def anonymize(source, target):
"""
The source argument is a path to a CSV file containing data to anonymize,
while target is a path to write the anonymized CSV data to.
"""
with open(source, 'rU') as f:
with open(target, 'w') as o:
# Use the DictReader to easily extract fields
reader = csv.DictReader(f)
writer = csv.DictWriter(o, reader.fieldnames)
# Read and anonymize data, writing to target file.
for row in anonymize_rows(reader):
writer.writerow(row)
Der Einstieg in diesen Code ist die anonymize Funktion selbst. Es wird der Pfad zu zwei Dateien verwendet. Einmal source , die als Quell CSV-Datei mit Originaldaten bestückt ist und einmal target
, die als Ziel CSV-Datei fungieren soll und in den die Daten dann schlussendlich geschrieben werden. Beide Pfade sind zum Schreiben und Lesen geöffnet. Das unicodecsv Modul wird zum Lesen und Analysieren eingesetzt und wandelt die Ergebnisse dann in ein Python Dictionary um. Diese Dictionaries werden an die anonymize_rows
Funktion übergeben, die mit yields
jede Zeile entsprechend umwandelt und auf die Festplatte schreibt.
Mit dem Python Collection Modul erhalten Sie ein defaultdict
, welches als Standard Dictionary fungiert, allerdings keine Schlüssel beinhaltet. Hier werden Standardwerte generiert und an die Instanz übergeben. Mit der Verwendung von defaultdict(faker.name)
, werden für jeden Schlüssel, der nicht im Dictionary steht, ein falscher Name erstellt. Damit kann eine Zuordnung von echten zu gefälschten Daten sichergestellt werden.
Generieren von gefälschten Daten
Um gefälschte Daten zu generieren gibt es mittlerweile einige Drittanbieter, die dabei unterstützen können. Diese sogenannten Faker bieten eine Anonymisierung von Benutzerprofildaten, die vollständig auf Instanz bezogener Basis generiert werden. Die primäre Schnittstelle der Faker sind Generatoren. Diese umschließen quasi eine Sammlung von Providern, die für die Formatierung der Zufallsdaten für eine bestimmte Domäne zuständig sind. Generatoren bieten zudem auch einen Wrapper um das Modul und ermöglichen damit einen Zufallsstartwert. Generatoren können mit unterschiedlichsten Methoden erstellt werden, als da wären fake.credit_card_number()
, fake.military_ship()
oder fake.hex_color()
. Damit lässt sich recht schnell ein Schema entdecken, wie Sie Generatoren mittels diesen Methoden anpassen und gestalten können.
Wie bereits angemerkt, gibt es eine Vielzahl an Drittanbietern, die diverse Faker-Bibliotheken beinhalten und zur Verfügung stellen. Wir möchten jedoch keine Werbung für einen bestimmten Anbieter machen, deswegen empfehlen wir Ihnen, sollten Sie darüber nachdenken diesen Weg zu wählen, dass Sie sich auf GitHub über gängige Anbieter ein Bild machen und sich erkundigen.
Erstellen eines Anbieters
Wie bereits erwähnt, gibt es eine Vielzahl an Anbietern, die Faker-Bibliotheken anbieten. Theoretisch brauchen Sie zum Generieren von gefälschten Daten nur einen domänenspezifischen Datengenerator. Möchten Sie nun einen benutzerdefinierten Anbieter selbst erstellen, nutzen Sie die BaseProvider Faker-Methode. Sie können dafür folgenden Code verwenden:
from faker.providers import BaseProvider
class OceanProvider(BaseProvider):
__provider__ = "ocean"
__lang__ = "en_US"
oceans = [
u'Atlantic', u'Pacific', u'Indian', u'Arctic', u'Southern',
]
@classmethod
def ocean(cls):
return cls.random_element(cls.oceans)
Um Dopplungen zu vermeiden, empfehlen wir in diesem Beispiel ocean zur Duplikatsliste hinzuzufügen. Fügen Sie dann im Nachgang Faker als Objekt hinzu.
>>> fake = Factory.create()
>>> fake.add_provider(OceanProvider)
>>> fake.ocean()
u'Indian'
In routinemäßigen Datenwrangling Operationen können Sie eine Paketstruktur mit ähnlicher Lokalisierung wie die eines Fakers erstellen und nach Bedarf laden.
Datenqualität aufrecht erhalten
Bisher haben wir die Vielfalt an gefälschten Daten beleuchtet und verstanden, wie wir diese entsprechend auch generieren können. Kehren wir zu unserem Beispiel zurück, erstellen wir zunächst Benutzerprofildaten, lediglich mit Namen und Email-Adresse. Beobachten wir die Ergebnisse der Anonymisierung können wir folgende Vor- & Nachteile feststellen:
Vorteile:
→ Duplikate, die exakt so aufgebaut wurden wie Ihre Quelle, werden über das Mapping beibehalten.
→ Die erstellten Benutzerprofile sind nun gefälscht worden und PII geschützt
Nachteile:
→ Duplikate werden anders angeordnet und stimmen nicht mehr exakt überein (J. Smith vs. John Smith)
→ Alle Domains sind von kostenlosen Providern wie Gmail
→ Name und Email-Adresse entsprechend nicht mehr dem Original und stimmen nicht mehr überein.
Da es jedoch unser Bestreben ist, Benutzerprofile zu verbessern, möchten wir beispielsweise sicherstellen, dass die Domänen für Emailadressen nicht mehr kostenloser Natur sind und entsprechend etwas realistischer rüberkommen. Weiterhin beziehen wir auch Aliase, Spitznamen oder Namensversionen mit ein. Dafür verwenden wir folgendes Skript:
>>> fake.simple_profile()
u'{
"username": "autumn.weissnat",
"name": "Jalyn Crona",
"birthdate": "1981-01-29",
"sex": "F",
"address": "Unit 2875 Box 1477 \n DPO AE 18742-1954",
"mail": "zollie.schamberger@hotmail.com"
}'
Im nachfolgenden Abschnitt werden wir uns dann mit dem Problem beschäftigen, dass wir unsere Datenmodifizierung so anpassen, dass realistischere Fake Profile erstellt werden können und diese mit dem ursprünglichen Datensatz übereinstimmen.