![]() |
| | Themen-Optionen |
| | Nach oben #1 |
| Corvin Gröning Registriert seit: 19.03.2005 Ort: S-H | Flensburg
Beiträge: 449
| Sichere PHP-Web-Applikationen schreiben Inhalt: Einleitung 1. register_globals 2. XSS 3. CSRF 4. SQL-Injection 5. Versteckte Formularfelder 6. Sessions 7. Variabler Funktionsaufruf 8. Variabler Include 9. Schutz vor ScreenScraping durch CAPTACHs 10. Fremde PHP-Skripte 11. Server-Logs 12. Speichern von Passwörtern 13. Schutz von E-Mail-Adressen 14. Fazit Geändert von Ben (23.05.2007 um 22:09 Uhr). |
| | |
| | Nach oben #2 |
| Corvin Gröning Registriert seit: 19.03.2005 Ort: S-H | Flensburg
Beiträge: 449
| Einleitung In diesem Tutorial erläutere ich die häufigsten Sicherheitslücken von PHP-Skripten und Möglichkeiten, um diese zu vermeiden. Ich setze vorraus, dass du mindestens die Grundlagen von PHP, SQL und HTML beherrschst. Geändert von Corvin (06.04.2008 um 14:24 Uhr). |
| | |
| | Nach oben #3 |
| Corvin Gröning Registriert seit: 19.03.2005 Ort: S-H | Flensburg
Beiträge: 449
| 1. register_globals register_globals ist eine Einstellungsmöglichkeit von PHP. Wenn diese aktiviert ist, ist ein direkter Zugriff auf Variablen, die via GET- oder POST-Methode übergeben wurden möglich. Beispiel: Code: <form method="POST" action="getData.php" name="myform"> <input type="text" name="username" width="100" /><br /> <input type="password" name="password" width="100" /><br /> <input type="submit" name="login" /> </form> Code: $userdata = array(); $userdata['name'] = $username; $userdata['pass'] = $password; Code: $userdata = array(); $userdata['name'] = $_POST['username']; $userdata['pass'] = $_POST['password']; Der direkte Zugriff ist zwar etwas kürzer, er stellt aber ein großes Sicherheitsrisiko dar. Beispiel: Code: <?php
echo '<form action="" name="login" method="POST">';
echo '<input type="text" name="username" width="100" />';
echo '<input type="password" name="password" width="100" />';
echo '<input type="submit" value="Login" />';
echo '</form>';
// check username and password
if( $_POST['username'] == "foo" AND $_POST['password'] == "bar" ) {
$logged_in = true;
}
// check if the user is logged in
if( $logged_in == true ) {
// print secret data
echo "Your secret data";
}
?>
Code: // check if the user is logged in
if($logged_in == true) {
// print secret data
echo "Your secret data";
}
Code: $logged_in = true;
// check if the user is logged in
if($logged_in == true) {
// print secret data
echo "Your secret data";
}
Alternativ kannst du auch "$logged_in = false;" an den Anfang des Skriptes schreiben (z. B. wenn du bei deinem Hoster kein Zugriff auf die php.ini hast). Link zu dem Thema: Geändert von Corvin (06.04.2008 um 14:25 Uhr). |
| | |
| | Nach oben #4 |
| Corvin Gröning Registriert seit: 19.03.2005 Ort: S-H | Flensburg
Beiträge: 449
| 2. XSS XSS ist die Abkürzung für Cross Site Scripting (es wurde mit XSS abgekürzt, weil CSS schon als Abkürzung für Cascading Style Sheets verwendet wird und im englischen cross häufig mit einem X abgekürzt wird). XSS ist der Versuch, fremden Code auf einer fremden Webseite zur Ausführung zu bringen. Als Beispiel folgendes XSS-gefährdetes Gästebuch: Code: <?php
/*----------------
* mini guestbook
*----------------
*/
$gbfile = "gb.txt";
// what to do?
$action = @$_GET['action'];
switch ($action) {
case "write":
write();
break;
case "edit":
// ...
break;
case "delete":
// ...
break;
default:
display();
}
// write entries
function write() {
global $gbfile;
// print form
echo '<form action="?action=write" name="gb" method="POST">';
echo 'Name:<br /> <input type="text" name="author" /><br />';
echo 'Text:<br /> <textarea name="text" cols="50" rows="5"></textarea><br />';
echo '<input type="submit" name="submit" value="Write" />';
echo '</form>';
// set vars
$author = $_POST['author'];
$text = $_POST['text'];
// write to file if text and author are given
if (!empty($author) AND !empty($text)) {
$file = file_get_contents($gbfile);
$file = $author .": " .$text ."\n{}". $file;
file_put_contents($gbfile, $file);
}
return true;
}
// display entries
function display() {
global $gbfile;
echo '<a href="?action=write">New Entry</a><br /><br /><br />';
// print entrys
$file = file_get_contents($gbfile);
$file = explode("{}", $file);
for ( $i=0; $i<count($file)-1; $i++ ) {
echo stripslashes( $file[$i] ) ."<hr />";
}
return true;
}
?>
Code: <script>document.location.href="http://domain.tld";</script> Um sich vor einem solchen Angriff zu schützen, kann man vor der Ausgabe der Einträge (Zeile 60) mit der Funktion htmlentities() alle HTML-Tags in Text umwandeln oder diese mit strip_tags() komplett entfernen. Beispiel: Code: echo htmlentities( stripslashes( $file[$i] ) ) ."<hr />"; Code: echo strip_tags( stripslashes( $file[$i] ) ) ."<hr />"; Code: echo strip_tags( stripslashes( $file[$i] ), "<b>" ) ."<hr />"; Code: <b style="font-size: 1000px; ">Hallo!!</b> Um dem Benutzer trotz Vewendung von htmlentities() oder strip_tags() die Möglichkeit zu geben, seinen Text zu formatieren, können entsprechende BBCodes implementiert werden. Ein Tutorial dazu findet sich hier: Weiterführende Links zum Thema XSS: Geändert von Corvin (06.04.2008 um 14:26 Uhr). |
| | |
| | Nach oben #5 |
| Corvin Gröning Registriert seit: 19.03.2005 Ort: S-H | Flensburg
Beiträge: 449
| 3. CSRF CSRF steht für Cross Site Request Forgery. Ein CSRF-Angriff ähnelt einem XSS-Angriff, bei ersterem geht es aber primär darum, Objekte (wie Bilder) auf einer fremden Webseite einzubinden. Als Beispiel das obige Gästebuch, dort ist folgender Eintrag möglich: Code: <img src="http://www.bad-site.com/bad-script.php" width="0" height="0" /> Ein Angreifer könnte so zum Beispiel die IP-Adressen von Benutzern mitloggen, da das Skript jedes mal ausgeführt wird, wenn jemand sich die Gästebuch-Einträge anschaut. Das ist noch nicht wirklich bedrohlich, aber ein Angreifer könnte auch folgendes in das Gästebuch eintragen: Code: <img src="http://www.domain.tld/buy.php?id=12345&ip=$_SERVER['REMOTE_ADDR']" width="0" height="0" /> Vor einem CSRF-Angriff schützt man sich genauso, wie vor einem XSS-Angriff. Wenn Bilder per BBCode zugelassen werden, sollte unbedingt überprüft werden, ob es sich bei dem Bild, das eingebunden werden soll, auch wirklich um ein Bild handelt. Zu überprüfen, ob das Bild eine gängige Dateiendung hat (.gif, .jpeg, .png) reicht allerdings nicht aus! Ein Angreifer kann mit einer einfachen Einstellung auf seinem Server festlegen, dass zum Beispiel .gif-Dateien als PHP-Skripte geparst werden sollen (AddHandler application/x-httpd-php .gif in der httpd.conf eines Apache Servers). Das Bild muss also vor dem Anzeigen auf den eigenen Server geladen werden, damit überprüft werden kann, ob es sich tatsächlich um ein Bild handelt. Der URL sollte dann so abgeändert werden, dass er auf das Bild auf dem eigenen Server verweist, so muss es nur einmal, nämlich wenn ein neuer Eintrag abgeschickt wird, auf den Server geladen und überprüft werden. Eine Demonstration eines CSRF-Angriffs findet sich hier: Link zum Thema XSS und CSRF: Geändert von Corvin (06.04.2008 um 14:26 Uhr). |
| | |
| | Nach oben #6 |
| Corvin Gröning Registriert seit: 19.03.2005 Ort: S-H | Flensburg
Beiträge: 449
| 4. SQL-Injection Von SQL-Injection spricht man, wenn ein Angreifer versucht, eine SQL-Abfrage zu manipulieren, um dann SQL-Befehle auszuführen, die nicht vorgesehen waren. Beispiel: Bei einem Newssystem gibt es folgende SQL-Query, um News in die Datenbank einzutragen ($title und $text enthalten Daten aus einem Formular Code: $sql = "INSERT INTO `news` (`title`, `text`) VALUES ('$title', '$text')";
Code: '); DELETE FROM news -- Code: INSERT INTO `news` (`title`, `text`) VALUES ('$title', ''); DELETE FROM news --')
Analyse der Query: Code: INSERT INTO news (title, text) VALUES ('$title', ''); Code: DELETE FROM news Code: --') Um sich vor einem SQL-Injection-Angriff zu schützen, muss in der php.ini die Einstellung magic_quotes_gpc auf On gestellt werden. Das bewirkt, dass Sonderzeichen in $_GET, $_POST und $_COOKIE "escaped" werden. Falls bei deinem Hoster magic_quotes_gpc deaktiviert ist und du keinen Zugriff auf die php.ini hast, bietet sich folgende Alternative: Code: if ( get_magic_quotes_gpc() == false ) {
$title = addslashes( $_POST['title'] );
$text = addslashes( $_POST['text'] );
} else {
$title = $_POST['title'];
$text = $_POST['text'];
}
Links zum Thema: Geändert von Corvin (06.04.2008 um 14:27 Uhr). |
| | |
| | Nach oben #7 |
| Corvin Gröning Registriert seit: 19.03.2005 Ort: S-H | Flensburg
Beiträge: 449
| 5. Versteckte Formularfelder Es ist möglich, Werte an ein andere Seite über ein verstecktes Formularfeld zu übergeben, solange der Benutzer nicht in den Quellcode schaut, sieht er nicht, was übergeben wird: Code: <!-- weitere Formular-Elemente --> <input type="hidden" value="wert" /> <!-- weitere Formular-Elemente --> Code: <form action="delete_account.php" name="delete" method="POST"> <input type="hidden" name="id" value="78" /> <input type="submit" value="Ja, meinen Account löschen!" /> </form> Code: <?php // ... Verbindung zur Datenbank $sql = "DELETE FROM users WHERE id = '".$_POST['id']."'"; mysql_query($sql); ?> Code: <input type="hidden" name="id" value="123" /> Aus diesem Grund sollten versteckte Formularfelder für solche sensiblen Daten nur verwendet werden, wenn überprüft wird, ob der Benutzer überhaupt berechtigt ist, die dem Inhalt des versteckten Feldes entsprechende Aktion durchzuführen. Geändert von Corvin (28.08.2008 um 16:35 Uhr). |
| | |
| | Nach oben #8 |
| Corvin Gröning Registriert seit: 19.03.2005 Ort: S-H | Flensburg
Beiträge: 449
| 6. Sessions Bei der Verwendung von Sessions sollte folgendes beachtet werden: Wenn der User die Verwendung von Cookies in seinem Browser aktiviert hat, wird die Session-ID in einem Cookie gespeichert. Wenn er dies nicht hat, wird sie einfach an den URL angehängt, um sie der nächsten Seite zu übergeben. Letzterer Fall stellt ein sehr großes Sicherheitsrisiko dar, denn wenn der Benutzer nun eine Seite geöffnet hat, auf der eine Session gestartet wurde, und nun von dieser aus eine andere Website besucht, wird eventuell der Referer (und damit die Session-ID des Users) mitgeloggt. Über die Session-ID kommen Dritte nun an Daten heran, die eigentlich nicht für sie bestimmt waren. Eine Schutzmaßnahme dagegen wäre, PHP mit aktiviertem session.use_only_cookies zu konfigurieren, dann wird die Session-ID immer in einem Cookie gespeichert. Wenn ein Benutzer die Verwendung von Cookies in seinem Browser deaktiviert hat, schlägt das Starten einer Session fehl! Weiterhin entsteht ein Sicherheitsrisiko, wenn die Session-ID auf dem Server unverschlüsselt übertragen wird. Dazu: Geändert von Corvin (06.04.2008 um 14:28 Uhr). |
| | |
| | Nach oben #9 |
| Corvin Gröning Registriert seit: 19.03.2005 Ort: S-H | Flensburg
Beiträge: 449
| 7. Variabler Funktionsaufruf Gerne verwendet wird ein "variabler Funktionsaufruf". Dabei wird dem PHP-Skript der Name einer Funktion übergeben, welche aufgerufen werden soll. Dies kann hilfreich sein, wenn man z. B. ein Gästebuch innerhalb einer einzigen PHP-Datei geschrieben hat und nun über den URL festgelegt werden soll, ob nun die Einträge angezeigt werden sollen oder ein neuer verfasst werden soll. Der URL könnte zum Beispiel so aussehen: guestbook.php?do=display_entries Und so das Gästebuch: Code: function display_entries() {
// ...
}
function new_entry() {
// ...
}
$function = $_GET['do'];
$function();
guestbook.php?do=phpinfo Damit wird die Funktion phpinfo() aufgerufen und der Angreifer erhält wertvolle Informationen über dein System. Um sich vor einem solchen Angriff zu schützen sollten die übergebenen Parameter wiefolgt überprüft werden: Code: function display_entries() {
// ...
}
function new_entry() {
// ...
}
// Prüfen was übergeben wurde
switch( $_GET['do'] ) {
case "new_entry":
$function = "new_entry";
break;
case "display_entries":
$function = "display_entries";
break;
default:
$function = "display_entries":
break;
}
$function();
Geändert von Corvin (06.04.2008 um 14:28 Uhr). |
| | |
| | Nach oben #10 |
| Corvin Gröning Registriert seit: 19.03.2005 Ort: S-H | Flensburg
Beiträge: 449
| 8. Variabler Include Sehr beliebt ist es, für eine Website eine Hauptdatei anzulegen, welche HTML-Kopf und -Fuß (und evt. noch ein paar andere Sachen) enthält und die Seite, die aufgerufen werden soll (zum Beispiel das Impressum oder Gästebuch) in die Mitte der Hauptdatei einzubinden. Die Links sehen dann etwa so aus: index.php?action=imprint index.php?action=guestbook Und der Code der PHP-Datei so: Code: <?php // HTML-Kopf include( $_GET['action'].".php" ); // HTML-Fuß ?> Daher sollten alle Namen der Dateien, die eingebunden werden können, in einem Array gespeichert werden. Über den URL wird dann nicht mehr der Dateinahme, sondern der Schlüssel des Array-Elementes, das den Dateinahmen enthält, übergeben. Beispiel: Code: $files = array( "start" => "start.php",
"..." => "..."
);
// $_GET['action'] gesetzt?
if ( empty( $_GET['action'] ) ) {
$key = "start";
} else {
$key = $_GET['site'];
}
// Existiert die Datei, die eingebunden werden soll?
if ( !@file_exists( $files[$key] ) ) {
echo "Error!";
} else {
include( $files[$key] );
}
Geändert von Corvin (06.04.2008 um 14:41 Uhr). |
| | |
| | Nach oben #11 |
| Corvin Gröning Registriert seit: 19.03.2005 Ort: S-H | Flensburg
Beiträge: 449
| 9. Schutz vor ScreenScraping durch CAPTACHs Angenommen, auf einer Webseite gibt es ein Umfrage-Skript. Es gibt nun folgende "Angriffsmöglichkeiten":
Sogenannte CAPTCHAs (Completely Automated Public Turing-Test to Tell Computers and Humans Apart) sind eine Lösung für das Problem. Sie dienen dazu, einen Menschen von einem Computer zu unterscheiden: Wenn jemand an der Umfrage teilnehmen will oder die Ergebnisse von dieser aufrufen will, wird eine Grafik mit einer verzogenen Zeichenfolge anzeigt (diese Grafiken sind für (die meisten) Bots nicht lesbar), welche der Benutzer in ein Feld eingeben muss. Links: Geändert von Corvin (06.04.2008 um 15:01 Uhr). |
| | |
| | Nach oben #12 |
| Corvin Gröning Registriert seit: 19.03.2005 Ort: S-H | Flensburg
Beiträge: 449
| 10. Fremde PHP-Skripte Beim Einsetzen von fremden PHP-Anwendungen (Foren, Gästebücher etc.) auf deinem Server solltest du folgende Punkte beachten:
Geändert von Corvin (06.04.2008 um 15:04 Uhr). |
| | |
| | Nach oben #13 |
| Corvin Gröning Registriert seit: 19.03.2005 Ort: S-H | Flensburg
Beiträge: 449
| 11. Server-Logs Die Log-Dateien deines Webservers solltest du so oft wie möglich auswerten, so kannst du einen versuchten Angriff schon früh erkennen und dem Angreifer entsprechend den Weg versperren. Hilfreiche Tools/Programme um Server-Logs auszuwerten, lassen sich über Google schnell finden. Geändert von Corvin (09.03.2006 um 21:01 Uhr). |
| | |
| | Nach oben #14 |
| Corvin Gröning Registriert seit: 19.03.2005 Ort: S-H | Flensburg
Beiträge: 449
| 12. Speichern von Passwörtern Bei einem Login-System zum Beispiel müssen die Passwörter der Benutzer in einer Datei/Datenbank gespeichert werden. Um die Passwörter zu schützen (falls ein Angreifer sich Zugriff auf den Speicherort der Passwörter verschafft), sollten sie nicht im Klartext, sondern als Hash abgespeichert werden, z. B. als md5-Hash. Beispiel: Die Query, um den Benutzernamen und das Passwort bei der Registration in der Datenbank zu speichern, könnte wie folgt lauten (um den md5-Hash des Passworts zu erhalten wird die PHP-Funktion md5 verwendet Code: $user = $_GET['user'];
$pw = md5($_GET['pw']);
$sql = "INSERT INTO `users` (`username`, `password`) VALUES ('$user', '$pw')";
Code: $user = $_GET['user']; $pw = md5($_GET['pw']); $sql = "SELECT `username` FROM `users` WHERE `username` = '$user' AND `password` = '$pw'"; Geändert von Corvin (06.04.2008 um 15:17 Uhr). |
| | |
| | Nach oben #15 |
| Corvin Gröning Registriert seit: 19.03.2005 Ort: S-H | Flensburg
Beiträge: 449
| 13. Schutz von E-Mail-Adressen Versender von Spammails lassen oft Bots durch das Internet laufen, die wahllos auf Webseiten nach E-Mail-Adressen suchen, um an diese Spamnachrichten verschicken zu können. Um sich davor zu schützen, können E-Mail-Adressen z. B. etwas "verschlüsselt" ausgegeben werden: email [ at ] host [ dot ] com anstelle von email@host.com, allerdings durchschauen die meisten Bots das. Eine sicherere Methode, E-Mail-Adressen zu schützen, ist es, sie als Bild darzustellen. Weder die "verschlüsselte" E-Mail-Adresse noch das Bild sollten allerdings verlinkt werden (<a href="mailto:email@host.com"> ... </a>), denn Bots, die nach E-Mail-Adressen suchen, analysieren nicht die Ausgabe des Browsers, sondern den Quellcode der HTML-Datei. Hierfür gibt es allerdings eine sichere Alternative, es kann mittels PHP ein Header an den Browser gesendet werden: Code: header("Location:mailto:".$mail);
Geändert von Corvin (06.04.2008 um 15:30 Uhr). |
| | |
| | Nach oben #16 |
| Corvin Gröning Registriert seit: 19.03.2005 Ort: S-H | Flensburg
Beiträge: 449
| 14. Fazit Ich hoffe, ich konnte dir hiermit einen guten Einstieg in einige Aspekte der Sicherheit von PHP-Skripten vermitteln. Wie bereits am Anfang des Tutorials erwähnt, es wurden hier nur einige der häufigsten Sicherheitslücken angesprochen. Du solltest dich auf jeden Fall weiter mit dem Thema befassen. Hier findest du einige Links zu Webseiten, auf denen du weiterarbeiten kannst: Bei Fragen oder Problemen sind wir dir hier im Forum sehr gerne behilflich. Geändert von Corvin (06.04.2008 um 15:33 Uhr). |
| | |
| | Nach oben #17 |
| Goldman.de Registriert seit: 09.10.2005 Ort: Frankfurt am Main
Beiträge: 190
|
kleine Hilfe zu CSRF PHP-Code: |
| | |
| | Nach oben #18 | |||
| Gast
Beiträge: n/a
| Zitat:
In Sessions speichere ich Daten die über einen längeren zeitraum benötigt werden. Zitat:
Zitat:
-- Fat Tony | |||
|
| | Nach oben #19 |
| Gast
Beiträge: n/a
|
zu Punkt 8 hätte ich auch noch eine sichere alternative. Man speichert die zu includierenden Seiten einfach in einen Unterordner, beispielsweise /inc PHP-Code: |
|