Analysieren
Die Analyse modellieren
Info
Alle in diesem Tutorial beschriebenen Modellierungen kannst du dir mit Kommentaren im
Testordner der Profile Templates (TestAnalyzeProfile.php) anschauen.
Einen Überblick verschaffen
Um einen Überblick über die Daten in der Datenbank zu bekommen, kann das Kommando pseudify:debug:table_schema
verwendet werden.
Du kannst aber natürlich auch jedes andere Tool deiner Wahl dazu verwenden.
$ pseudify pseudify:debug:table_schema
wh_log
------
-------------------- --------- ---------------------------------------------------------------------------------------------------------
column type data example
-------------------- --------- ---------------------------------------------------------------------------------------------------------
id integer 6
log_type string foo
log_data blob 613a323a7b693a303b733a33383a223466623a313434373a646566623a396434373a613265303a613336613a313064333a66...
log_message text {"message":"foo text \"ronaldo15\", another \"mcclure.ofelia@example.com\""}
ip string 4fb:1447:defb:9d47:a2e0:a36a:10d3:fd98
-------------------- --------- ---------------------------------------------------------------------------------------------------------
wh_meta_data
------------
--------------------- --------- ---------------------------------------------------------------------------------------------------------
column type data example
--------------------- --------- ---------------------------------------------------------------------------------------------------------
id integer 5
meta_data blob 1f8b08000000000000036592dd6ea33010855f65657159116ca0818922f52fca6ea5d52a4bab46bd89066c821b302c769246...
--------------------- --------- ---------------------------------------------------------------------------------------------------------
wh_user
-------
-------------------- --------- ----------------------------------------------------------------------------------------------
column type data example
-------------------- --------- ----------------------------------------------------------------------------------------------
id integer 5
username string howell.damien
password string $argon2i$v=19$m=8,t=1,p=1$ZldmOWd2TDJRb3FTNVpGNA$ORIwp6yekRx02mqM4WCTVhllgXpUpuFJZ1MmbYwAMXs
first_name string Mckayla
last_name string Stoltenberg
email string cassin.bernadette@example.net
city string South Wilfordland
-------------------- --------- ----------------------------------------------------------------------------------------------
wh_user_session
---------------
------------------- --------- --------------------------------------------------------------------
column type data example
------------------- --------- --------------------------------------------------------------------
id integer 5
session_data blob a:1:{s:7:"last_ip";s:38:"4fb:1447:defb:9d47:a2e0:a36a:10d3:fd98";}
session_data_json text {"data":{"last_ip":"4fb:1447:defb:9d47:a2e0:a36a:10d3:fd98"}}
------------------- --------- --------------------------------------------------------------------
Das Kommando gibt nacheinander alle Tabellen der Datenbank aus und listet deren Spalten auf.
In der Spalte column
befindet sich der Name der Datenbankspalte.
In der Spalte type
steht der menschenlesbarer Name des Datentyps der Datenbankspalte.
In der Spalte data example
befindet sich der jeweils längste Datensatz, welcher in der Datenbank in dieser Datenbankspalte gefunden werden kann. Nach 100 Zeichen werden die Daten abgeschnitten.
Suche nach personenbezogenen Daten, welche du pseudonymisieren möchtest.
Suche nach Namen, Benutzernamen, Passwörtern, Adressen, E-Mail-Adressen, IP-Adressen, Telefonnummern, ID-Nummern wie Versicherungsnummern, Profildaten wie Größe oder Gewicht usw.
Info
Falls du Anregungen brauchst, dann lies das Kapitel "Was sollte pseudonymisiert werden?"
Notiere dir am besten die Spalten mit direkt sichtbaren personenbezogenen Daten, also die Spalten welche Daten im Klartext enthalten und nicht solche mit komplexeren Datenstrukturen wie JSON (z.B. die Spalte wh_log.log_message
) oder solche in denen die Daten in enkodierter Form vorliegen (z.B. die Spalte wh_log.log_data
).
Im Beispiel wären die bevorzugten Spalten:
wh_log.ip
wh_user.username
wh_user.password
wh_user.first_name
wh_user.last_name
wh_user.email
wh_user.city
Ein "Analyze Profile" modellieren
Ein "Profile" anlegen
Lege im Ordner src/Profiles eine PHP Datei mit einem beliebigen Namen an.
Im Beispiel wird die Datei TestAnalyzeProfile.php
genannt.
Die Datei bekommt folgenden Inhalt:
<?php
namespace Waldhacker\Pseudify\Profiles;
use Waldhacker\Pseudify\Core\Profile\Analyze\ProfileInterface;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TableDefinition;
class TestAnalyzeProfile implements ProfileInterface
{
public function getIdentifier(): string
{
return 'test-profile';
}
public function getTableDefinition(): TableDefinition
{
$tableDefinition = new TableDefinition(identifier: $this->getIdentifier());
return $tableDefinition;
}
}
Die Methode getIdentifier()
muss eine eindeutige Bezeichnung deines Profils wiedergeben und sollte nur aus Buchstaben, Zahlen oder den Zeichen -
und _
bestehen und darf keine Leerzeichen enthalten.
Nach der Erzeugung des Profils muss der Cache geleert werden.
$ pseudify cache:clear
Der Befehl pseudify pseudify:debug:analyze test-profile
gibt dir nun bereits Informationen über dein Profil aus.
$ pseudify pseudify:debug:analyze test-profile
Analyzer profile "test-profile"
===============================
Basis configuration
-------------------
----------------------------------------------- -------
Key Value
----------------------------------------------- -------
Shown characters before and after the finding 10
----------------------------------------------- -------
Collect search data from this tables
------------------------------------
------- -------- --------------- -----------------
Table column data decoders data collectors
------- -------- --------------- -----------------
Search data in this tables
--------------------------
----------------- -------------------------- --------------- -----------------------
Table column data decoders special data decoders
----------------- -------------------------- --------------- -----------------------
wh_log id (integer) Scalar no further processing
wh_log log_type (string) Scalar no further processing
wh_log log_data (blob) Scalar no further processing
wh_log log_message (text) Scalar no further processing
wh_log ip (string) Scalar no further processing
wh_meta_data id (integer) Scalar no further processing
wh_meta_data meta_data (blob) Scalar no further processing
wh_user id (integer) Scalar no further processing
wh_user username (string) Scalar no further processing
wh_user password (string) Scalar no further processing
wh_user first_name (string) Scalar no further processing
wh_user last_name (string) Scalar no further processing
wh_user email (string) Scalar no further processing
wh_user city (string) Scalar no further processing
wh_user_session id (integer) Scalar no further processing
wh_user_session session_data (blob) Scalar no further processing
wh_user_session session_data_json (text) Scalar no further processing
----------------- -------------------------- --------------- -----------------------
Quelldaten definieren
Info
Mit dem "Analyze Profile" wird ermittelt, in welchen "unbeleuchteten Ecken" der Datenbank sich noch weitere personenbezogene Daten verstecken.
Wir verwenden darum die uns bereits bekannten personenbezogene Daten, welche wir im ersten Schritt identifiziert haben, um sie in der restlichen Datenbank aufzuspüren.
Wir haben personenbezogene Daten in folgenden Spalten identifiziert:
wh_log.ip
wh_user.username
wh_user.password
wh_user.first_name
wh_user.last_name
wh_user.email
wh_user.city
Du musst pseudify nun mitteilen, dass du die Daten in diesen Spalten als Quelldaten verwenden möchtest.
Dazu erweiterst du die Methode getTableDefinition()
im Profil.
public function getTableDefinition(): TableDefinition
{
$tableDefinition = new TableDefinition(identifier: $this->getIdentifier());
$tableDefinition
->addSourceTable(table: 'wh_log', columns: [
'ip',
])
->addSourceTable(table: 'wh_user', columns: [
'username',
'password',
'first_name',
'last_name',
'email',
'city',
])
;
return $tableDefinition;
}
Mit der Methode addSourceTable()
sagst du pseudify, in welcher Datenbanktabelle und in welchen Datenbankspalten die Quelldaten gesammelt werden sollen.
Pseudify wird dann automatisch in allen anderen Datenbankspalten der Datenbanktabellen nach Vorkommen der Quelldaten suchen und diese ausgeben.
Zuvor standen in der Ausgabe des Kommandos pseudify:debug:analyze test-profile
unter Search data in this tables
alle Datenbanktabellen und alle Datenbankspalten.
Nun werden dort nur noch die Datenbanktabellen und deren Datenbankspalten aufgelistet, welche nicht als Quelldaten mittels addSourceTable()
definiert wurden.
$ pseudify pseudify:debug:analyze test-profile
Analyzer profile "test-profile"
===============================
Basis configuration
-------------------
----------------------------------------------- -------
Key Value
----------------------------------------------- -------
Shown characters before and after the finding 10
----------------------------------------------- -------
Collect search data from this tables
------------------------------------
--------- --------------------- --------------- -----------------------
Table column data decoders data collectors
--------- --------------------- --------------- -----------------------
wh_log ip (string) Scalar default (scalar data)
wh_user username (string) Scalar default (scalar data)
wh_user password (string) Scalar default (scalar data)
wh_user first_name (string) Scalar default (scalar data)
wh_user last_name (string) Scalar default (scalar data)
wh_user email (string) Scalar default (scalar data)
wh_user city (string) Scalar default (scalar data)
--------- --------------------- --------------- -----------------------
Search data in this tables
--------------------------
----------------- -------------------------- --------------- -----------------------
Table column data decoders special data decoders
----------------- -------------------------- --------------- -----------------------
wh_log id (integer) Scalar no further processing
wh_log log_type (string) Scalar no further processing
wh_log log_data (blob) Scalar no further processing
wh_log log_message (text) Scalar no further processing
wh_meta_data id (integer) Scalar no further processing
wh_meta_data meta_data (blob) Scalar no further processing
wh_user id (integer) Scalar no further processing
wh_user_session id (integer) Scalar no further processing
wh_user_session session_data (blob) Scalar no further processing
wh_user_session session_data_json (text) Scalar no further processing
----------------- -------------------------- --------------- -----------------------
Enkodierte Daten als Quelldaten
Es kommt vor, dass Daten in Datenbankspalten in enkodierter Form vorliegen.
Das bedeutet, der kodierte Klartext muss während der Analyse dekodiert werden, um ihn als Quelldaten verwenden zu können.
Ähnlich wie unter "Enkodierte Daten durchsuchen" beschrieben, können auch die Datenbankspalten der Quelldaten dekodiert werden.
Der Methode SourceColumn::create()
kann mit dem Parameter dataType
ein Name eines Built-in Dekodierers mitgegeben werden.
Note
Wie unter "Mehrfach enkodierte Daten durchsuchen" beschrieben kann auch hier der ChainedEncoder
verwendet werden, um mehrfach enkodierte Daten zu dekodieren.
<?php
namespace Waldhacker\Pseudify\Profiles;
use Waldhacker\Pseudify\Core\Profile\Analyze\ProfileInterface;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\SourceColumn;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TableDefinition;
class TestAnalyzeProfile implements ProfileInterface
{
public function getIdentifier(): string
{
return 'test-profile';
}
public function getTableDefinition(): TableDefinition
{
$tableDefinition = new TableDefinition(identifier: $this->getIdentifier());
$tableDefinition
->addSourceTable(table: 'wh_test_table', columns: [
SourceColumn::create(identifier: 'wh_test_column', dataType: SourceColumn::DATA_TYPE_HEX),
])
;
return $tableDefinition;
}
}
Du siehst unter Collect search data from this tables
nun, dass unter data decoders
der Datenbankspalte session_data_json
der Name Hex
aufgelistet wird.
Dies signalisiert dir, dass die Daten mittels des HexEncoder dekodiert werden.
$ pseudify pseudify:debug:analyze test-profile
Analyzer profile "test-profile"
===============================
Basis configuration
-------------------
----------------------------------------------- -------
Key Value
----------------------------------------------- -------
Shown characters before and after the finding 10
----------------------------------------------- -------
Collect search data from this tables
------------------------------------
----------------- -------------------------- --------------- ----------------------
Table column data decoders data collectors
----------------- -------------------------- --------------- ----------------------
wh_test_table wh_test_column (text) Hex default (scalar data)
----------------- -------------------------- --------------- ----------------------
Search data in this tables
--------------------------
----------------- --------------------- --------------- -----------------------
Table column data decoders special data decoders
----------------- --------------------- --------------- -----------------------
wh_log id (integer) Scalar no further processing
wh_log log_type (string) Scalar no further processing
wh_log log_data (blob) Scalar no further processing
wh_log log_message (text) Scalar no further processing
wh_log ip (string) Scalar no further processing
wh_meta_data id (integer) Scalar no further processing
wh_meta_data meta_data (blob) Scalar no further processing
wh_user id (integer) Scalar no further processing
wh_user username (string) Scalar no further processing
wh_user password (string) Scalar no further processing
wh_user first_name (string) Scalar no further processing
wh_user last_name (string) Scalar no further processing
wh_user email (string) Scalar no further processing
wh_user city (string) Scalar no further processing
wh_user_session id (integer) Scalar no further processing
wh_user_session session_data (blob) Scalar no further processing
----------------- --------------------- --------------- -----------------------
Alternativ kann die ausgeschriebene Variante ->setEncoder(encoder: new HexEncoder())
verwendet werden:
<?php
namespace Waldhacker\Pseudify\Profiles;
use Waldhacker\Pseudify\Core\Profile\Analyze\ProfileInterface;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\SourceColumn;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TableDefinition;
class TestAnalyzeProfile implements ProfileInterface
{
public function getIdentifier(): string
{
return 'test-profile';
}
public function getTableDefinition(): TableDefinition
{
$tableDefinition = new TableDefinition(identifier: $this->getIdentifier());
$tableDefinition
->addSourceTable(table: 'wh_test_table', columns: [
SourceColumn::create(identifier: 'wh_test_column')->setEncoder(encoder: new HexEncoder()),
])
;
return $tableDefinition;
}
}
Suche optimieren
Ohne weitere Definition wird pseudify die Quelldaten in allen Datenbanktabellen und deren Datenbankspalten suchen, welche nicht als Quelldaten mittels addSourceTable()
bzw. addColumn()
definiert wurden.
Damit die Analyse nicht unnötig lange dauert, kann die Suche optimiert werden.
Ziel ist es in der Regel, nur "Text" (Strings) zu durchsuchen.
Datentypen ausschließen
Du kannst Spalten mit bestimmten Datentypen von der Suche ausschließen, um die Suchzeit zu verkürzen.
Beispielsweise ist es in den meisten Fällen nicht sinnvoll, Datenbankspalten vom Typ integer
zu durchsuchen.
Datentypen lassen sich für bestimmte oder für alle Tabellen ausschließen.
Sobald auf Tabellenebene Datentypen ausgeschlossen werden, kommt es für diese Tabelle nicht noch zusätzlich zum Ausschluss der global ausgeschlossenen Datentypen.
Info
Die Namen der Datentypen kannst du im Quellcode des Doctrine Projekts finden, z.B.: string
, integer
, datetime
etc.
Info
Es existiert die Konstante TableDefinition::COMMON_EXCLUED_TARGET_COLUMN_TYPES
, welche
alle Datentypen enthält, die in der Regel nicht durchsucht werden müssen.
Datentypen auf Tabellenebene ausschließen
Um in der Tabelle wh_meta_data
alle Spalten mit dem Datentyp integer
von der Suche auszuschließen, musst du die Methode getTableDefinition()
im Profil erweitern:
public function getTableDefinition(): TableDefinition
{
$tableDefinition = new TableDefinition(identifier: $this->getIdentifier());
$tableDefinition
// ...
->addTargetTable(table: 'wh_meta_data', excludeColumnTypes: [
'integer'
])
;
return $tableDefinition;
}
Die Methode addTargetTable()
teilt der automatischen Tabellenkonfiguration mit, dass du die Tabelle wh_meta_data
speziell konfigurieren möchtest.
Im Parameter excludeColumnTypes
kann ein Array von Datentypen übergeben werden, welche bei der Suche ausgeschlossen werden sollen.
Datentypen global ausschließen
Um global in allen Tabellen alle Spalten mit dem Datentyp integer
von der Suche auszuschließen, musst du die Methode getTableDefinition()
im Profil erweitern:
public function getTableDefinition(): TableDefinition
{
$tableDefinition = new TableDefinition(identifier: $this->getIdentifier());
$tableDefinition
->addSourceTable(table: 'wh_log', columns: [
'ip',
])
->addSourceTable(table: 'wh_user', columns: [
'username',
'password',
'first_name',
'last_name',
'email',
'city',
])
->excludeTargetColumnTypes(columnTypes: [
'integer'
])
;
return $tableDefinition;
}
Die Methode excludeTargetColumnTypes()
teilt der automatischen Tabellenkonfiguration mit,
dass in allen Tabellen (welche keine speziellen Ausschlüsse definiert bekommen haben) alle Spalten vom Datentyp integer
von der Suche ausgeschlossen werden sollen.
$ pseudify pseudify:debug:analyze test-profile
Analyzer profile "test-profile"
===============================
Basis configuration
-------------------
----------------------------------------------- -------
Key Value
----------------------------------------------- -------
Shown characters before and after the finding 10
----------------------------------------------- -------
Collect search data from this tables
------------------------------------
--------- --------------------- --------------- -----------------------
Table column data decoders data collectors
--------- --------------------- --------------- -----------------------
wh_log ip (string) Scalar default (scalar data)
wh_user username (string) Scalar default (scalar data)
wh_user password (string) Scalar default (scalar data)
wh_user first_name (string) Scalar default (scalar data)
wh_user last_name (string) Scalar default (scalar data)
wh_user email (string) Scalar default (scalar data)
wh_user city (string) Scalar default (scalar data)
--------- --------------------- --------------- -----------------------
Search data in this tables
--------------------------
----------------- -------------------------- --------------- -----------------------
Table column data decoders special data decoders
----------------- -------------------------- --------------- -----------------------
wh_log log_type (string) Scalar no further processing
wh_log log_data (blob) Scalar no further processing
wh_log log_message (text) Scalar no further processing
wh_meta_data meta_data (blob) Scalar no further processing
wh_user_session session_data (blob) Scalar no further processing
wh_user_session session_data_json (text) Scalar no further processing
----------------- -------------------------- --------------- -----------------------
Du siehst unter Search data in this tables
nun, dass alle integer
Spalten verschwunden sind.
In der Regel bietet es sich an, folgende Zeile im Profil zu integrieren, um global alle Datentypen auszuschließen, bei denen es nicht sinnvoll ist, sie zu durchsuchen:
->excludeTargetColumnTypes(columnTypes: TableDefinition::COMMON_EXCLUED_TARGET_COLUMN_TYPES)
Datenbankspalten ausschließen
Die automatische Tabellenkonfiguration wird Datenbankspalten immer zuerst anhand des Datentyps von der Suche ausschließen.
Zusätzlich kannst du im Profil auf Tabellenebene definieren, dass Datenbankspalten anhand ihres Namens von der Suche ausgeschlossen werden sollen.
Dazu musst du die Methode getTableDefinition()
im Profil erweitern:
public function getTableDefinition(): TableDefinition
{
$tableDefinition = new TableDefinition(identifier: $this->getIdentifier());
$tableDefinition
->addSourceTable(table: 'wh_log', columns: [
'ip',
])
->addSourceTable(table: 'wh_user', columns: [
'username',
'password',
'first_name',
'last_name',
'email',
'city',
])
->excludeTargetColumnTypes(columnTypes: TableDefinition::COMMON_EXCLUED_TARGET_COLUMN_TYPES)
->addTargetTable(table: 'wh_log', excludeColumns: [
'log_message',
])
;
return $tableDefinition;
}
Die Methode addTargetTable()
teilt der automatischen Tabellenkonfiguration mit, dass du die Tabelle wh_log
speziell konfigurieren möchtest.
Im Parameter excludeColumns
kann ein Array von Spaltennamen übergeben werden, welche bei der Suche ausgeschlossen werden sollen.
$ pseudify pseudify:debug:analyze test-profile
Analyzer profile "test-profile"
===============================
Basis configuration
-------------------
----------------------------------------------- -------
Key Value
----------------------------------------------- -------
Shown characters before and after the finding 10
----------------------------------------------- -------
Collect search data from this tables
------------------------------------
--------- --------------------- --------------- -----------------------
Table column data decoders data collectors
--------- --------------------- --------------- -----------------------
wh_log ip (string) Scalar default (scalar data)
wh_user username (string) Scalar default (scalar data)
wh_user password (string) Scalar default (scalar data)
wh_user first_name (string) Scalar default (scalar data)
wh_user last_name (string) Scalar default (scalar data)
wh_user email (string) Scalar default (scalar data)
wh_user city (string) Scalar default (scalar data)
--------- --------------------- --------------- -----------------------
Search data in this tables
--------------------------
----------------- -------------------------- --------------- -----------------------
Table column data decoders special data decoders
----------------- -------------------------- --------------- -----------------------
wh_log log_type (string) Scalar no further processing
wh_log log_data (blob) Scalar no further processing
wh_meta_data meta_data (blob) Scalar no further processing
wh_user_session session_data (blob) Scalar no further processing
wh_user_session session_data_json (text) Scalar no further processing
----------------- -------------------------- --------------- -----------------------
Du siehst unter Search data in this tables
nun, dass die Spalte log_message
der Tabelle wh_log
verschwunden ist.
Tabellen ausschließen
Du kannst ganze Tabellen von der Suche ausschließen, um die Suchzeit zu verkürzen.
Dies kann mit der Methode excludeTargetTables()
erledigt werden.
public function getTableDefinition(): TableDefinition
{
$tableDefinition = new TableDefinition(identifier: $this->getIdentifier());
$tableDefinition
->addSourceTable(table: 'wh_log', columns: [
'ip',
])
->excludeTargetColumnTypes(columnTypes: TableDefinition::COMMON_EXCLUED_TARGET_COLUMN_TYPES)
->excludeTargetTables(tables: [
'wh_user',
])
;
return $tableDefinition;
}
Wie du siehst, wird die Tabelle wh_user
nicht mehr unter Search data in this tables
aufgelistet.
$ pseudify pseudify:debug:analyze test-profile
Analyzer profile "test-profile"
===============================
Basis configuration
-------------------
----------------------------------------------- -------
Key Value
----------------------------------------------- -------
Shown characters before and after the finding 10
----------------------------------------------- -------
Collect search data from this tables
------------------------------------
-------- ------------- --------------- -----------------------
Table column data decoders data collectors
-------- ------------- --------------- -----------------------
wh_log ip (string) Scalar default (scalar data)
-------- ------------- --------------- -----------------------
Search data in this tables
--------------------------
----------------- ---------------------------- --------------- -----------------------
Table column data decoders special data decoders
----------------- ---------------------------- --------------- -----------------------
wh_log log_type (string) Scalar no further processing
wh_log log_data (blob) Scalar no further processing
wh_log log_data_plaintext (blob) Scalar no further processing
wh_log log_message (text) Scalar no further processing
wh_meta_data meta_data (blob) Scalar no further processing
wh_meta_data meta_data_plaintext (blob) Scalar no further processing
wh_user_session session_data (blob) Scalar no further processing
----------------- ---------------------------- --------------- -----------------------
In den auszuschließenden Tabellennamen können reguläre Ausdrücke verwendet werden, z.B.: wh_user.*
.
Somit ist es z.B. möglich, mehrere Tabellen mit einem Ausdruck auszuschließen:
public function getTableDefinition(): TableDefinition
{
$tableDefinition = new TableDefinition(identifier: $this->getIdentifier());
$tableDefinition
->addSourceTable(table: 'wh_log', columns: [
'ip',
])
->excludeTargetColumnTypes(columnTypes: TableDefinition::COMMON_EXCLUED_TARGET_COLUMN_TYPES)
->excludeTargetTables(tables: [
'wh_user.*',
])
;
return $tableDefinition;
}
Wie du siehst, werden die Tabellen wh_user
und die Tabelle wh_user_session
nicht mehr unter Search data in this tables
aufgelistet.
$ pseudify pseudify:debug:analyze test-profile
Analyzer profile "test-profile"
===============================
Basis configuration
-------------------
----------------------------------------------- -------
Key Value
----------------------------------------------- -------
Shown characters before and after the finding 10
----------------------------------------------- -------
Collect search data from this tables
------------------------------------
-------- ------------- --------------- -----------------------
Table column data decoders data collectors
-------- ------------- --------------- -----------------------
wh_log ip (string) Scalar default (scalar data)
-------- ------------- --------------- -----------------------
Search data in this tables
--------------------------
-------------- ---------------------------- --------------- -----------------------
Table column data decoders special data decoders
-------------- ---------------------------- --------------- -----------------------
wh_log log_type (string) Scalar no further processing
wh_log log_data (blob) Scalar no further processing
wh_log log_data_plaintext (blob) Scalar no further processing
wh_log log_message (text) Scalar no further processing
wh_meta_data meta_data (blob) Scalar no further processing
wh_meta_data meta_data_plaintext (blob) Scalar no further processing
-------------- ---------------------------- --------------- -----------------------
Enkodierte Daten durchsuchen
Es kommt vor, dass Daten in Datenbankspalten in enkodierter Form vorliegen.
Das bedeutet, der kodierte Klartext muss während der Analyse dekodiert werden.
In unserem Beispiel enthält die Datenbankspalte log_data
der Tabelle wh_log
und die Datenbankspalte meta_data
der Tabelle wh_meta_data
enkodierte Daten.
Wie diese Daten enkodiert sind, musst du anhand des Quellcodes oder der Dokumentation der Applikation, welche die Datenbank verwendet, herausfinden.
In unserem Beispiel sind die Daten der Datenbankspalte log_data
(mit log_type
= bar
) wie folgt kodiert.
Datenbankdaten:
613a323a7b693a303b733a31353a223133322e3138382e3234312e313535223b733a343a2275736572223b4f3a383a22737464436c617373223a353a7b733a383a22757365724e616d65223b733a373a22637972696c3036223b733a383a226c6173744e616d65223b733a383a22486f6d656e69636b223b733a353a22656d61696c223b733a32313a22636c696e746f6e3434406578616d706c652e6e6574223b733a323a226964223b693a39313b733a343a2275736572223b523a333b7d7d
Kodierung durch die Applikation:
$plaintext = 'a:2:{i:0;s:15:"132.188.241.155";s:4:"user";O:8:"stdClass":5:{s:8:"userName";s:7:"cyril06";s:8:"lastName";s:8:"Homenick";s:5:"email";s:21:"clinton44@example.net";s:2:"id";i:91;s:4:"user";R:3;}}';
$logData = bin2hex($plaintext);
Damit pseudify die Daten ($plaintext
) durchsuchen kann, müssen die Daten erst von hexadezimaler Darstellungsform zum Binärformat umgewandelt werden.
Hierzu kann der Definition einer Datenbankspalte (TargetColumn::create()
) der Datentyp (Parameter dataType
) übergeben werden.
<?php
namespace Waldhacker\Pseudify\Profiles;
use Waldhacker\Pseudify\Core\Profile\Analyze\ProfileInterface;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TableDefinition;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TargetColumn;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TargetTable;
class TestAnalyzeProfile implements ProfileInterface
{
public function getIdentifier(): string
{
return 'test-profile';
}
public function getTableDefinition(): TableDefinition
{
$tableDefinition = new TableDefinition(identifier: $this->getIdentifier());
$tableDefinition
// ...
->addTargetTable(table: TargetTable::create(identifier: 'wh_log',
columns: [
TargetColumn::create(identifier: 'log_data', dataType: TargetColumn::DATA_TYPE_HEX),
]
))
;
return $tableDefinition;
}
}
Der Methode TargetColumn::create()
kann mit dem Parameter dataType
ein Name eines Built-in Dekodierers mitgegeben werden.
Dies ist gleichbedeutend mit der ausgeschriebenen Variante ->setEncoder(encoder: new HexEncoder())
.
<?php
namespace Waldhacker\Pseudify\Profiles;
use Waldhacker\Pseudify\Core\Processor\Encoder\HexEncoder;
use Waldhacker\Pseudify\Core\Profile\Analyze\ProfileInterface;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TableDefinition;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TargetColumn;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TargetTable;
class TestAnalyzeProfile implements ProfileInterface
{
public function getIdentifier(): string
{
return 'test-profile';
}
public function getTableDefinition(): TableDefinition
{
$tableDefinition = new TableDefinition(identifier: $this->getIdentifier());
$tableDefinition
// ...
->addTargetTable(table: TargetTable::create(identifier: 'wh_log',
columns: [
TargetColumn::create(identifier: 'log_data')->setEncoder(encoder: new HexEncoder()),
]
))
;
return $tableDefinition;
}
}
Beim Durchsuchen der Datenbankspalte log_data
wird pseudify die Daten der Datenbankspalte dann immer mittels der Methode decode()
des HexEncoder verarbeiten und anschließend das Resultat durchsuchen.
$ pseudify pseudify:debug:analyze test-profile
Analyzer profile "test-profile"
===============================
Basis configuration
-------------------
----------------------------------------------- -------
Key Value
----------------------------------------------- -------
Shown characters before and after the finding 10
----------------------------------------------- -------
Collect search data from this tables
------------------------------------
--------- --------------------- --------------- -----------------------
Table column data decoders data collectors
--------- --------------------- --------------- -----------------------
wh_log ip (string) Scalar default (scalar data)
wh_user username (string) Scalar default (scalar data)
wh_user password (string) Scalar default (scalar data)
wh_user first_name (string) Scalar default (scalar data)
wh_user last_name (string) Scalar default (scalar data)
wh_user email (string) Scalar default (scalar data)
wh_user city (string) Scalar default (scalar data)
--------- --------------------- --------------- -----------------------
Search data in this tables
--------------------------
----------------- -------------------------- --------------- -----------------------
Table column data decoders special data decoders
----------------- -------------------------- --------------- -----------------------
wh_log log_data (blob) Hex no further processing
wh_log log_type (string) Scalar no further processing
wh_log log_message (text) Scalar no further processing
wh_meta_data meta_data (blob) Scalar no further processing
wh_user_session session_data (blob) Scalar no further processing
wh_user_session session_data_json (text) Scalar no further processing
----------------- -------------------------- --------------- -----------------------
Du siehst unter Search data in this tables
nun, dass unter data decoders
der Datenbankspalte log_data
der Name Hex
aufgelistet wird.
Dies signalisiert dir, dass die Daten mittels des HexEncoder dekodiert werden.
Mehrfach enkodierte Daten durchsuchen
Es kommt vor, dass Daten in Datenbankspalten in mehrfach enkodierter Form abgespeichert sind.
In unserem Beispiel sind die Daten der Datenbankspalte meta_data
so kodiert:
$plaintext = 'a:3:{s:4:"key1";a:9:{s:2:"id";i:5;s:8:"username";s:13:"howell.damien";s:8:"password";s:92:"$argon2i$v=19$m=8,t=1,p=1$ZldmOWd2TDJRb3FTNVpGNA$ORIwp6yekRx02mqM4WCTVhllgXpUpuFJZ1MmbYwAMXs";s:18:"password_hash_type";s:8:"argon2id";s:18:"password_plaintext";s:13:"nF5;06?nsS/nE";s:10:"first_name";s:7:"Mckayla";s:9:"last_name";s:11:"Stoltenberg";s:5:"email";s:24:"conn.abigale@example.net";s:4:"city";s:11:"Dorothyfort";}s:4:"key2";a:2:{s:2:"id";i:3;s:12:"session_data";s:41:"a:1:{s:7:"last_ip";s:13:"244.166.32.78";}";}s:4:"key3";a:1:{s:4:"key4";s:12:"139.81.0.139";}}';
$meta_data = bin2hex(gzencode($plaintext, 5, ZLIB_ENCODING_GZIP));
Damit pseudify die Daten ($plaintext
) durchsuchen kann, müssen die Daten erst von hexadezimaler Darstellungsform in ein Binärformat umgewandelt werden und dann müssen die Binärdaten noch im ZLIB-Format dekomprimiert werden.
Um mehrfache Dekodierung durchzuführen, kann der ChainedEncoder
verwendet werden.
Mit dem ChainedEncoder können mehrere Dekodierer konfiguriert werden, welche dann der Reihe nach die Daten dekodieren.
<?php
namespace Waldhacker\Pseudify\Profiles;
use Waldhacker\Pseudify\Core\Processor\Encoder\ChainedEncoder;
use Waldhacker\Pseudify\Core\Processor\Encoder\GzEncodeEncoder;
use Waldhacker\Pseudify\Core\Processor\Encoder\HexEncoder;
use Waldhacker\Pseudify\Core\Profile\Analyze\ProfileInterface;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TableDefinition;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TargetColumn;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TargetTable;
class TestAnalyzeProfile implements ProfileInterface
{
public function getIdentifier(): string
{
return 'test-profile';
}
public function getTableDefinition(): TableDefinition
{
$tableDefinition = new TableDefinition(identifier: $this->getIdentifier());
$tableDefinition
// ...
->addTargetTable(table: TargetTable::create(identifier: 'wh_meta_data',
columns: [
TargetColumn::create(identifier: 'meta_data')->setEncoder(encoder: new ChainedEncoder(encoders: [
new HexEncoder(),
new GzEncodeEncoder(defaultContext: [
GzEncodeEncoder::ENCODE_LEVEL => 5,
GzEncodeEncoder::ENCODE_ENCODING => ZLIB_ENCODING_GZIP,
]),
])),
]
))
;
return $tableDefinition;
}
}
Beim Durchsuchen der Datenbankspalte meta_data
der Tabelle wh_meta_data
wird pseudify die Daten der Datenbankspalte dann zuerst mittels der Methode decode()
des HexEncoder
und dann mittels der Methode decode()
des GzEncodeEncoder verarbeiten und anschließend das Resultat durchsuchen.
$ pseudify pseudify:debug:analyze test-profile
Analyzer profile "test-profile"
===============================
Basis configuration
-------------------
----------------------------------------------- -------
Key Value
----------------------------------------------- -------
Shown characters before and after the finding 10
----------------------------------------------- -------
Collect search data from this tables
------------------------------------
--------- --------------------- --------------- -----------------------
Table column data decoders data collectors
--------- --------------------- --------------- -----------------------
wh_log ip (string) Scalar default (scalar data)
wh_user username (string) Scalar default (scalar data)
wh_user password (string) Scalar default (scalar data)
wh_user first_name (string) Scalar default (scalar data)
wh_user last_name (string) Scalar default (scalar data)
wh_user email (string) Scalar default (scalar data)
wh_user city (string) Scalar default (scalar data)
--------- --------------------- --------------- -----------------------
Search data in this tables
--------------------------
----------------- -------------------------- --------------- -----------------------
Table column data decoders special data decoders
----------------- -------------------------- --------------- -----------------------
wh_meta_data meta_data (blob) Hex>GzEncode no further processing
wh_log log_type (string) Scalar no further processing
wh_log log_data (blob) Scalar no further processing
wh_log log_message (text) Scalar no further processing
wh_user_session session_data (blob) Scalar no further processing
wh_user_session session_data_json (text) Scalar no further processing
----------------- -------------------------- --------------- -----------------------
Du siehst unter Search data in this tables
nun, dass unter data decoders
der Datenbankspalte wh_meta_data
die Namen Hex>GzEncode
aufgelistet wird.
Dies signalisiert dir, dass die Daten zuerst mittels des HexEncoder dekodiert werden und dann mittels des GzEncodeEncoder.
Unterschiedlich enkodierte Daten durchsuchen
Es kommt vor, dass Daten in Datenbankspalten in unterschiedlich enkodierter Form abgespeichert sind.
Anhand von Bedingungen speichern Applikationen die Daten in verschiedenen Formen ab.
In unserem Beispiel sind die Daten der Datenbankspalte log_data
wie folgt kodiert, wenn die Datenbankspalte log_type
den Wert bar
enthält.
Datenbankdaten:
613a323a7b693a303b733a31353a223133322e3138382e3234312e313535223b733a343a2275736572223b4f3a383a22737464436c617373223a353a7b733a383a22757365724e616d65223b733a373a22637972696c3036223b733a383a226c6173744e616d65223b733a383a22486f6d656e69636b223b733a353a22656d61696c223b733a32313a22636c696e746f6e3434406578616d706c652e6e6574223b733a323a226964223b693a39313b733a343a2275736572223b523a333b7d7d
Kodierung durch die Applikation:
$plaintext = 'a:2:{i:0;s:15:"132.188.241.155";s:4:"user";O:8:"stdClass":5:{s:8:"userName";s:7:"cyril06";s:8:"lastName";s:8:"Homenick";s:5:"email";s:21:"clinton44@example.net";s:2:"id";i:91;s:4:"user";R:3;}}';
$logData = bin2hex($plaintext);
Damit pseudify die Daten ($plaintext
) durchsuchen kann, müssen die Daten erst von hexadezimaler Darstellungsform zum Binärformat umgewandelt werden.
Die Daten der Datenbankspalte log_data
sind wie folgt kodiert, wenn die Datenbankspalte log_type
den Wert foo
enthält.
Datenbankdaten:
65794a3163325679546d46745a534936496e4a76626d46735a4738784e534973496d567459576c73496a6f6962574e6a624856795a5335765a6d5673615746415a586868625842735a53356a623230694c434a7359584e30546d46745a534936496b746c5a577870626d63694c434a7063434936496a457a4d6a45364e54646d597a6f304e6a42694f6d51305a4441365a44677a5a6a706a4d6a41774f6a52694f6d5978597a676966513d3d
Kodierung durch die Applikation:
$plaintext = '{"userName":"ronaldo15","email":"mcclure.ofelia@example.com","lastName":"Keeling","ip":"1321:57fc:460b:d4d0:d83f:c200:4b:f1c8"}';
$logData = bin2hex(base64_encode($logDataPlaintext));
Damit pseudify die Daten ($plaintext
) durchsuchen kann, müssen die Daten erst von hexadezimaler Darstellungsform zum Binärformat umgewandelt werden und dann im Base64-Format dekodiert werden.
In beiden Fällen (log_type
== foo
und log_type
== bar
) können die Daten zuerst von hexadezimaler Darstellungsform zum Binärformat umgewandelt werden.
Wenn die Datenbankspalte log_type
== foo
enthält, müssen die Daten dann zusätzlich noch base64 dekodiert werden.
Dies kann wie folgt modelliert werden:
<?php
namespace Waldhacker\Pseudify\Profiles;
use Waldhacker\Pseudify\Core\Processor\Encoder\Base64Encoder;
use Waldhacker\Pseudify\Core\Processor\Processing\Analyze\TargetDataDecoderContext;
use Waldhacker\Pseudify\Core\Processor\Processing\DataProcessing;
use Waldhacker\Pseudify\Core\Profile\Analyze\ProfileInterface;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TableDefinition;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TargetColumn;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TargetTable;
class TestAnalyzeProfile implements ProfileInterface
{
public function getIdentifier(): string
{
return 'test-profile';
}
public function getTableDefinition(): TableDefinition
{
$tableDefinition = new TableDefinition(identifier: $this->getIdentifier());
$tableDefinition
// ...
->addTargetTable(table: TargetTable::create(identifier: 'wh_log',
columns: [
TargetColumn::create(identifier: 'log_data', dataType: TargetColumn::DATA_TYPE_HEX)
->addDataProcessing(dataProcessing: new DataProcessing(identifier: 'decode conditional log data',
processor: function (TargetDataDecoderContext $context): void {
$row = $context->getDatebaseRow();
if ('foo' !== $row['log_type']) {
return;
}
$data = $context->getDecodedData();
$encoder = new Base64Encoder();
$logData = $encoder->decode(data: $data);
$context->setDecodedData(decodedData: $logData);
}
)),
]
))
;
return $tableDefinition;
}
}
Mit der Methode addDataProcessing()
können zusätzlich zur Dekodierung der Daten weitere manuelle Datentransformationen programmiert werden.
Die DataProcessings
werden nach der Dekodierung der Daten aufgeführt.
Es können beliebig viele DataProcessings
definiert werden, welche nacheinander abgearbeitet werden.
Ein DataProcessing
besteht aus einer eindeutigen Identifizierung pro Datenbankspalte (Parameter identifier
) und
einer anonymen Funktion (Parameter processor
).
Die anonyme Funktion wird mit einem Parameter context
vom Typ TargetDataDecoderContext
aufgerufen.
Durch den TargetDataDecoderContext
können diverse Informationen über den zu verarbeitenden Datensatz erhalten werden:
$context->getRawData()
: Die Originaldaten der Datenbankspalte$context->getDecodedData()
: Die Daten der Datenbankspalte nach der Dekodierung$context->getDatebaseRow()
: Enthält die Originaldaten aller Datenbankspalten der Datenbankzeile die verarbeitet wird
Mit der Methode setDecodedData()
können manuell prozessierte Daten an pseudify übergeben werden.
Diese manuell prozessierte Daten werden dann von der Analyse durchsucht.
In unserem Beispiel ermitteln wir anhand des Wertes der Datenbankspalte log_type
ob die Daten noch weiter mittels base64 dekodiert werden müssen.
Ist der Wert von log_type
nicht foo
, so wird durch das return
Statement nichts weiter prozessiert.
Ist der Wert von log_type
gleich foo
, so werden die Daten mittels des Base64Encoder() dekodiert und durch die Methode setDecodedData()
an pseudify zurückgeschrieben.
$ pseudify pseudify:debug:analyze test-profile
Analyzer profile "test-profile"
===============================
Basis configuration
-------------------
----------------------------------------------- -------
Key Value
----------------------------------------------- -------
Shown characters before and after the finding 10
----------------------------------------------- -------
Collect search data from this tables
------------------------------------
--------- --------------------- --------------- -----------------------
Table column data decoders data collectors
--------- --------------------- --------------- -----------------------
wh_log ip (string) Scalar default (scalar data)
wh_user username (string) Scalar default (scalar data)
wh_user password (string) Scalar default (scalar data)
wh_user first_name (string) Scalar default (scalar data)
wh_user last_name (string) Scalar default (scalar data)
wh_user email (string) Scalar default (scalar data)
wh_user city (string) Scalar default (scalar data)
--------- --------------------- --------------- -----------------------
Search data in this tables
--------------------------
----------------- -------------------------- --------------- -----------------------------
Table column data decoders special data decoders
----------------- -------------------------- --------------- -----------------------------
wh_log log_data (blob) Hex decode conditional log data
wh_log log_type (string) Scalar no further processing
wh_log log_message (text) Scalar no further processing
wh_meta_data meta_data (blob) Scalar no further processing
wh_user_session session_data (blob) Scalar no further processing
wh_user_session session_data_json (text) Scalar no further processing
----------------- -------------------------- --------------- -----------------------------
Du siehst unter Search data in this tables
nun, dass unter data decoders
der Datenbankspalte wh_log
der Name Hex
aufgelistet wird.
Dies signalisiert dir, dass die Daten zuerst mittels des HexEncoder dekodiert werden.
Unter special data decoders
wird das DataProcessing
mit der Identifizierung decode conditional log data
aufgelistet.
Dies signalisiert dir, dass nach der Dekodierung der Daten diese zusätzlich mittels des angegebenen DataProcessing
verarbeitet werden.
JSON Daten normalisieren
Liegen zu durchsuchende Daten im JSON-Format in der Datenbank,
sollten diese normalisiert werden, um sie für pseudify vollständig durchsuchbar zu machen.
Beispielsweise werden UTF-8 Zeichen im JSON-Format maskiert, so ist beispielsweise ein Ö
im JSON-Format durch die Zeichenkette \u00d6
maskiert.
Beispieldatensatz:
"{"oldRecord":{"bodytext":"<p>In 2023 sind folgende \u00d6ffentlichkeitsaktionen geplant:<\/p>"}}"
Angenommen pseudify soll nach dem Vorkommen des Wortes Öffentlichkeitsaktionen
suchen, so wird pseudify dies im Beispieldatensatz durch die Maskierung nicht finden.
Um den JSON-String zu normalisieren und ihn so aussehen zu lassen:
"{"oldRecord":{"bodytext":"<p>In 2023 sind folgende Öffentlichkeitsaktionen geplant:</p>"}}"
existiert das DataProcessing
namens normalizedJsonString()
.
Das Hinzufügen dieses DataProcessing
mittels
->addDataProcessing(dataProcessing: TargetDataDecoderPreset::normalizedJsonString())
zu einer Datenbankspalte, welche JSON Datenstrukturen enthält, normalisiert den JSON-String und macht ihn für pseudify durchsuchbar.
<?php
namespace Waldhacker\Pseudify\Profiles;
use Waldhacker\Pseudify\Core\Processor\Processing\Analyze\TargetDataDecoderPreset;
use Waldhacker\Pseudify\Core\Profile\Analyze\ProfileInterface;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TableDefinition;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TargetColumn;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TargetTable;
class TestAnalyzeProfile implements ProfileInterface
{
public function getIdentifier(): string
{
return 'test-profile';
}
public function getTableDefinition(): TableDefinition
{
$tableDefinition = new TableDefinition(identifier: $this->getIdentifier());
$tableDefinition
// ...
->addTargetTable(table: TargetTable::create(identifier: 'wh_log',
columns: [
TargetColumn::create(identifier: 'log_message')->addDataProcessing(dataProcessing: TargetDataDecoderPreset::normalizedJsonString()),
]
))
;
return $tableDefinition;
}
}
Nicht-Skalare Quelldaten definieren
Manchmal ist es notwendig, Daten aus komplexen Datenstrukturen als Quelldaten zu definieren.
Als Beispiel möchten wir Daten aus der Datenbankspalte session_data_json
der Tabelle wh_user_session
verwenden, um sie als Quelldaten zu verwenden.
session_data_json
enthält einen String im JSON-Format. In diesem gibt es eine Eigenschaft namens data
bestehend aus einem Array mit der Eigenschaft last_ip
welche wir als Quelldaten verwenden möchten.
{"data": {"last_ip":"107.66.23.195"}}
Der Methode SourceColumn::create()
kann mit dem Parameter dataType
ein Name eines Built-in Dekodierers mitgegeben werden.
Note
Wie unter "Mehrfach enkodierte Daten durchsuchen" beschrieben kann auch hier der ChainedEncoder
verwendet werden, um mehrfach enkodierte Daten zu dekodieren.
Mit der Methode addDataProcessing()
kann nun definiert werden, welche Daten aus der dekodierten Datenstruktur extrahiert werden sollen, um sie als Quelldaten zu verwenden.
Die DataProcessings
werden nach der Dekodierung der Daten ausgeführt.
Es können beliebig viele DataProcessings
definiert werden, welche nacheinander abgearbeitet werden.
Ein DataProcessing
besteht aus einer eindeutigen Identifizierung pro Datenbankspalte (Parameter identifier
) und einer anonymen Funktion (Parameter processor
).
Die anonyme Funktion wird mit einem Parameter context
vom Typ SourceDataCollectorContext
aufgerufen.
Durch den SourceDataCollectorContext
können diverse Informationen über den zu verarbeitenden Datensatz erhalten werden:
$context->getRawData()
: Die Originaldaten der Datenbankspalte$context->getDecodedData()
: Die Daten der Datenbankspalte nach der Dekodierung$context->getDatebaseRow()
: Enthält die Originaldaten aller Datenbankspalten der Datenbankzeile die verarbeitet wird
Mit der Methode addCollectedData()
können die extrahierten Daten als Quelldaten an pseudify übergeben werden.
Die Methode addCollectedData()
kann beliebig oft verwendet werden, um beliebige viele Quelldaten an pseudify zu übergeben.
Der Methode addCollectedData()
kann entweder ein String übergeben werden , oder ein eindimensionales Array. Wird ein Array übergeben, so werden alle darin befindlichen skalaren Daten extrahiert und als Quelldaten an pseudify übergeben.
Info
Wird kein DataProcessing
definiert, so wird automatisch das Standard-DataProcessing SourceDataCollectorPreset::scalarData()
verwendet.
Dieses sammelt die Daten aus einer Datenbankspalte nur dann, wenn der Inhalt mehr als 2 Zeichen beinhaltet.
<?php
namespace Waldhacker\Pseudify\Profiles;
use Waldhacker\Pseudify\Core\Processor\Processing\Analyze\SourceDataCollectorContext;
use Waldhacker\Pseudify\Core\Processor\Processing\DataProcessing;
use Waldhacker\Pseudify\Core\Profile\Analyze\ProfileInterface;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\SourceColumn;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TableDefinition;
class TestAnalyzeProfile implements ProfileInterface
{
public function getIdentifier(): string
{
return 'test-profile';
}
public function getTableDefinition(): TableDefinition
{
$tableDefinition = new TableDefinition(identifier: $this->getIdentifier());
$tableDefinition
->addSourceTable(table: 'wh_user_session', columns: [
SourceColumn::create(identifier: 'session_data_json', dataType: SourceColumn::DATA_TYPE_JSON)
->addDataProcessing(dataProcessing: new DataProcessing(identifier: 'extract ip address',
processor: function (SourceDataCollectorContext $context): void {
$data = $context->getDecodedData();
$context->addCollectedData(data: $data['data']['last_ip']);
}
)),
])
;
return $tableDefinition;
}
}
Du siehst unter Collect search data from this tables
nun, dass unter data decoders
der Datenbankspalte session_data_json
der Name Json
aufgelistet wird.
Dies signalisiert dir, dass die Daten mittels des JsonEncoder dekodiert werden.
Unter data collectors
wird das DataProcessing
mit der Identifizierung extract ip address
aufgelistet.
Dies signalisiert dir, dass nach der Dekodierung der Daten diese zusätzlich mittels des angegebenen DataProcessing
gesammelt werden.
$ pseudify pseudify:debug:analyze test-profile
Analyzer profile "test-profile"
===============================
Basis configuration
-------------------
----------------------------------------------- -------
Key Value
----------------------------------------------- -------
Shown characters before and after the finding 10
----------------------------------------------- -------
Collect search data from this tables
------------------------------------
----------------- -------------------------- --------------- --------------------
Table column data decoders data collectors
----------------- -------------------------- --------------- --------------------
wh_user_session session_data_json (text) Json extract ip address
----------------- -------------------------- --------------- --------------------
Search data in this tables
--------------------------
----------------- --------------------- --------------- -----------------------
Table column data decoders special data decoders
----------------- --------------------- --------------- -----------------------
wh_log id (integer) Scalar no further processing
wh_log log_type (string) Scalar no further processing
wh_log log_data (blob) Scalar no further processing
wh_log log_message (text) Scalar no further processing
wh_log ip (string) Scalar no further processing
wh_meta_data id (integer) Scalar no further processing
wh_meta_data meta_data (blob) Scalar no further processing
wh_user id (integer) Scalar no further processing
wh_user username (string) Scalar no further processing
wh_user password (string) Scalar no further processing
wh_user first_name (string) Scalar no further processing
wh_user last_name (string) Scalar no further processing
wh_user email (string) Scalar no further processing
wh_user city (string) Scalar no further processing
wh_user_session id (integer) Scalar no further processing
wh_user_session session_data (blob) Scalar no further processing
----------------- --------------------- --------------- -----------------------
Benutzerdefinierte Quelldaten definieren
Es ist möglich benutzerdefinierte Quelldaten zu definieren die sich nicht auf Datenbankspalten beziehen.
Mit der Methode addSourceString()
können Strings als Quelldaten definiert werden.
<?php
namespace Waldhacker\Pseudify\Profiles;
use Waldhacker\Pseudify\Core\Profile\Analyze\ProfileInterface;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TableDefinition;
class TestAnalyzeProfile implements ProfileInterface
{
public function getIdentifier(): string
{
return 'test-profile';
}
public function getTableDefinition(): TableDefinition
{
$tableDefinition = new TableDefinition(identifier: $this->getIdentifier());
$tableDefinition
->addSourceTable(table: 'wh_log', columns: [
'ip',
])
->addSourceTable(table: 'wh_user', columns: [
'username',
'password',
'first_name',
'last_name',
'email',
'city',
])
->addSourceString(string: 'example.com')
->addSourceString(string: 'regex:(?:[0-9]{1,3}\.){3}[0-9]{1,3}')
// ...
;
return $tableDefinition;
}
}
Du siehst unter Search for this strings
nun die benutzerdefinierten Strings nach denen in der Datenbank gesucht wird.
Alternativ zu statischen Werten ist es möglich, reguläre Ausdrücke für die Suche zu verwenden.
Ein regulärer Ausdruck muss durch den Präfix regex:
gekennzeichnet werden und der PCRE-Regex-Syntax folgen.
Mit regex:(?:[0-9]{1,3}\.){3}[0-9]{1,3}
kann beispielsweise nach IPv4 Adressen gesucht werden.
$ pseudify pseudify:debug:analyze test-profile
Analyzer profile "test-profile"
===============================
Basis configuration
-------------------
----------------------------------------------- -------
Key Value
----------------------------------------------- -------
Shown characters before and after the finding 10
----------------------------------------------- -------
Collect search data from this tables
------------------------------------
--------- --------------------- --------------- -----------------------
Table column data decoders data collectors
--------- --------------------- --------------- -----------------------
wh_log ip (string) Scalar default (scalar data)
wh_user username (string) Scalar default (scalar data)
wh_user password (string) Scalar default (scalar data)
wh_user first_name (string) Scalar default (scalar data)
wh_user last_name (string) Scalar default (scalar data)
wh_user email (string) Scalar default (scalar data)
wh_user city (string) Scalar default (scalar data)
--------- --------------------- --------------- -----------------------
Search for this strings
-----------------------
-------------------------------------
String
-------------------------------------
example.com
regex:(?:[0-9]{1,3}\.){3}[0-9]{1,3}
-------------------------------------
Search data in this tables
--------------------------
----------------- -------------------------- --------------- -----------------------
Table column data decoders special data decoders
----------------- -------------------------- --------------- -----------------------
wh_log log_type (string) Scalar no further processing
wh_log log_data (blob) Scalar no further processing
wh_log log_message (text) Scalar no further processing
wh_meta_data meta_data (blob) Scalar no further processing
wh_user_session session_data (blob) Scalar no further processing
wh_user_session session_data_json (text) Scalar no further processing
----------------- -------------------------- --------------- -----------------------
Ein "Analyze Profile" ausführen
Ein "Analyze Profile" kann mit dem Kommando pseudify:analyze <profil-name>
ausgeführt werden.
$ pseudify pseudify:analyze test-profile
1224/1224 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100% < 1 sec/< 1 sec 4.0 MiB
summary
=======
----------------------------------- ---------------------------------------------------------------------------------------------- ------------------------------
source data seems to be in
----------------------------------- ---------------------------------------------------------------------------------------------- ------------------------------
__custom__.__custom__ 132.188.241.155 wh_log.ip
__custom__.__custom__ 155.215.67.191 wh_log.ip
__custom__.__custom__ 243.202.241.67 wh_log.ip
__custom__.__custom__ 132.188.241.155 wh_log.log_data
__custom__.__custom__ 155.215.67.191 wh_log.log_data
__custom__.__custom__ 243.202.241.67 wh_log.log_data
__custom__.__custom__ example.com wh_log.log_data
__custom__.__custom__ example.com wh_log.log_message
__custom__.__custom__ 139.81.0.139 wh_meta_data.meta_data
__custom__.__custom__ 187.135.239.239 wh_meta_data.meta_data
__custom__.__custom__ 197.110.248.18 wh_meta_data.meta_data
__custom__.__custom__ 20.1.58.149 wh_meta_data.meta_data
__custom__.__custom__ 239.27.57.12 wh_meta_data.meta_data
__custom__.__custom__ 244.166.32.78 wh_meta_data.meta_data
__custom__.__custom__ 83.243.216.115 wh_meta_data.meta_data
__custom__.__custom__ example.com wh_meta_data.meta_data
__custom__.__custom__ 107.66.23.195 wh_user_session.session_data
__custom__.__custom__ 197.110.248.18 wh_user_session.session_data
__custom__.__custom__ 244.166.32.78 wh_user_session.session_data
wh_user.city Dorothyfort wh_meta_data.meta_data
wh_user.city North Elenamouth wh_meta_data.meta_data
wh_user.city South Wilfordland wh_meta_data.meta_data
wh_user.email mcclure.ofelia@example.com wh_log.log_data
wh_user.email mcclure.ofelia@example.com wh_log.log_message
wh_user.email cassin.bernadette@example.net wh_meta_data.meta_data
wh_user.email conn.abigale@example.net wh_meta_data.meta_data
wh_user.email mcclure.ofelia@example.com wh_meta_data.meta_data
wh_user.first_name Donato wh_meta_data.meta_data
wh_user.first_name Maybell wh_meta_data.meta_data
wh_user.first_name Mckayla wh_meta_data.meta_data
wh_user.last_name Keeling wh_log.log_data
wh_user.last_name Anderson wh_meta_data.meta_data
wh_user.last_name Keeling wh_meta_data.meta_data
wh_user.last_name Stoltenberg wh_meta_data.meta_data
wh_user.password $argon2i$v=19$m=8,t=1,p=1$QXNXbTRMZWxmenBRUzdwZQ$i6hntUDLa3ZFqmCG4FM0iPrpMp6d4D8XfrNBtyDmV9U wh_meta_data.meta_data
wh_user.password $argon2i$v=19$m=8,t=1,p=1$SUJJeWZGSGEwS2h2TEw5Ug$kCQm4/5DqnjXc/3SiXwimtTBvbDO9H0Ru1f5hkQvE/Q wh_meta_data.meta_data
wh_user.password $argon2i$v=19$m=8,t=1,p=1$ZldmOWd2TDJRb3FTNVpGNA$ORIwp6yekRx02mqM4WCTVhllgXpUpuFJZ1MmbYwAMXs wh_meta_data.meta_data
wh_user.username georgiana59 wh_log.log_data
wh_user.username georgiana59 wh_log.log_message
wh_user.username georgiana59 wh_meta_data.meta_data
wh_user.username howell.damien wh_meta_data.meta_data
wh_user.username hpagac wh_meta_data.meta_data
wh_user_session.session_data_json 1321:57fc:460b:d4d0:d83f:c200:4b:f1c8 wh_log.ip
wh_user_session.session_data_json 4fb:1447:defb:9d47:a2e0:a36a:10d3:fd98 wh_log.ip
wh_user_session.session_data_json 1321:57fc:460b:d4d0:d83f:c200:4b:f1c8 wh_log.log_data
wh_user_session.session_data_json 4fb:1447:defb:9d47:a2e0:a36a:10d3:fd98 wh_log.log_data
wh_user_session.session_data_json 1321:57fc:460b:d4d0:d83f:c200:4b:f1c8 wh_meta_data.meta_data
wh_user_session.session_data_json 197.110.248.18 wh_meta_data.meta_data
wh_user_session.session_data_json 244.166.32.78 wh_meta_data.meta_data
wh_user_session.session_data_json 107.66.23.195 wh_user_session.session_data
wh_user_session.session_data_json 1321:57fc:460b:d4d0:d83f:c200:4b:f1c8 wh_user_session.session_data
wh_user_session.session_data_json 197.110.248.18 wh_user_session.session_data
wh_user_session.session_data_json 244.166.32.78 wh_user_session.session_data
wh_user_session.session_data_json 4fb:1447:defb:9d47:a2e0:a36a:10d3:fd98 wh_user_session.session_data
----------------------------------- ---------------------------------------------------------------------------------------------- ------------------------------
Note
Je nach Größe der Datenbank kann die Analyse nach Sekunden oder erst nach Stunden fertig sein.
Da Analysen in der Regel nur selten durchgeführt werden, z.B. um mit den gesammelten Informationen die Pseudonymisierung zu modellieren, haben wir entscheiden, dass eine etwas längere Laufzeit einer Analyse vertretbar ist.
Die erste Zeile der Analyse gibt an, wie viele Daten bereits analysiert wurden und wie viele insgesamt analysiert werden (1148/1148
).
Es folgt ein Fortschrittsbalken und eine prozentuale Angabe des Fortschritts.
Danach wird die Laufzeit und die geschätzte Gesamtzeit der Analyse ausgegeben.
Zum Schluss wird der bisher maximale Speicherverbrauch ausgegeben.
Die Zusammenfassung der Analyse listet letztendlich auf, welche Quelldaten (Spalte data
) aus welcher Quell-Datenbankspalte (Spalte source
) sich in welchen Datenbankspalten wiederfinden (Spalte seems to be in
).
Wenn in der Spalte source
ein __custom__.__custom__
steht so bedeutet dies, dass die Quelldaten nicht aus einer Datenbankspalte stammen, sondern mittels addSourceString()
definiert wurden.
Wenn dir bisher noch nicht bekannt war, dass sich in einer Datenbankspalte unter seems to be in
gewisse Quelldaten befinden, dann kannst du dir nun diese Datenbankspalten genauer anschauen und sie in die Modellierung der Pseudonymisierung mit aufnehmen.
Info
Wenn viele Datenbanktabellen und Spalten existieren, dann kann die Ausgabe der Analyse sehr lang werden und vielleicht nicht in den Buffer deines Terminals passen.
In diesem Fall lohnt es sich, die Ausgabe in eine Datei zu schreiben.
pseudify --no-ansi pseudify:debug:analyze test-profile > analysis.log
Erweiterte Informationen ausgeben
Für die Fehlersuche oder die Verfeinerung des Analyseprofils kann es sinnvoll sein zu sehen, welche Daten pseudify in den Datenbankdaten gefunden hat.
Dafür kann das Kommando pseudify:analyze
mit dem Parameter --verbose
aufgerufen werden:
pseudify pseudify:analyze <profil-name> --verbose
Nun werden die Quelldaten aufgelistet (wh_log.ip (1321:57fc:460b:d4d0:d83f:c200:4b:f1c8
)) und die Fundstelle (wh_meta_data.meta_data (...ip";s:37:"1321:57fc:460b:d4d0:d83f:c200:4b:f1c8
";}";}s:4:...))
Die Anzahl der Zeichen, die vor und nach der Fundstelle ausgegeben werden, können mit der Methode setTargetDataFrameCuttingLength()
definiert werden.
Standardmäßig werden 10 Zeichen vor und nach einer Fundstelle ausgegeben.
Wird der Wert auf 0 gesetzt, so wird vor und nach der Fundstelle nichts abgeschnitten und du bekommst den vollständigen Datenbankinhalt ausgegeben.
<?php
namespace Waldhacker\Pseudify\Profiles;
use Waldhacker\Pseudify\Core\Profile\Analyze\ProfileInterface;
use Waldhacker\Pseudify\Core\Profile\Model\Analyze\TableDefinition;
class TestAnalyzeProfile implements ProfileInterface
{
public function getIdentifier(): string
{
return 'test-profile';
}
public function getTableDefinition(): TableDefinition
{
$tableDefinition = new TableDefinition(identifier: $this->getIdentifier());
$tableDefinition
// ...
->setTargetDataFrameCuttingLength(length: 15);
return $tableDefinition;
}
}