PHP bietet Entwicklern große Flexibilität, aber dies bringt auch potenzielle verborgene Gefahren für die Sicherheit mit sich. Kürzlich muss ich vergangene Probleme zusammenfassen. Hier werde ich einen Artikel übersetzen und einige meiner eigenen Entwicklungserfahrungen hinzufügen, um zusammenzufassen.

Einführung
Bei der Entwicklung eines Internetdienstes müssen Sie stets Sicherheitskonzepte im Hinterkopf behalten und sie in dem von Ihnen entwickelten Code widerspiegeln. Die Skriptsprache PHP kümmert sich nicht besonders um Sicherheitsfragen, insbesondere für die meisten unerfahrenen Entwickler. Wann immer Sie mit einer Transaktion zu tun haben, bei der es um Geld oder andere finanzielle Angelegenheiten geht, müssen Sie Sicherheitsaspekten besondere Aufmerksamkeit schenken, beispielsweise bei der Entwicklung eines Forums oder eines Warenkorbs.
Allgemeine Punkte zum Sicherheitsschutz
Vertrauen Sie keinen Formularen
Bei der allgemeinen JavaScript-Frontend-Validierung können Sie das Verhalten des Benutzers nicht kennen, beispielsweise das Deaktivieren der JavaScript-Engine des Browsers; daher können bösartige Daten per POST an den Server gesendet werden. Sie müssen serverseitig validieren und bei jedem PHP-Skript die an es übergebenen Daten validieren, um XSS-Angriffe und SQL-Injection zu verhindern.
Vertrauen Sie Benutzern nicht
Gehen Sie davon aus, dass jedes Datenelement, das Ihre Website empfängt, bösartigen Code und versteckte Bedrohungen enthält, und bereinigen Sie jedes Datenelement.
Globale Variablen deaktivieren
Nehmen Sie die folgende Konfiguration in der Datei php.ini vor:
register_globals = Off
Wenn diese Konfigurationsoption eingeschaltet ist, bestehen große Sicherheitsrisiken. Zum Beispiel gibt es eine Skriptdatei process.php, die empfangene Daten in die Datenbank einfügt. Das Formular, das Benutzereingabedaten empfängt, könnte wie folgt aussehen:
<input name="username" type="text" size="15" maxlength="64">
Auf diese Weise registriert PHP nach dem Übermitteln von Daten an process.php eine Variable $username und übergibt diese Variablendaten an process.php. Gleichzeitig wird für jeden POST- oder GET-Anforderungsparameter eine solche Variable gesetzt. Wenn sie nicht explizit initialisiert wird, tritt das folgende Problem auf:
<?php
// Define $authorized = true only if user is authenticated
if (authenticated_user()) {
$authorized = true;
}
?>
Hier wird angenommen, dass die Funktion authenticated_user einfach den Wert der Variable $authorized prüft; wenn die Konfiguration register_globals aktiviert ist, kann jeder Benutzer eine Anforderung senden, um die Variable $authorized auf einen beliebigen Wert zu setzen und so diese Überprüfung zu umgehen.
Alle diese übermittelten Daten sollten über die vordefinierten integrierten globalen Arrays von PHP abgerufen werden, einschließlich $_POST, $_GET, $_FILES, $_SERVER, $_REQUEST usw. Dabei ist $_REQUEST eine kombinierte Variable der drei Arrays $_GET/$_POST/$_COOKIE, und die Standardreihenfolge ist $_COOKIE, $_POST, $_GET.
- Empfohlene Sicherheitskonfigurationsoptionen
Setzen Sie error_reporting auf Off: Geben Sie Fehlermeldungen nicht gegenüber Benutzern preis. Während der Entwicklung kann es auf ON gesetzt werden.
Setzen Sie safe_mode auf Off
Setzen Sie register_globals auf Off
Deaktivieren Sie die folgenden Funktionen: system, exec, passthru, shell_exec, proc_open, popen
Setzen Sie open_basedir auf /tmp, damit Sitzungsinformationen Speicherberechtigungen haben, und richten Sie ein separates Website-Stammverzeichnis ein.
Setzen Sie expose_php auf Off
Setzen Sie allow_url_fopen auf Off
Setzen Sie allow_url_include auf Off
SQL-Injection-Angriff
Bei SQL-Anweisungen, die auf eine Datenbank zugreifen, muss besonders auf die Sicherheit geachtet werden, da Benutzer bestimmte Anweisungen eingeben können, die die Funktionalität der ursprünglichen SQL-Anweisung verändern. Ähnlich wie im folgenden Beispiel:
$sql = "select * from pinfo where product = '$product'";
Wenn der vom Benutzer eingegebene Parameter $product an dieser Stelle lautet:
39'; DROP pinfo; SELECT 'FOO
Dann lautet die endgültige SQL-Anweisung wie folgt:
select product from pinfo where product = '39'; DROP pinfo; SELECT 'FOO'
Daraus werden drei SQL-Anweisungen, wodurch die Tabelle pinfo gelöscht wird, was zu schwerwiegenden Konsequenzen führt.
Dieses Problem lässt sich einfach mit den in PHP integrierten Funktionen lösen:
$sql = 'Select * from pinfo where product = '"'
mysql_real_escape_string($product) . '"';
Um SQL-Injection-Angriffe zu verhindern, müssen zwei Dinge gut umgesetzt werden:
Führen Sie stets eine Typvalidierung der Eingabeparameter durch
Verwenden Sie immer die Funktion mysql_real_escape_string, um Sonderzeichen wie einfache Anführungszeichen, doppelte Anführungszeichen und Backticks zu escapen.
Basierend auf Entwicklungserfahrung sollten Sie jedoch PHPs Magic Quotes nicht aktivieren. Dieses Feature wurde in PHP 6 entfernt. Escapen Sie bei Bedarf immer manuell.
Verhinderung einfacher XSS-Angriffe
XSS-Angriffe sind nicht wie andere Angriffe; dieser Angriff wird auf der Clientseite ausgeführt. Der grundlegendste XSS-Angriff besteht darin, ein JavaScript-Skript auf der Formularseite zu platzieren, die der Benutzer gerade absenden möchte, und dabei die vom Benutzer übermittelten Daten und Cookies zu stehlen.
XSS-Angriffe sind schwieriger abzuwehren als SQL-Injection. Websites großer Unternehmen wurden durch XSS angegriffen. Obwohl dieser Angriff nicht mit der Sprache PHP zusammenhängt, kann PHP verwendet werden, um Benutzerdaten zu filtern, um Benutzerdaten zu schützen. Hier besteht der Hauptansatz darin, Benutzerdaten zu filtern, im Allgemeinen durch Herausfiltern von HTML-Tags, insbesondere <a>-Tags. Nachfolgend finden Sie eine gängige Filtermethode:
function transform_HTML($string, $length = null) {
// Helps prevent XSS attacks
// Remove dead space.
$string = trim($string);
// Prevent potential Unicode codec problems.
$string = utf8_decode($string);
// HTMLize HTML-specific characters.
$string = htmlentities($string, ENT_NOQUOTES);
$string = str_replace("#", "#", $string);
$string = str_replace("%", "%", $string);
$length = intval($length);
if ($length > 0) {
$string = substr($string, 0, $length);
}
return $string;
}
Diese Funktion wandelt spezielle HTML-Zeichen in HTML-Entities um. Wenn der Browser diesen Text rendert, wird er als reiner Text angezeigt. Beispielsweise wird <strong>bold</strong> wie folgt angezeigt:
<STRONG>BoldText</STRONG>
Der Kern der obigen Funktion ist die Funktion htmlentities. Diese Funktion wandelt spezielle HTML-Tags in HTML-Entity-Zeichen um, wodurch die meisten XSS-Angriffe herausgefiltert werden können.
Für erfahrene XSS-Angreifer gibt es jedoch raffiniertere Angriffsmöglichkeiten: Sie kodieren ihren bösartigen Code in Hexadezimal oder UTF-8 statt in gewöhnlichem ASCII-Text. Zum Beispiel können sie es auf die folgende Weise tun:
<a href="http://host/a.php?variable=%22%3e %3c%53%43%52%49%50%54%3e%44%6f%73%6f%6d%65%74%68%69%6e%67%6d%61%6c%69%63%69%6f%75%73%3c%2f%53%43%52%49%50%54%3e">
In diesem Fall lautet das vom Browser tatsächlich gerenderte Ergebnis:
<a href="http://host/a.php?variable="> <SCRIPT>Dosomethingmalicious</SCRIPT>
Auf diese Weise wird der Zweck des Angriffs erreicht. Um diese Situation zu verhindern, müssen Sie zusätzlich auf Grundlage der Funktion transform_HTML # und % in ihre entsprechenden Entity-Symbole umwandeln und den Parameter $length hinzufügen, um die maximale Länge der übermittelten Daten zu begrenzen.
Verwendung von SafeHTML zur Verhinderung von XSS-Angriffen
Der obige Schutz gegen XSS-Angriffe ist sehr einfach, aber er umfasst nicht alle Benutzer-Tags. Gleichzeitig gibt es Hunderte von Möglichkeiten, die Filterfunktion zu umgehen, um JavaScript-Code zu übermitteln, und es gibt keine Möglichkeit, diese Situation vollständig zu verhindern.
Derzeit kann kein einzelnes Skript garantieren, dass es nicht durch Angriffe kompromittiert wird, aber es gibt immer relativ bessere Schutzmaßnahmen. Es gibt zwei Sicherheitsmethoden: Whitelist und Blacklist. Unter ihnen ist die Whitelist einfacher und effektiver.
Eine Whitelist-Lösung ist SafeHTML, die intelligent genug ist, gültiges HTML zu erkennen und dann alle gefährlichen Tags zu entfernen. Dies muss basierend auf dem HTMLSax-Paket geparst werden.
Wie man SafeHTML installiert und verwendet:
1. Gehen Sie zuhttp://pixel-apes.com/safehtml/?page=safehtml Laden Sie die neueste SafeHTML herunter
2. Legen Sie die Dateien in das classes-Verzeichnis des Servers, das alle SafeHTML- und HTMLSax-Bibliotheken enthält.
3. Binden Sie die SafeHTML-Klassendatei in Ihr eigenes Skript ein.
4. Erstellen Sie ein SafeHTML-Objekt.
5. Verwenden Sie die parse-Methode zum Filtern.
<?php
/* If you're storing the HTMLSax3.php in the /classes directory, along
with the safehtml.php script, define XML_HTMLSAX3 as a null string. */
define(XML_HTMLSAX3, '');
// Include the class file.
require_once('classes/safehtml.php');
// Define some sample bad code.
$data = "This data would raise an alert <script>alert('XSS Attack')</script>";
// Create a safehtml object.
$safehtml = new safehtml();
// Parse and sanitize the data.
$safe_data = $safehtml->parse($data);
// Display result.
echo 'The sanitized data is <br />' . $safe_data;
?>
SafeHTML kann XSS-Angriffe nicht vollständig verhindern; es ist nur eine relativ komplexe skriptbasierte Verifizierungsmethode.
Verwendung von Einweg-HASH-Verschlüsselung zum Schutz von Daten
Die Einweg-Hash-Verschlüsselung stellt sicher, dass das Passwort jedes Benutzers eindeutig ist und nicht entschlüsselt werden kann. Nur der Endbenutzer kennt das Passwort; das System kennt das ursprüngliche Passwort nicht. Ein Vorteil davon ist, dass selbst wenn das System angegriffen wird, der Angreifer die ursprünglichen Passwortdaten nicht erfahren kann.
Verschlüsselung und Hashing sind zwei unterschiedliche Prozesse. Anders als bei der Verschlüsselung kann ein Hash nicht entschlüsselt werden; er ist einweg. Gleichzeitig können zwei unterschiedliche Zeichenketten denselben Hashwert erzeugen, sodass die Eindeutigkeit des Hashwerts nicht garantiert werden kann.
Mit der MD5-Funktion verarbeitete Hashwerte sind so gut wie unmöglich zu knacken, aber es gibt immer eine Möglichkeit, und es gibt online verfügbare MD5-Hash-Wörterbücher.
Daten mit mcrypt verschlüsseln
Die MD5-Hashfunktion kann Daten in lesbarer Form anzeigen, aber beim Speichern von Kreditkarteninformationen der Benutzer müssen sie verschlüsselt gespeichert und später entschlüsselt werden.
Die beste Methode ist, das mcrypt-Modul zu verwenden, das mehr als 30 Verschlüsselungsmethoden enthält, um sicherzustellen, dass nur der Verschlüsseler die Daten entschlüsseln kann.
<?php
$data = "Stuff you want encrypted";
$key = "Secret passphrase used to encrypt your data";
$cipher = "MCRYPT_SERPENT_256";
$mode = "MCRYPT_MODE_CBC";
function encrypt($data, $key, $cipher, $mode) {
// Encrypt data
return (string)
base64_encode
(
mcrypt_encrypt
(
$cipher,
substr(md5($key),0,mcrypt_get_key_size($cipher, $mode)),
$data,
$mode,
substr(md5($key),0,mcrypt_get_block_size($cipher, $mode))
)
);
}
function decrypt($data, $key, $cipher, $mode) {
// Decrypt data
return (string)
mcrypt_decrypt
(
$cipher,
substr(md5($key),0,mcrypt_get_key_size($cipher, $mode)),
base64_decode($data),
$mode,
substr(md5($key),0,mcrypt_get_block_size($cipher, $mode))
);
}
?>
Die mcrypt-Funktion benötigt die folgenden Informationen:
1. Die zu verschlüsselnden Daten
2. Der Schlüssel, der zum Verschlüsseln und Entschlüsseln der Daten verwendet wird
3. Der spezifische Algorithmus (Cipher), den der Benutzer zum Verschlüsseln von Daten auswählt, wie z. B.MCRYPT_TWOFISH192,MCRYPT_SERPENT_256, MCRYPT_RC2, MCRYPT_DES, und MCRYPT_LOKI97)
4. Der für die Verschlüsselung verwendete Modus
5. Der Verschlüsselungs-Seed, also die Daten, die zum Starten des Verschlüsselungsprozesses verwendet werden, ist eine zusätzliche binäre Datenmenge, die zum Initialisieren des Verschlüsselungsalgorithmus verwendet wird.
6. Die Längen des Verschlüsselungsschlüssels und des Seeds können mit der Funktion mcrypt_get_key_size und der Funktion mcrypt_get_block_size ermittelt werden.
Wenn sowohl die Daten als auch der Schlüssel gestohlen werden, kann der Angreifer Chiffren durchlaufen, um einen Weg zum Entschlüsseln zu finden. Daher müssen wir MD5 einmal auf den Verschlüsselungsschlüssel anwenden, um die Sicherheit zu gewährleisten. Da die von der Funktion mcrypt zurückgegebenen verschlüsselten Daten Binärdaten sind, kann das direkte Speichern in einem Datenbankfeld andere Fehler verursachen, daher wird base64encode verwendet, um diese Daten zur bequemen Speicherung in eine Hexadezimalzahl umzuwandeln.
Referenzen: http://www.codeproject.com/Articles/363897/PHP-Security
Artikelquelle: http://blog.csdn.net/u010487568/article/details/29828757