1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
|
<?xml version="1.0" encoding="UTF-8"?>
<!-- EN-Revision: 24249 -->
<!-- Reviewed: no -->
<sect1 id="zend.auth.adapter.dbtable">
<title>Datenbanktabellen Authentifizierung</title>
<sect2 id="zend.auth.adapter.dbtable.introduction">
<title>Einführung</title>
<para>
<classname>Zend_Auth_Adapter_DbTable</classname> bietet die Möglichkeit sich gegenüber
Zeugnissen zu authentifizieren die in einer Datenbank Tabelle gespeichert sind. Weil
<classname>Zend_Auth_Adapter_DbTable</classname> eine Instanz von
<classname>Zend_Db_Adapter_Abstract</classname> benötigt, die an den Konstruktor
übergeben wird, ist jede Instanz an eine spezielle Datenbank Verbindung verknüpft.
Andere Konfigurationsoptionen können durch den Konstruktor gesetzt werden und durch die
Methoden der Instanz. Eine für jede Option.
</para>
<para>
Die vorhandenen Konfigurationsoptionen beinhalten:
</para>
<itemizedlist>
<listitem>
<para>
<emphasis><property>tableName</property></emphasis>: Das ist der Name der
Datenbanktabelle welche die Authentifikations Zeugnisse enthält, und gegen die
jene Datenbank Authentifikations Abfrage durchgeführt wird.
</para>
</listitem>
<listitem>
<para>
<emphasis><property>identityColumn</property></emphasis>: Ist der Name der
Spalte der Datenbanktabelle welche die Identität repräsentiert. Die Spalte der
Identität muß eindeutige und einmalige Werte enthalten, wie einen Benutzernamen
oder eine Email Adresse.
</para>
</listitem>
<listitem>
<para>
<emphasis><property>credentialColumn</property></emphasis>: Das ist der Name
der Spalte der Datenbanktabelle die verwendet wird um die Zeugnisse zu
repräsentieren. Bei einem einfachen Identitäts und Passwort-Authentifizierungs
Schema korrespondieren die Zeugnisse mit dem Passwort. Siehe auch die
<property>credentialTreatment</property> Option.
</para>
</listitem>
<listitem>
<para>
<emphasis><property>credentialTreatment</property></emphasis>: In vielen Fällen
sind Passwörter und andere sensitive Daten verschlüsselt, gehasht, kodiert,
gesalted, verschleiert oder auf andere Weise durch irgendeine Funktion oder
einen Algorithmus behandelt. Durch die Spezifikation eines parametrisierbaren
Behandlungsstrings mit dieser Methode, wie '<methodname>MD5(?)</methodname>'
oder '<methodname>PASSWORD(?)</methodname>', könnte ein Entwickler beliebiges
<acronym>SQL</acronym> an den Eingabe- Zeugnis-Daten anwenden. Da diese
Funktionen der darunter liegenden <acronym>RDBMS</acronym> speziell gehören,
sollte das Handbuch der Datenbank auf das Vorhandensein solcher Funktionen im
eigenen Datenbank System geprüft werden.
</para>
</listitem>
</itemizedlist>
<example id="zend.auth.adapter.dbtable.introduction.example.basic_usage">
<title>Grundsätzliche Verwendung</title>
<para>
Wie bereits in der Einführung beschrieben benötigt der
<classname>Zend_Auth_Adapter_DbTable</classname> Konstruktor eine Instanz von
<classname>Zend_Db_Adapter_Abstract</classname> die als Datenbank Verbindung
fungiert zu welcher die Instanz des Authentifizierungs-Adapters gebunden ist. Zuerst
sollte die Datenbankverbindung erstellt werden.
</para>
<para>
Der folgende Code erstellt einen Adapter für eine In-Memory Datenbank, erstellt ein
einfaches Datenbankschema, und fügt eine Zeile ein gegen die später eine
Authentifizierungs-Abfrage durchgeführt werden kann. Dieses Beispiel benötigt die
<acronym>PDO</acronym> SQLite Erweiterung:
</para>
<programlisting language="php"><![CDATA[
// Erstellt eine In-Memory SQLite Datenbankverbindung
$dbAdapter = new Zend_Db_Adapter_Pdo_Sqlite(array('dbname' =>
':memory:'));
// Erstellt eine einfache Datenbank-Erstellungs-Abfrage
$sqlCreate = 'CREATE TABLE [users] ('
. '[id] INTEGER NOT NULL PRIMARY KEY, '
. '[username] VARCHAR(50) UNIQUE NOT NULL, '
. '[password] VARCHAR(32) NULL, '
. '[real_name] VARCHAR(150) NULL)';
// Erstellt die Tabelle für die Authentifizierungs Zeugnisse
$dbAdapter->query($sqlCreate);
// Erstellt eine Abfrage um eine Zeile einzufügen für die eine
// Authentifizierung erfolgreich sein kann
$sqlInsert = "INSERT INTO users (username, password, real_name) "
. "VALUES ('my_username', 'my_password', 'My Real Name')";
// Daten einfügen
$dbAdapter->query($sqlInsert);
]]></programlisting>
<para>
Mit der Datenbankverbindung und den vorhandenen Tabellendaten, kann eine Instanz von
<classname>Zend_Auth_Adapter_DbTable</classname> erstellt werden. Die Werte der
Konfigurationsoptionen können dem Konstruktor übergeben werden, oder als Parameter
der setzenden Methoden nach der Instanziierung:
</para>
<programlisting language="php"><![CDATA[
// Die Instanz mit Konstruktor Parametern konfiurieren...
$authAdapter = new Zend_Auth_Adapter_DbTable(
$dbAdapter,
'users',
'username',
'password'
);
// ...oder die Instanz mit den setzenden Methoden konfigurieren
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
$authAdapter
->setTableName('users')
->setIdentityColumn('username')
->setCredentialColumn('password');
]]></programlisting>
<para>
An diesem Punkt ist die Instanz des Authentifizierungsadapters bereit um
Authentifierungsabfragen zu akzeptieren. Um eine Authentifierungsabfrage zu
formulieren, werden die Eingabezeugnis Werte dem Adapter vor dem Aufruf der
<methodname>authenticate()</methodname> Methode, übergeben:
</para>
<programlisting language="php"><![CDATA[
// Die Eingabezeugnis Werte setzen (z.B. von einem Login Formular)
$authAdapter
->setIdentity('my_username')
->setCredential('my_password');
// Die Authentifizierungsabfrage durchführen, das Ergebnis speichern
$result = $authAdapter->authenticate();
]]></programlisting>
<para>
Zusätzlich zum Vorhandensein der <methodname>getIdentity()</methodname> Methode
über das Authentifizierungs Ergebnisobjekt, unterstützt
<classname>Zend_Auth_Adapter_DbTable</classname> auch das empfangen der
Tabellenzeile wenn die Authentifizierung erfolgeich war:
</para>
<programlisting language="php"><![CDATA[
// Die Identität ausgeben
echo $result->getIdentity() . "\n\n";
// Die Ergebniszeile ausgeben
print_r($$authAdapter->getResultRowObject());
/* Ausgabe:
my_username
Array
(
[id] => 1
[username] => my_username
[password] => my_password
[real_name] => My Real Name
)
*/
]]></programlisting>
<para>
Da die Zeile der Tabelle die Zeugnis Daten enthält ist es wichtig diese Werte
gegenüber unberechtigten Versuchen abzusichern.
</para>
</example>
</sect2>
<sect2 id="zend.auth.adapter.dbtable.advanced.storing_result_row">
<title>Fortgeschrittene Verwendung: Ein DbTable Ergebnis Objekt dauerhaft machen</title>
<para>
Standardmäßig gibt <classname>Zend_Auth_Adapter_DbTable</classname> die unterstützte
Identität an das Auth Objekt bei erfolgreicher Authentifizierung zurück. Ein anderes
Verwendungs-Szenario, bei dem Entwickler ein Identitäts Objekt, welches andere nützliche
Informationen enthält, in den dauerhaften Speichermechanismus von
<classname>Zend_Auth</classname> abspeichern wollen, wird durch die Verwendung der
<methodname>getResultRowObject()</methodname> Methode gelöst die ein
<emphasis>stdClass</emphasis> Objekt zurück gibt. Der folgende Code Abschnitt zeigt
diese Verwendung:
</para>
<programlisting language="php"><![CDATA[
// Mit Zend_Auth_Adapter_DbTable authentifizieren
$result = $this->_auth->authenticate($adapter);
if ($result->isValid()) {
// Die Identität als Objekt speichern wobei nur der Benutzername und
// der echte Name zurückgegeben werden
$storage = $this->_auth->getStorage();
$storage->write($adapter->getResultRowObject(array(
'username',
'real_name'
)));
// Die Identität als Objekt speichern, wobei die
// Passwort Spalte unterdrückt wird
$storage->write($adapter->getResultRowObject(
null,
'password'
));
/* ... */
} else {
/* ... */
}
]]></programlisting>
</sect2>
<sect2 id="zend.auth.adapter.dbtable.advanced.advanced_usage">
<title>Fortgeschrittene Verwendung durch Beispiele</title>
<para>
Wärend der primäre Zweck von <classname>Zend_Auth</classname> (und konsequenter Weise
<classname>Zend_Auth_Adapter_DbTable</classname>) die
<emphasis>Authentifizierung</emphasis> und nicht die <emphasis>Authorisierung</emphasis>
ist, gibt es ein paar Instanzen und Probleme auf dem Weg welche Art besser passt.
Abhängig davon wie man sich entscheidet ein Problem zu beschreiben, macht es manchmal
Sinn, das was wie ein Authorisierungsproblem aussieht im Authentifizierungs-Adapter zu
lösen.
</para>
<para>
Mit dieser Definition, hat <classname>Zend_Auth_Adapter_DbTable</classname> einige
eingebaute Mechanismen die für zusätzliche Checks während der Authentifizierungszeit
angepasst werden können, um einige übliche Benutzerprobleme zu lösen.
</para>
<programlisting language="php"><![CDATA[
// Der Feldwert des Status eines Accounts ist nicht gleich "compromised"
$adapter = new Zend_Auth_Adapter_DbTable(
$db,
'users',
'username',
'password',
'MD5(?) AND status != "compromised"'
);
// Der aktive Feldwert des Accounts ist gleich "TRUE"
$adapter = new Zend_Auth_Adapter_DbTable(
$db,
'users',
'username',
'password',
'MD5(?) AND active = "TRUE"'
);
]]></programlisting>
<para>
Ein anderes Szenario kann die Implementierung eines Saltingmachanismus sein. Salting
ist ein Ausdruck der auf eine Technik verweist welche die Sicherheit der Anwendung sehr
stark erhöht. Sie basiert auf der Idee dass das Anfügen von zufälligen Strings bei jedem
Passwort es unmöglich macht eine erfolgreiche Brute-Force Attacke auf die Datenbank
durchzuführen bei der vorberechnete Hashwerte aus einem Verzeichnis genommen werden.
</para>
<para>
Hierfür muß die Tabelle so modifiziert werden das Sie unseren Salt-String enthält:
</para>
<programlisting language="php"><![CDATA[
$sqlAlter = "ALTER TABLE [users] "
. "ADD COLUMN [password_salt] "
. "AFTER [password]";
$dbAdapter->query($sqlAlter);
]]></programlisting>
<para>
Hier ist ein einfacher Weg um einen Salt String für jeden Benutzer bei der Registrierung
zu erstellen:
</para>
<programlisting language="php"><![CDATA[
for ($i = 0; $i < 50; $i++) {
$dynamicSalt .= chr(rand(33, 126));
}
]]></programlisting>
<para>
Und nun erstellen wir den Adapter:
</para>
<programlisting language="php"><![CDATA[
$adapter = new Zend_Auth_Adapter_DbTable(
$db,
'users',
'username',
'password',
"MD5(CONCAT('"
. Zend_Registry::get('staticSalt')
. "', ?, password_salt))"
);
]]></programlisting>
<note>
<para>
Die Sicherheit kann sogar noch mehr erhöht werden indem ein statischer Salt Wert
hardcoded in der Anwendung verwendet wird. Im Falle das die Datenbank korrumpiert
wird (z.B. durch eine <acronym>SQL</acronym> Injection Attacke) aber der Webserver
intakt bleibt sind die Daten für den Angreifer noch immer nicht verwendbar.
</para>
</note>
<para>
Eine andere Alternative besteht darin die <methodname>getDbSelect()</methodname>
Methode von <classname>Zend_Auth_Adapter_DbTable</classname> zu verwenden nachdem der
Adapter erstellt wurde. Diese Methode gibt die Instanz des
<classname>Zend_Db_Select</classname> Objekts zurück welches verwendet wird um die
<methodname>authenticate()</methodname> Methode zu komplettieren. Es ist wichtig
anzumerken das diese Methode immer das gleiche Objekt zurückgibt unabhängig davon ob
<methodname>authenticate()</methodname> aufgerufen wurde oder nicht. Diese Objekt
<emphasis>enthält keine</emphasis> Identity oder Anmeldeinformationen in sich da diese
Werte im Select Objekt während des Ausführens von
<methodname>authenticate()</methodname> platziert werden.
</para>
<para>
Als Beispiel einer Situation könnte man die <methodname>getDbSelect()</methodname>
Methode verwenden um den Status eines Benutzers zu prüfen, in anderen Worten sehen ob
der Account des Benutzers aktiviert ist.
</para>
<programlisting language="php"><![CDATA[
// Das Beispiel von oben weiterführen
$adapter = new Zend_Auth_Adapter_DbTable(
$db,
'users',
'username',
'password',
'MD5(?)'
);
// Das Select Objekt (durch Referenz) bekommen
$select = $adapter->getDbSelect();
$select->where('active = "TRUE"');
// Authentifizieren, das stellt sicher das users.active = TRUE
$adapter->authenticate();
]]></programlisting>
</sect2>
</sect1>
|