• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

[Guide] Sichere Webanwendungen erstellen

tool

Neu angemeldet

Registriert
7 Aug. 2015
Beiträge
14
Hi zusammen,

da die Sicherheit im Internet derzeit ein brandheißes Thema ist, wollte ich an dieser Stelle eine kleine Einführung zur Websicherheit zusammenstellen, die die wichtigsten und häufigsten Schwachstellen in (hoffentlich) verständlicher Form vorstellt.

Dafür habe ich mir folgende Themen überlegt:
  • Logical Flaws
  • Cross Site Sripting (XSS)
  • SQL Injection (SQLi)
  • Local/Remote File Inclusion (LFI/RFI)
  • Remote Code Execute (RCE)
  • Cross Site Request Forgery (CSRF/XSRF)
  • Seitenkanäle

Durchgestrichene Themen folgen noch, die einzelnen Abschnitte werde ich nach und nach schreiben, wenn ich die Zeit dazu finde.


Logical Flaws

Was sind Logical Flaws überhaupt?

Ich besuche die Seite eines kleinen Shops für Schreibwaren, der derzeit eine Rabattaktion führt, bei der ab einer Bestellung im Wert von 25€ 5€ Rabatt gewährt werden, wenn der Gutscheincode eingegeben wird. Die Gelegenheit ist ideal, um meine Kugelschreibersammlung zu erweitern, also besuche ich den Shop und lege das gute Stück in den Warenkorb. Ich betrachte diesen nun und finde auch prompt das Feld zur Eingabe des Rabattcodes. Doch da mein Kugelschreiber nur 5,99€ kostet, verwehrt mir der Shop, den Gutscheincode einzulösen.
Zu blöd nur, dass ich den Kugelschreiber unbedingt will, aber mir kommt die Idee, meinen Warenkorb solange mit Artikeln zu füllen, bis der Gesamtwert über 25€ liegt. Erneut gebe ich den Gutscheincode ein. Dieses mal wird er akzeptiert und ich sehe im Warenkorb meine Artikel aufgelistet. Darunter eine Bemerkung, dass ein 5€-Gutschein aktiv ist.
Leider stelle ich fest, dass mein Monatsbudget für Kugelschreiber schon fast aufgebraucht ist und nur Geld für den ursprünglichen Kugelschreiber habe. Also entferne ich kurzerhand alle Artikel außer diesem aus dem Warenkorb. Beim nächsten Schritt zur Kasse entdecke ich zu meiner Überraschung, dass mir für den Kugelschreiber, der ursprünglich doch 5,99€ kostete, nur 99ct angerechnet werden.

Was ist hier passiert?

Obwohl es in dem Code des Shops keine keine Bugs im eigentlichen Sinn gibt, die ich ausnutzen könnte, ist es mir gelungen, einen Gutschein einzulösen, der erst ab einem Warenwert von 25€ genutzt werden dürfte. Die Entwickler haben bedacht, dass beim Einlösen des Gutscheins der Warenwert aller Artikel im Warenkorb größer als 25€ sein muss, doch vergaßen sie, dass Artikel auch wieder entfernt werden können und die Gültigkeit des Gutscheins dann erneut geprüft werden sollte. Da es sich bei allen Schritten um legitime Aktionen handelt, die von Programmierern vorgesehen und implementiert wurden, ist der Angriff schwer zu erkennen. Insbesondere automatische Tools wie Intrusion Detection Systems werden keinen Alarm schlagen, da schädliche Anfragen nicht von Unschädlichen unterscheidbar sind. Hier ist also nicht nur sichere Programmierung notwendig, sondern müssen Abfolgen von Interaktionen bei der Entwicklung des Shops berücksichtigt werden, um sich effektiv zu schützen.


Ein Paket Tee und 15 Schweizer Franken bitte

Wer kennt das nicht: Man sitzt gemütlich auf der Couch und genießt seinen Nachmittagstee als einem der Gedanke kommt, "Und jetzt noch für's Tee trinken bezahlt werden". Gesagt, getan! Nach einer kurzen Recherche im Internet bin ich auf einen Onlineshop für Tee gestoßen, bei dem ich mir meine eigene Mischung aus einer Liste von gegebenen Zutaten zusammenstellen kann.

1.PNG

Doch nicht nur die Zutaten kann ich zusammenstellen. Es scheint, mit der Anzahl der Zutaten ändert sich auch der Preis. Das ist ein genaueres Hinschauen wert. Tatsächlich werde ich im Quellcode der Seite fündig und entdecke folgenden Code-Ausschnitt:

[src=html4strict]<input type="hidden" name="preis" id="preisinput">
<input type="hidden" name="hot" id="hotinput">
<input type="hidden" name="intense" id="intenseinput">
<input type="hidden" name="sweet" id="sweetinput">[/src]

... nicht wirklich, oder? Doch.

2.PNG

Ich denke, die Lösung des Problems versteht sich an dieser Stelle von selbst: Der Preis sollte serverseitig anhand der Zutaten berechnet werden.

Der 0x-Trick

Gut, solche Tricks wie bei dem Tee-Shop gibt es nur noch selten zu finden - und wenn, dann werden sie meistens nach sehr kurzer Zeit ausgenutzt, fast behoben, nochmal ausgenutzt, und dann wirklich behoben. Deutlich unbekannter ist jedoch der 0x-Trick.

Für diesen Abschnitt habe ich leider kein Beispiel zum Anschauen parat, dafür aber ein wenig eigenen Code, der vereinfacht das Kennwort-Ändern Formular einer kleinen Seite entgegen nimmt:
[src=php]$password = $_POST['password'];
$userid = $_POST['uid'];

if($userid == 0) {
// admin user has id 0, don't change password
} else {
// change password
$sql = 'update users set password = "' . md5($password) . '" where id = ' . intval($userid);

// execute sql and stuff
}[/src]

Wenn man davon absieht, dass md5 ohne Salt für Kennworthashes genutzt wird, sieht das auf den ersten Blick recht sicher aus. Der Admin hat ID 0 und nur für andere Nutzer kann das Kennwort geändert werden. Oder?

PHP hat bekanntlich ein paar Macken, gerade was die Sicherheit angeht. Eine davon ist hier zu finden: Das Casten zu einem Integer passiert auf zwei verschiedene Wege.

Einmal gibt es einen impliziten Cast in der if-Bedingung und ein weiterer wird von intval() ausgeführt. Ist die Eingabe ein String, der eine Zahl in Hex-Repräsentation darstellt, also beispielsweise '0x1234', so wird dieser String in der if-Bedingung zum Integer 4660 gecastet und ist offensichtlich ungleich 0. intval() hingegen geht ein wenig anders vor: Die Funktion sucht im Eingabestring nach Zeichen zwischen '0' und '9', d.h. nach Ziffern. Wird ein Buchstabe gefunden, so wird die Zahl an dieser Stelle abgeschnitten:
intval('123') == 123
intval('12k3') == 12
intval('abc') == 0

Dreimal dürft ihr raten, was passiert, wenn der Eingabestring '0x1' ist.
lol, für sowas lohnt sich ein Spoiler nun echt nicht.
Na gut: intval('0x1') == 0

Wir haben also die if-Abfrage gebypassed und können nun das Admin-Kennwort ändern, obwohl dies im Code eigentlich ausschließlich zu unterbinden versucht wird.
Besser wäre es gewesen, wenn zusätzlich zu Beginn des Scripts intval direkt auf $_POST['uid'] angewendet worden wäre, da zu keinem Zeitpunkt im Script etwas anderes als eine Zahl erwartet wurde:
[src=php]$userid = intval($_POST['uid']);[/src]


Was sonst noch? Information Leak.

Logical Flaws sind bisher als eher kleinere Fehler aufgefallen, die recht einfach zu beheben sind. Problematischer wird es allerdings, wenn mittels Logical Flaws Informationen über den Server geleaked werden können, die einem böswilligen Hacker weitere Angriffe erleichtern. So wäre es denkbar, dass Local File Inlcusions (dazu später mehr) möglich sind, über die ein Angreifer Dateien auslesen kann, die nicht für die Öffentlichkeit bestimmt sind. Interessant ist beispielsweise das Webroot-Verzeichnis, um von dort systematisch nach bestimmten Dateien zu suchen.

An diese Informationen kann ein Angreifer kommen, indem er absichtlich Fehlermeldungen provoziert, die in PHP teilweise als Warnungen, teilweise als Hinweise und teilweise als kritische Fehler ausgegeben werden. Eine Warnung kann beispielsweise provoziert werden, indem ein Parameter, welcher in den Funktionsaufruf mysql_real_escape_string wandert, in der URL zu einem Array gemacht wird:

4.PNG

Um diese Problematik zu verhindern, sollten (technische) Fehlermeldung im Allgemeinen nur für die Entwicklung zugelassen werden, im Produktivbetrieb sollten diese jedoch abgeschaltet werden.
[src=php]error_reporting(0);[/src]

Doch auf diese Weise wird nur das Symptom behoben. Besser ist es, alle Werte und Parameter, die nicht vom Script selbst verwaltet werden, auf ihren Typ zu untersuchen, bevor diese verwendet werden. In PHP gibt es zu diesem Zweck die Funktionen isset, is_string, is_array, is_int, is_bool, is_float, is_decimal und viele Weitere. Wie im Fall einer falschen Eingabe vorzugehen ist, hängt von der Anwendung ab: manchmal genügt es, einen Standardwert stattdessen zu setzen, manchmal muss die Ausführung des Scripts abgebrochen werden.


Die robots.txt

Die robots.txt ist eine Datei, die Bots und Crawler anweist, welche Verzeichnisse durchsucht werden sollen und welche nicht. Die Angaben sind für Bots nicht verpflichtend und können umgekehrt Informationen über die Verzeichnisstruktur unter dem Webroot geben. Ist beispielsweise ein Eintrag vorhanden, der den Zugriff auf den Ordner /a82_secret_login_page verbietet, kann dieses Wissen eingesetzt werden, um eben den Pfad zum Login in Erfahrung zu bringen.
Als Alternative könnte der Eintrag in der robots.txt weggelassen werden und stattdessen in den HTML-Dokumenten unter diesem Pfad ein meta-Tag gesetzt werden, der Suchmaschinen die Indizierung verbietet:
[src=html4strict]<meta name="robots" content="noindex,nofollow">[/src]


Zusammenfassung

Bei der Entwicklung von Webanwendungen immer prüfen
  • wer welche Informationen sehen kann und darf.
  • auf welche Variablen ein potentieller Angreifer Einfluss hat.
  • typsicher programmieren.
  • die Gesamtlogik einer Webanwendung berücksichtigen.

Ich hoffe, dieser Text ist einigermaßen verständlich. Bei Unklarheiten beantworte ich sonst aber gerne Fragen. Kritik und Verbesserungsvorschläge sind immer erwünscht, insbesondere wenn ein ganzer Block im Text unklar/unschön/falsch ist. An dieser Stelle möchte ich auch anmerken, dass ich keine Gewähr für die Richtigkeit meiner Aussagen übernehme; Fehler können auch mir passieren.

Weitere Informationen zum Thema von anderen Usern
https://ngb.to/threads/17590-Guide-Sichere-Webanwendungen-erstellen?p=561125#post561125


Ich Gedenke bis zum Wochenende Anfang August (private Projekte sind Grund für Verspätung) das Thema Remote Code Execution zu posten.


Anmerkung 1: Mittlerweile hat der Betreiber des Tee-Shops das Problem erkannt und setzt bei negativem Preis den Gesamtpreis schlicht auf 0 CHF.
Anmerkung 2: Ich habe den Text vorm Posten kein zweites Mal gelesen. Yoloswag.
 
Zuletzt bearbeitet:

Jester

★★★★☆ (Kasparski)

Registriert
1 Dez. 2014
Beiträge
6.066
Ort
Code Azure
@tool:
Nice, klasse Artikel!

Nur bei einer Sache hätte ich etwas anzumerken: das noindex, nofollow ist zwar in der Theorie ok, in der Praxis aber - Google hat das auch schon explizit zugegeben - wird diese Angabe ignoriert - z.B. wenn es sich um (von Google so eingestufte) Themen von besonderer, aktueller Relevanz handelt. Sprich: sicher ist das nicht.

Gruß, J.
 

tool

Neu angemeldet

Registriert
7 Aug. 2015
Beiträge
14
  • Thread Starter Thread Starter
  • #3
@Jester: Okay, das war mir in der Form so nicht bekannt. Ist dieses Verhalten denn abweichend davon, wie Google Seiten über die robots.txt indizieren würde?
 

Jester

★★★★☆ (Kasparski)

Registriert
1 Dez. 2014
Beiträge
6.066
Ort
Code Azure
Google hält sich grundsätzlich an die in der robots.txt hinterlegten Restriktionen, andere Suchmaschinen/Bots halten sich unter Umständen nicht daran Schnelle Quelle

Bei den Meta-Daten "noindex, nofollow" sagte Google explizit, dass diese unter Umständen ignoriert werden Quelle

Unter dem Strich bedeutet das, dass beide Verfahren nicht 100% sicher sind, dass der so gekennzeichnete Inhalt nicht doch in den Index wandert.

Gruß,
J.
 

virtus

Gehasst

Registriert
24 Apr. 2015
Beiträge
1.689
Ort
AUF DEM MOND
Hier werden nur ein paar Negativbeispiele aufgezählt, aber ein wirklicher Guide zum programmieren sicherer Webanwendungen ist das nicht.
Zumal ausschließlich PHP und Logikfehler betrachtet werden.

Google scannt unabhängig von robots und meta-Feldern die vollständige Seite. Listet allerdings nur die Inhalte, die tatsächlich entweder gar nicht oder als erlaubt markiert sind. Prinzipiell ist die Akzeptanz der robots.txt bzw. meta-Felder rein freiwillig. Man kann damit nicht verhindern, dass auf den Content zugegriffen wird. Wie bei den "Betreten der Baustelle verboten"-Schildern.
 

Kugelfisch

Nerd

Registriert
12 Juli 2013
Beiträge
2.342
Ort
Im Ozean
Eine Ergänzung zu PHP-Logikfehlern: Das Problem betrifft nicht nur den beschriebenen Fall, schwach typisierte Vergleiche (d.h. der PHP-Operator [kw]==[/kw]) und das PHP-Type-Juggling sollten im Allgemeinen mit höchster Vorsicht verwendet werden. Insbesondere kann der schwach typisierte Vergleichsoperator in PHP auch dann eine Typkonvertierung durchführen, wenn die beiden Operanden bereits von identischen Typen sind! Das klassische Beispiel dafür ist wohl
PHP:
if("0" == "0E823078838802729574831914927860") {
// ...
}
Obwohl in diesem Fall zwei Strings verglichen werden, wandelt PHP die Werte in Gleitkommazahlen um und vergleicht diese, der Vergleich liefert demnach true; dieses Verhalten hat in der Vergangenheit u.a. in TYPO3 bereits zu einer kritischen Schwachstelle geführt: http://blog.nibblesec.org/2010/12/typo3-sa-2010-020-typo3-sa-2010-022.html


Ein damit zusammenhängendes weiteres Problem ist das automatische Parsen der übergebenen Parameter in $_GET, $_POST, $_REQUEST und $_COOKIE sowie das Verhalten im Fehlerfall. Zum Beispiel liesse sich in
PHP:
if(strcmp($_GET['secret'],'ThisStringIsSecret') == 0) {
 // Login erfolgreich
}
der Vergleich umgehen, indem als GET-Parameter [kw]secret[]=42[/kw] übergeben wird - der Punkt dabei ist, dass PHP aufgrund der an den Parameternamen angehängten Klammern automatisch ein Array (mit dem einzigen Element `42` als String) in [kw]$_GET['secret'][/kw] erzeugen wird. Dies führt wiederum dazu, dass [kw]strcmp()[/kw] eine PHP-Warnung erzeugt und NULL zurückliefert. Schliesslich werden NULL und 0 schwach typisiert vergleichen, was true liefert.


Grundsätzlich empfiehlt es sich, in PHP immer den stark typisierten Vergleichsoperator [kw]===[/kw] und ggf. explizite Typecasts zu verwenden, speziell wenn vom Benutzer beeinflussbare Daten involviert sind.
 

tool

Neu angemeldet

Registriert
7 Aug. 2015
Beiträge
14
  • Thread Starter Thread Starter
  • #7
@virtus: Danke für deinen Kritik. Vorm Schreiben des Posts habe ich mir überlegt, was ich mit diesem Thread erreichen möchte. Mir schien es wichtig, dass der Leser nicht eine Anleitung liest, sondern zunächst einmal von dem typischen Denkmuster "Wie programmiere ich, damit mein Code funktioniert wie geplant?" wegkommt und sich stattdessen die Frage stellt "Wie funktioniert mein Code, wenn nicht bedachte Fälle (Parameter-Typen ändern, bestimmte Strings bei SQLi, ...) auftreten?".

Ziel Nummer zwei ist: Ich möchte den Leser in die Thematik einführen und mir sicher sein, dass es auch als Einführung verstanden wird. Mein Wissen ist nicht perfekt und noch viel weniger vollständig. Ich möchte zu keinem Zeitpunkt den Eindruck erwecken, dass man sicher programmiert, wenn man sich an meine Posts hält. Wichtiger wäre mir, dass der Leser versteht, dass es bei Angriffen keine Tabus gibt und dass jeder Userinput - egal welcher Form - Schaden anrichten kann, wenn man nicht richtig damit umgeht.

Ich möchte deine Kritik aber nicht ignorieren. Ich würde meinen Stil weiterhin so beibehalten, aber einen zusammenfassenden Abschnitt "Lessons learned" einführen, der stichpunktartig kurze Informationen für die Entwicklung bereithält, die aber nicht weiter erläutert werden. Das Verständnis für diese kann dann hoffentlich aus den vorhergehenden Abschnitten selbst gewonnen werden oder durch fortführende Ressourcen (die mir per PN vorgeschlagen wurden und ich ebenfalls im nächsten Post einführen werde).


@Kugelfisch: Dein Post spricht nochmal zwei Themen an, die ich mittlerweile selbst nicht mehr im Kopf hatte. Danke dafür, ich werde denen Post entsprechend im Startpost verlinken. Eine kleinere Anmerkung habe ich aber zu deinem Post ebenfalls:
Der Vergleich von Kennworthashes mit dem ==-Operator kann genau aus dem Grund, den du genannt hast, kritisch sein. Das Szenario ist: Dem Angreifer ist ein Hash mit Salt bekannt, der zu einem User gehört und möchte sich nun mit den Benutzerdaten einloggen. Ein typischer Brute-Force-Angriff ist wahrscheinlich zu aufwändig, doch sollte durch Zufall der Hash des Users das Format "0e[nur ziffern]" besitzen, so muss der Angreifer auch nur einen Hash vom Typ "0e[nur Ziffern]" finden. Bei MD5 (sollte nicht unbedingt für Kennworthashes eingesetzt werden, ist aber noch häufig der Fall) würde die Wahrscheinlichkeit von 2^-128 auf ca. 2^-28 steigen und wäre damit 2^100 mal schneller. *

* (1/16)^2 * (10/16)^30 = ca. 2^-28, wobei (1/16)^2 zustande kommt, da "0e" am Anfang fix gegeben ist und (10/16)^30, da die restlichen 30 Hexzeichen einen Wert zwischen 0 und 9 haben müssen, damit der Hash als Zahl interpretiert wird.
 

tool

Neu angemeldet

Registriert
7 Aug. 2015
Beiträge
14
  • Thread Starter Thread Starter
  • #8
Hi,

eigentlich wollte ich schon längst den Post zu Remote Code Execution online haben, doch habe ich es erneut nicht geschafft. Es kamen ein paar neue private Projekte hinzu, die erstmal Priorität haben. Daher bitte ich um Entschuldigung für die Verspätung.

Der RCE-Post ist aktuell etwa halb fertig, allerdings habe ich es in den letzten zwei Wochen nicht geschafft, weiterzuschreiben. Sobald ich wieder etwas mehr Luft habe, werde ich die versprochenen Posts liefern, aber ich möchte das Ganze erst einmal unbefristet verschieben und euch dies wissen lassen.

An dieser Stelle möchte ich aber dennoch ermöglichen, dass andere User einen Guide zu den im Startpost aufgelisteten Themen schreiben können, wenn sie möchten. Ich würde mich darüber freuen und den Post entsprechend verlinken.

Bis dann!
 
Oben