Seite besser absichern

nchristoph

Erfahrenes Mitglied
Hallo zusammen,

ich bin gerade dabei, eine Seite von PHP 5 auf PHP 7 upzugraden.

Im Zuge dessen möchte ich die Seite gleich in punkto Sicherheit aufrüsten.

Folgendes mache ich momentan:

- Prepared Statements
- ID durch intval absichern
- Passwort und Login mittels BCrypt

Was kann ich noch verbessern? Ich habe natürlich schon gegooglet und habe unter anderem filter_input gefunden, soll ich das zusätzlich zu Prepared Statements verwenden um z.b. meine Suche besser abzusichern?
Gibt es eine aktuelle Bestpractice in Punkto Sicherheit und PHP?

lt. SQL Map ist meine Seite nicht SQL Injection fähig aber trau schau wem.

Hat wer Tipps zu dem Thema?
 
unter anderem filter_input gefunden, soll ich das zusätzlich zu Prepared Statements verwenden um z.b. meine Suche besser abzusichern?
Sofern du es zur Validierung deiner Business Rules nicht benötigst, würde ich das nicht machen. Würdest du etwa Quotes aus Freitexten löschen wollen? Dann hast du die Texte nur noch 'kaputt' in der DB stehen.

- Prepared Statements
Sehr gut!
- ID durch intval absichern
Sei dir darüber im Klaren, dass bei Nutzung von Prepared Statements keinen Sicherheitsgewinn darstellt, außer du siehst es als Vorsichtsmaßnahme, falls mal doch ein SQL manuell zusammengebaut wird.
Überprüfung der ID auf eine Zahl ist Teil der Business Logik/Validierung.
- Passwort und Login mittels BCrypt
Sehr gut! Anscheinend ist bcrypt immer noch State of the Art: Are there more modern password hashing methods than bcrypt and scrypt?

Gibt es eine aktuelle Bestpractice in Punkto Sicherheit und PHP?
Generell kann ich dir OWASP empfehlen: Category:OWASP Top Ten Project - OWASP

Ich hätten noch HTTPS mit TLS vorgeschlagen, HTTP Strict Transport Security und Content Security Policy.
 
Danke ComFreek für deine ausführliche Antwort.

Momentan entschärfe ich nur die ID über Intval, wie kann ich Text sonst noch entschärfen?
addslashes(), htmlspecialchars()?

Gibt es mit PHP7 da neue Mechanismen?

Habe vergessen zu erwähnen, das ich HTTPS mittels Let's Encrypt Zertifikat verwende.
 
Zuletzt bearbeitet:
Momentan entschärfe ich nur die ID über Intval, wie kann ich Text sonst noch entschärfen?
addslashes(), htmlspecialchars()?
Ich glaube, dass du den Sinn von Entschärfen nicht ganz verstanden hast ;) Vielleicht ist das auch das Wort "Entschärfen" bzw. "Escaping" missverständlich. Es ist nicht Ziel, alle möglichen Funktionen draufzuwerfen in der Hoffnung, dass jede Funktion die Wahrscheinlichkeit einer "Explosion" (um die Bombenanalogie weiter zu bemühen; eines Exploits) zu verringern.

Wenn du z. B. eine Nutereingabe in einem <input>-Feld wieder in ein solches ausgeben möchtest, dann würde man das naiv so tun:
PHP:
<!-- XSS possible - DO NOT USE -->
<input type='text' value='<?php echo $_GET['variable']; ?>'>
Probleme tauchen dann auf, wenn $_GET['variable'] selbst Single Quotes (und wahrscheinlich bei anderen Zeichen auch) enthält.

Vergleiche das mal mit Code einer klassischen (non-Web) GUI-Anwendung, etwa C mit WinAPI oder Java mit Swing:
Java:
// Somewhere defined to reference the GUI's text field
TextField myInputField = ...

String userInput = readFromUser();
myInputField.value = userInput;
Warum ist das hier kein Problem?
Weil die Nutzereingabe niemals aus dem Kontext "ausbrechen" könnte. userInput wird ganz eindeutig nur value zugeordnet, es ist klar, dass auch wenn userInput HTML oder JS enthält, value-Attribute von TextFields nicht plötzlich anfangen werden, HTML oder JS zu interpretieren!

Warum geht das bei HTML nicht? Das ist einfach eine Einschränkung von HTML als Plaintextsprache.

Vergleiche auch nochmal dasselbe Beispiel mit JS und DOM:
Javascript:
const myInputField = document.getElementById('my-input-field');
// No danger
myInputField.value = readFromUser();

// However this is dangerous
document.body.innerHTML = readFromUser();

Wann immer man Werte zuweist/ausgibt, muss man sich dem Kontext bewusst sein. Wenn man mit PHP wie oben im ersten Codebeispiel einen Wert ausgibt, so ist der Kontext HTML oder genauer "HTML-Attribut mit Single Quotes". D.h. alles was man ausgibt, wird zwangsläufig als HTML-Attribut interpretiert. Und wenn es Single Quotes enthält, dann wird eben das Attribut als abgeschlossen interpretiert.

Sicherheitslücken treten immer dann auf, wenn der intendierte Kontext != dem eigentlichen Kontext ist.

Bei SQL Stringinterpolation (= Werte mittels Stringkonkatenation einfügen) ist es ähnlich: der Kontext ist SQL, der beabsichtigte ist aber z. B. "reiner uninterpretierter String-Wert", den man einfügen möchte.

Zum Glück bieten heutige DB-Driver Prepared Statements an. Ähnlich wie das JS-Beispiel oben hat man nun "Struktur" und kann explizit Werte einfügen im Gegensatz zu davor: man hatte nur die Plaintextsprache SQL.
Man möchte eigentlich immer Struktur und keine Plaintextsprache haben, sobald man in irgendeinerweise automatische Verarbeitung mit variablen Eingaben anstrebt.

Ich hoffe, ich konnte rüberbringen, warum es nicht zweckmäßig ist, irgendwelche Escape-Funktionen im Voraus auf die Daten zu werfen, ohne zu wissen, wo man sie am Ende ausgibt.
Es gibt noch einen anderen Grund: Durch diese Funktionen änderst du die Repräsentation des Wertes. Wenn der ursprüngliche String Single Quotes enthielt, so enthält er nun Vorkommnisse von \'. Wenn du den neuen Wert nun etwa in einem Kontext nutzt, in dem \' keine Funktion hat, etwa im DOM in einem value-Attribut, so wird tatsächlich auch \' übernommen!

Gibt es mit PHP7 da neue Mechanismen?
Dazu kann ich dir leider nichts sagen, da ich schon länger nichts mehr in PHP programmiert habe ;)

Du könntest noch SSL Server Test (Powered by Qualys SSL Labs) auf deiner Seite laufen lassen.


PS: Analog zum Statement oben gilt auch:

Encoding-Probleme treten immer dann auf, wenn der intendierte Kontext != dem eigentlichen Kontext ist.
Etwa hast du eine Datei als UTF-8 kodiert, aber der Editor öffnet sie in UTF-16. Das kommt es zu Darstellungsfehlern.
 
Zuletzt bearbeitet:
Hallo Comfreek,

danke für die weiterführende Erklärung.

Ich bin halt in diesem Thema ein gebrandmarktes Kind, einmal gehackt worden und seitdem ein bissel überparanoid.

Werde mir den Link vom Servertest einmal ansehen.
 
Zurück