PHP-Quelltext anzeigen
Gunnar Bittersmann
- php
Auf meiner Website Star Trek series sorgt ein PHP-Script (index.php) dafür, dass die Rohdaten im JSON-LD-Format (erreichbar durch Endung .jsonld im URL) in HTML konvertiert werden.
Der Quelltext dieses Scripts soll auch für andere einsehbar sein. Ich habe deshalb eine Kopie davon als index.phps; den Rest erledigt die Servereinstellung für die Endung .phps durch meinen Hoster.
Die beiden Dateien sollten bis auf die Endung im Dateinamen identisch sein. Da ist es natürlich blöd, sie händisch zu synchronisieren. Würde ich den Webserver mein eigen nennen, wäre ein symbolischer Link von index.phps auf index.php das Mittel der Wahl.
Eine andere Möglichkeit wäre, das Script in index.phps zu pflegen und in der index.php steht lediglich:
<?php
@include 'index.phps';
Das fühlt sich aber nicht gut an, dass die index.php (die wohl weitaus häufuger aufgerufen wird als index.phps) jedesmal die index.phps aufruft. Besser wäre es andersrum: irgendwas, das aus der index.phps die index.php aufruft und mit dem richtigen MIME-Typen den Quelltext rausschickt. Wie kann ich das machen?
🖖 Живіть довго і процвітайте
Hallo Gunnar,
Das fühlt sich aber nicht gut an, dass die index.php (die wohl weitaus häufuger aufgerufen wird als index.phps) jedesmal die index.phps aufruft. Besser wäre es andersrum: irgendwas, das aus der index.phps die index.php aufruft und mit dem richtigen MIME-Typen den Quelltext rausschickt. Wie kann ich das machen?
wie wär's mit einem URL-Parameter? Dein PHP-Script könnte als erste Amtshandlung abfragen, ob $_GET['show-source'] gesetzt ist. Und wenn ja, gibt es den Content-Type text/plain und dann mit readfile() seinen eigenen Inhalt aus und endet dann.
Das sind drei, vier Zeilen am Scriptanfang, deren Zweck man den Interessierten sogar noch mit einem Kommentar erklären kann. Bildungsauftrag. 😉
Einen schönen Tag noch
Martin
Wie kann ich das machen?
mod_rewrite wäre eine Idee.
Mit ganz viel Vorsicht könnte das etwas wie
RewriteRule (.*)\.phps$ show.php?file=$1.php
tun. Ohne die Vorsicht zeigt das Skript show.php womöglich auch Dateien an, welche gerade nicht angezeigt werden sollten.
Martins Vorschlag mit dem Parameter wäre sicherer, übrigens auch vom Server völlig unabhängig und kann mit highlight_file() verfeinert angewendet werden:
if ( ! empty( $_GET['showSource'] ) ) {
highlight_file( __FILE__ );
exit;
}
Sieht aus wie der Kandidat meiner Wahl…
@@Raketenwilli
Ohne die Vorsicht zeigt das Skript show.php womöglich auch Dateien an, welche gerade nicht angezeigt werden sollten.
Solche sollte es nicht geben, zumal das Projekt auf Github liegt.
Was die index.phps eigentlich überflüssig macht; man kann sich ja das Script auf Github ansehen. (Die Idee mit index.phps stammt wohl noch aus der Zeit, bevor ich das Projekt auf Github gepackt habe.)
Aber ich sammle gern eure Vorschläge und werde sie mal testen.
🖖 Живіть довго і процвітайте
Solche sollte es nicht geben, zumal das Projekt auf Github liegt.
https://github.com/gunnarbittersmann/startrek/blob/main/series/index.php
Zeile 18:
$json = @file_get_contents($_GET['series'] . '.jsonld');
scheint mir heikel. Ich würde da zur Sicherheit "$_GET['series']" noch sanitizen. Ziffern und Buchstaben werden es wohl sein...
@@Mitleser 2.0
Zeile 18:
$json = @file_get_contents($_GET['series'] . '.jsonld');
scheint mir heikel. Ich würde da zur Sicherheit "$_GET['series']" noch sanitizen. Ziffern und Buchstaben werden es wohl sein...
In Zeile 19 wird das JSON-LD geparst: $data = json_decode($json, TRUE);
In Zeile 45 <?php if ($data): ?>
wird verzweigt, d.h. Zeilen 46 bis 293 werden nur ausgeführt, wenn es die Datei namens $_GET['series'] . '.jsonld'
tatsächlich gibt.
Im Else-Zweig ab Zeile 294 kommt $data
nicht vor. Ist das nicht sicher genug? 🤔
🖖 Живіть довго і процвітайте
In Zeile 19 wird das JSON-LD geparst:
$data = json_decode($json, TRUE);
In Zeile 45
<?php if ($data): ?>
wird verzweigt, d.h. Zeilen 46 bis 293 werden nur ausgeführt, wenn es die Datei namens$_GET['series'] . '.jsonld'
tatsächlich gibt.Im Else-Zweig ab Zeile 294 kommt
$data
nicht vor. Ist das nicht sicher genug? 🤔
Im Regelfall wird das soweit schon passen. Wenn ich es aber schaffen sollte, etwas "JSON-Parsebares" zu erwischen, was Du nicht nach außen geben willst…
Ich würde es absichern wollen, sei es auch nur um ruhig schlafen zu können. Alleine schon der Gedanke, dass bei jemand, der Dein Ding da klont in ein Problem läuft, was Du gar nicht auf dem Schirm haben kannst…
Soweit ich Deinen Code lese: ein gültiges JSON mit Attribut 'name', was vielleicht geheim bleiben sollte…
Probier es doch einfach mal aus:
https://bittersmann.de/startrek/series/index.php?series=../geheim
und leg dann das passende JSON-File dahin.
@@Mitleser 2.0
Im Regelfall wird das soweit schon passen. Wenn ich es aber schaffen sollte, etwas "JSON-Parsebares" zu erwischen, was Du nicht nach außen geben willst…
Ich würde es absichern wollen, sei es auch nur um ruhig schlafen zu können.
if (in_array($_GET['series'] . '.jsonld', scandir('.'))
bringt einen dann nicht um den Schlaf?
🖖 Живіть довго і процвітайте
if (in_array($_GET['series'] . '.jsonld', scandir('.'))
bringt einen dann nicht um den Schlaf?
Doch, durchaus. Der Parameter gehört komplett auf seinen Gültigkeitsbereich sanitized. In Deinem Fall: nur Ziffern und Buchstaben.
Samt Hinweis: bitte auf keinen Fall im selben Ordner '.jsonld' ablegen, die nicht öffentlich zugänglich sein sollen.
Allerdings sehe ich bei Github aktuell nur "$files = scandir('.');"
if (in_array($_GET['series'] . '.jsonld', scandir('.'))
bringt einen dann nicht um den Schlaf?
Doch, durchaus. Der Parameter gehört komplett auf seinen Gültigkeitsbereich sanitized.
Naja. Mal abgesehen von Klammern und unübersichtlicher Schreibweise müsste Gunnar vorher allerdings ziemlich krummen Dateinamen generieren. Wobei das natürlich einem Angreifer auch an anderer Stelle gelingen könnte. Nur braucht der dann dieses Problem längst nicht mehr. Der Check gegen einen existierenden Dateinamen sollte also genügen.
Naja. Mal abgesehen von Klammern und unübersichtlicher Schreibweise müsste Gunnar
Ansichtssache. Ich mag die Schreibweise tatsächlich auch nicht. Deine Schreibweise würde vermutlich statt einer dann acht Zeilen brauchen. Finde ich ebenso doof. Aber… Thema verfehlt. Bestenfalls hast Du eine Entwicklungsumgebung, die Dir DEINEN Coding-Style präsentiert. Was dann versioniert, deployt oder was auch immer wird, ist letztlich egal.
vorher allerdings ziemlich krummen Dateinamen generieren. Wobei das natürlich einem Angreifer auch an anderer Stelle gelingen könnte. Nur braucht der dann dieses Problem längst nicht mehr. Der Check gegen einen existierenden Dateinamen sollte also genügen.
M.E. nein. $_GET['series'] gehört da durch einen Regexp geschossen, der nur Zeichen und Ziffern erlaubt. Egal ob für scandir oder open_file. Fertig.
Einzige Stolperfalle, die dann m.E. noch bleibt: wenn da irgendein JSON-File im Ordner liegt, was man nicht publik machen möchte.
M.E. nein. $_GET['series'] gehört da durch einen Regexp geschossen,
Also wenn der Dateiname vorher aus dem eigenen Dateisystem gelesen wurde, sehe ich keine Stelle an der ein Sicherheitsproblem entstehen könnte, wenn man nachfolgend in exakt der gleichen Umgebung aus einer Datei mit exakt (Byte für Byte) gleichem Namen lesen will. Das ist es, was Gunnar vor hat.
Eine Beschränkung nicht etwa auf ASCII sondern auf einen Teil von ASCII kann aber aus anderen Gründen sinnvoll sein.
Z.B. ist \b
bzw. 0x08
das Steuerzeichen für einen Rückschritt. Jetzt sind zwar in Linux prinzipiell alle Zeichen außer dem Nulbyte in Dateinamen erlaubt - aber ich will bei manchen Experimenten mit Software dann doch lieber nicht dabei sein... Es macht sicherlich „viel Vergnügen“ eine Datei mit dem Steuerzeichen für den Rückschritt, EOF, EOT, BELL, ... im Name zu identifizieren oder zu adressieren um diese in irgendeiner Form (Inhalt, Eigenschaften) zu verändern oder auch nur zu löschen. Und die Symbole, z.B. aus asiatischen Sprachen, bereiten unter außerordentlich häufigen Umständen auch außerordentlichen „Spaß“, den ich zwar haben kann - aber nicht muss und längst nicht immer haben will.
@@Mitleser 2.0
Doch, durchaus. Der Parameter gehört komplett auf seinen Gültigkeitsbereich sanitized. In Deinem Fall: nur Ziffern und Buchstaben.
Siehe meine Antwort auf 🚀willi.
Samt Hinweis: bitte auf keinen Fall im selben Ordner '.jsonld' ablegen, die nicht öffentlich zugänglich sein sollen.
Dessen muss man sich natürlich bewusst sein.
🖖 Живіть довго і процвітайте
wenn es die Datei namens
$_GET['series'] . '.jsonld'
tatsächlich gibt.
Hm. Ja. Aber alles, was irgendwie auf das (File-)System feuert, bereitet auch mir Bauchschmerzen. Da mir die sanitize filters zu komplex (das ist eine eigene Fehlerquelle), vor allem zu instabil sind (da steht ziemlich oft "DEPRECATED" ...) genügt mir sowas:
function sanitizeFilenameStrictASCII( $s ) {
$n = preg_replace( '/[^a-zA-Z0-9._-]/', '', $s );
if ( $n === $s ) return $n;
return false;
}
Erlaubt: ASCII-Buchstaben, Ziffern, Punkt, Unterstrich und Minus-Symbol. Was nicht in die Vorgaben passt (Hier also auch kein Verzeichnis-Trenner) wird vollständig geancelt. Peng!
@@Raketenwilli
Erlaubt: ASCII-Buchstaben, Ziffern, Punkt, Unterstrich und Minus-Symbol. Was nicht in die Vorgaben passt (Hier also auch kein Verzeichnis-Trenner) wird vollständig geancelt. Peng!
Peng, ins eigene Knie geschossen.
Warum sollte ein Dateiname ausschließlich ASCII-Zeichen enthalten? Für uns Deutschsprachige kämen noch Umlaute und ß in Betracht. Eine Koreanerin möchte ihre Datei in Hangeul benennen: „스타트렉.jsonld“. Und wenn jemand „🚀.jsonld“ möchte – warum nicht? Dafür haben wir ja Unicode und Betriebssysteme, die damit umgehen können.
Die Beschränkung auf ASCII-Zeichen klingt wie aus dem vorigen Jahrtausend. Internationalisierung geht anders.
🖖 Живіть довго і процвітайте
Warum sollte ein Dateiname ausschließlich ASCII-Zeichen enthalten?
Zum Beispiel damit ich die Dateien unbestraft von Windows (10) zum „Fritzbox-NAS“ (7590, Neuestes FritzOS), vom „Fritzbox-NAS“ zu Linux (Ubuntu 22.04) transportieren kann. Und visa-versa. Hatte gerade erst den Fall, dass ich die Platte von der Fritzbox ziehen und unter Linux die Dateinamen reparieren musste. Vorher ging mit denen gar nichts mehr: Nicht per Weboberfläche der Fritzbox, nicht per FTP(S) nicht per CIFS. Und bevor ich um den Schreibtisch laufe versuche ich ziemlich viel.
klingt wie aus dem vorigen Jahrtausend
Vor einer Woche. Datum heute: 2022-12-29
Dafür haben wir ja Unicode und Betriebssysteme, die damit umgehen können.
Schön wäre es. Linux kann es... sogar mit Raketen-Dateien.
Außerdem würde ich einen Unterschied zwischen „technischen Dateien“ und Stuff wie „Wiedersehen mit Ödipus.png“ machen wollen.
Warum sollte ein Dateiname ausschließlich ASCII-Zeichen enthalten? Für uns Deutschsprachige kämen noch Umlaute und ß in Betracht. Eine Koreanerin möchte ihre Datei in Hangeul benennen: „스타트렉.jsonld“. Und wenn jemand „🚀.jsonld“ möchte – warum nicht?
Weil es nachweislich immer noch Systeme / NAS gibt, die damit nicht klarkommen.
Dafür haben wir ja Unicode und Betriebssysteme, die damit umgehen können.
Ja, diese Systeme (genauer gesagt Dateisysteme) gibt es. Aber verlassen kannst Du dich darauf nicht. Wenn Du dann mit blinder Gutgläubigkeit daher kommst, stehst Du als Softwaredienstleiter schnell vor einem Dilemma: Kunde andissen mit "Dein NAS ist scheiße, kauf Dir was Vernünftiges" oder einfach mit den Realitäten leben.
Ich präferiere Letzteres. Ob und wie weit ein Dateisystem mit Codierungen von Dateinamen klarkommt, ist nicht kriegsentscheidend. Metainformationen (Titel, Beschreibung, Autor) kriege ich eh nicht sinnvoll in den Dateinamen gepackt. Also brauche ich einen zusätzlich anderen Ort der Datenhaltung, wie z.B. eine Datenbank. Die muss Deine genannten Kriterien anno 2022 dann natürlich erfüllen.
Der Tradeoff "Dateinamen enthalten nicht das komplette Unicode-Spektrum" ist da m.E. absolut akzeptabel.
Die Beschränkung auf ASCII-Zeichen klingt wie aus dem vorigen Jahrtausend. Internationalisierung geht anders.
Große Worte, schön und toll. Realität geht anders.
@@Mitleser 2.0
Warum sollte ein Dateiname ausschließlich ASCII-Zeichen enthalten? Für uns Deutschsprachige kämen noch Umlaute und ß in Betracht. Eine Koreanerin möchte ihre Datei in Hangeul benennen: „스타트렉.jsonld“. Und wenn jemand „🚀.jsonld“ möchte – warum nicht?
Weil es nachweislich immer noch Systeme / NAS gibt, die damit nicht klarkommen.
Die würde ich aber als Ausnahme ansehen, nicht als Regel. Deshalb würde ich „nur ASCII-Zeichen in Dateinamen“ nicht als allgemeingültige Regel rausgeben. Wer das auf seinem System (bzw. dem seines Kunden) für sinnvoll erachtet, kann das natürlich so handhaben.
🖖 Живіть довго і процвітайте
Warum sollte ein Dateiname ausschließlich ASCII-Zeichen enthalten? Für uns Deutschsprachige kämen noch Umlaute und ß in Betracht. Eine Koreanerin möchte ihre Datei in Hangeul benennen: „스타트렉.jsonld“. Und wenn jemand „🚀.jsonld“ möchte – warum nicht? Dafür haben wir ja Unicode und Betriebssysteme, die damit umgehen können.
Weil das schon hier „so gut“ klappt:
Bildschirmfoto: Nicht jede OS-Installation hat Schriftarten, welche Hangeul-Zeichen umfassen. (und gib das mal blind mit der Tatstatur ein...)
Hallo,
Bildschirmfoto: Nicht jede OS-Installation hat Schriftarten, welche Hangeul-Zeichen umfassen.
ob diese Zeichen richtig angezeigt werden (können), ist ja nur ein optisches Problem. Für die Nutzbarkeit an sich (vom technischen Standpunkt her) ist das bedeutungslos. Sogar Copy&Paste funktioniert einwandfrei, auch wenn die Zeichen nur als Päckchen dargestellt werden.
Und ob diese Zeichen bei dir richtig angezeigt werden können, hast du selbst in der Hand - oder allgemein derjenige, der für die Administration des verwendeten Endgeräts verantwortlich ist. Aktuelle Windowse bringen beispielsweise jede Menge Fonts mit, die ein Durchschnittseuropäer nie braucht, die aber in diesem speziellen Beispiel dafür sorgen, dass die koreanischen Zeichen richtig angezeigt werden. Das gilt aber für viele Linux-Distros auch (mindestens mal für Ubuntoide).
(und gib das mal blind mit der Tatstatur ein...)
Das ist nun wieder ein ganz anderes Kapitel. Aber dafür gibt es ja die Zeichentabelle. Raussuchen, Copy, Paste, und gut. Wer solche Zeichen häufig braucht, wird sich ein Tastaturlayout installieren, mit dem die Eingabe einfacher wird.
Einen schönen Tag noch
Martin
@@Der Martin
(und gib das mal blind mit der Tatstatur ein...)
Das ist nun wieder ein ganz anderes Kapitel. Aber dafür gibt es ja die Zeichentabelle. Raussuchen, Copy, Paste, und gut.
Oder die Wikipedia. 😉
Wer solche Zeichen häufig braucht, wird sich ein Tastaturlayout installieren, mit dem die Eingabe einfacher wird.
Ich hab tatsächlich einen solchen Treiber installiert:
ⓈⓌⓉⒶⓉⓌⓇⒺⒾⒼ – voilà: 스타트렉
🖖 Живіть довго і процвітайте
(et voilà: Bildschirmfoto) Wenn mir das als Dateiname für einen Download angeboten wird, dann habe ich mit einer Standard-Installation (also ohne gigabyteweise Sonstwas-Schriften) ein Problem. Und zwar weil das Zeug mir dann unzugänglich ist.
@@Raketenwilli
(et voilà: Bildschirmfoto) Wenn mir das als Dateiname für einen Download angeboten wird, dann habe ich mit einer Standard-Installation (also ohne gigabyteweise Sonstwas-Schriften) ein Problem. Und zwar weil das Zeug mir dann unzugänglich ist.
Was ich nicht tragisch finde. Wenn du kein Hangeul lesen kannst, ist es ziemlich egal, ob du entsprechende Schriftarten auf deinem System hast oder nicht. Du gehörst nicht zur Zielgruppe dieser Ressource.
Die Zielgruppe (in dem Fall Koreanischsprecher) wird eine Hangeul-Schriftart installiert haben.
🖖 Живіть довго і процвітайте
...
function html($str) { echo htmlSpecialChars($str); }
Um sich (Ver-)Tipparbeit zu ersparen gibt es die Autovervollständigung der IDEs. Da muss man etablierten Funktionen keine sinnentfernenden Aliasnamen vergeben.
Hallo Anmerker,
böse, böse 😉
Die html-Funktion bringt aber auch noch ein echo mit.
Was ich in Summe ebenfalls ankreiden würde. Anstelle von
function html($text) {
echo htmlspecialchars($text);
}
<a href="<?php html($url)?>">
würde ich definitiv eine höhere Abstraktionsstufe und eine Lösung mit <?= ?>
statt <?php echo ?>
empfehlen wollen:
function html_attr($name, $value) {
return $name . '="' . htmlspecialchars($value) . '"';
}
<a <?=html_attr("href", $url)?>>
Bessere Benennungen sind zweifellos möglich. Das spart keinen Tippaufwand (es sei denn im Vergleich zum direkten Tippen von htmlspecialchars), aber die Funktion zum Generieren eines Attributs ist von der Ausgabe zum Browser separiert, was Wiederverwendbarkeit und Testbarkeit verbessert.
Rolf
@@Rolf B
würde ich definitiv eine höhere Abstraktionsstufe und eine Lösung mit
<?= ?>
statt<?php echo ?>
empfehlen wollen:function html_attr($name, $value) { return $name . '="' . htmlspecialchars($value) . '"'; } <a <?=html_attr("href", $url)?>>
Nö, das gefällt mir gar nicht. PHP wird hier als Templatesprache eingesetzt. (Ich hätte vielleicht eher von „Template“ als von „Script“ sprechen sollen? Wenngleich in den ersten paar Zeilen E und V stattfinden; ab Zeile 44 ist es das A der EVA.)
In einem Template sollte dann soviel wie möglich in der Zielsprache (hier: HTML) stehen, d.h. das Attribut als solches da sein, nicht durch eine Funktion in der Templatesprache generiert werden.
In Smarty wäre es <a href="{$url|escape}">
In PHP als Templatesprache: <a href="<?= htmlSpecialChars($url) ?>">
Wenn auf die selbstgestrickte html()
-Funktion verzichten (wofür es sicher gute Gründe gibt), dann würde ich das vorziehen (mit Kurzschreibweise <?=
).
🖖 Живіть довго і процвітайте
@@Raketenwilli
Mit ganz viel Vorsicht könnte das etwas wie
RewriteRule (.*)\.phps$ show.php?file=$1.php
tun.
So in etwa hab ich’s jetzt. Nur mit Vorsicht: ohne Wildcards. Ich brauch das ja nur für die index.php.
RewriteRule index.phps index.phps.php
und in der index.phps.php steht
<?php
highlight_file('index.php');
🖖 Живіть довго і процвітайте
@@Gunnar Bittersmann
Auf meiner Website Star Trek series sorgt ein PHP-Script (index.php) dafür, dass die Rohdaten im JSON-LD-Format (erreichbar durch Endung .jsonld im URL) in HTML konvertiert werden.
Der Quelltext dieses Scripts soll auch für andere einsehbar sein. Ich habe deshalb eine Kopie davon als index.phps; den Rest erledigt die Servereinstellung für die Endung .phps durch meinen Hoster.
Die beiden Dateien sollten bis auf die Endung im Dateinamen identisch sein. Da ist es natürlich blöd, sie händisch zu synchronisieren.
Ich hatte jetzt die glorreiche Idee, in index.phps zu schreiben:
<?php
highlight_file('index.php');
und in der .htaccess
AddType application/x-httpd-php .phps
Mit anderen Endungen als .phps funktioniert das auch. Bei .phps hingegen wird der Einzeiler der index.phps ausgegeben, nicht der Quelltext der index.php.
Ich kann auf die Art nicht die Voreinstellung meines Hosters überschreiben?
🖖 Живіть довго і процвітайте