Skip to content

Validierung von Eingaben im Kontaktformular

Meine Homepage hat noch ein Kontaktformular. Selbstverständlich findet sich auf derselben Seite auch meine Mailadresse (samt GPG-Key), und man sollte annehmen, dass das der übliche Weg zur Kontaktaufnahme wäre, aber überraschend viele Nachrichten erreichen mich dann doch noch über das Kontaktformular. Dafür mag es verschiedene Gründe geben: der Mailclient auf dem Arbeitsrechner (oder dem Smartphone) hat vielleicht kein Profil mit der gewünschten Absenderadresse - oder für den Absender ist “E-Mail” gleichbedeutend mit “GMail” oder einem anderen webbasierten Dienst, d.h. es wird gar kein Mailprogramm mehr verwendet. Sei dem, wie dem sei - das Kontaktformular wird (trotz Recaptcha) durchaus genutzt, und ab und an verschluckte es sich an unerwarteten Eingaben. Gerne genommen war beispielsweise ein Komma im Eingabefeld für den Namen (“Müller, Egon”). Da das Formular die Eingabe einfach 1:1 in das From:-Feld übernommen hat, fand sich da dann etwas wie

Müller, Egon <absender@domain.example>

Das aber gefällt der Technik nicht, denn ein , trennt im From: oder To: mehrere Absender/Adressaten voneinander. Soll im Namen ein Komma vorkommen, muss der gesamte Name in " gesetzt werden.

"Validierung von Eingaben im Kontaktformular" vollständig lesen

Naives MVC

Seit 2014 setze ich sowohl bei neuen Websites als auch bei der “Renovierung” alter auf static site generators, also Generatoren für statische Webseiten, die aus Templates und Inhalten in verschiedenen Markups, aus Helper-Klassen und ggf. auch Datenbankinhalten HTML-Seiten generieren, die dann auf den Server hochgeladen werden. Das hat verschiedene Vorteile ggü. CMS oder selbstgeschriebenem Code: weil nur statisches HTML ausgeliefert wird, muss auf dem Server keine Scriptsprache wie PHP laufen, was die Last vermindert und vor allem auch aus Sicherheitsgründen angenehm ist, denn wo kein Code läuft, gibt es auch keine Sicherheitslücken. Außerdem bringen Generatoren wie Nanoc, mein bevorzugtes Werkzeug, ein ganzes Toolset wie Helper-Klassen für häufige Aufgaben und Filter für die verschiedensten Markup-Formate mit. So habe ich mich daran gewöhnt, dass ich das Grundgerüst einer Website in Form von Templates, meistens in HAML, erstelle, für die optische Gestaltung CSS-Frameworks wie Bootstrap nutzen kann, wobei ein LESS-Compiler automatisch mitkommt, und dass ich die eigentlichen Inhalte in Markdown (oder in einer Kombination aus HAML und Markdown) erstellen kann. Auf diese Weise habe ich mir einen gut funktionierenden Workflow geschaffen.

Das alles erfüllt seinen Zweck im Grundsatz sehr gut, auch für in begrenztem Umfang dynamische Elemtente: es genügt ja, die Webseitengenerierung in regelmäßigen Abständen neu anzustoßen, bspw. nachts, oder wenn man will auch stündlich. Nanoc kann man zudem aus Datenbanken speisen, und auch beim bloßen Umgang mit Textdateien lassen sich deren Metadaten auswerten, um bspw. die letzten Änderungen zu verlinken, Termine anzukündigen (aber nur, solange sie noch bevorstehen), Zeitangaben automatisch zu ersetzen (“Diese Seiten stehen schon seit x Jahren online”) und anderes mehr. Man kann auch mal ein PHP-Script dazwischenmixen, beispielsweise für ein Kontaktformular. Ihre Grenzen erreicht die Technik erst, wenn es um tatsächlich dynamische Seiten geht, also bspw. die Suche in Datenbanken (bei der man die Einträge nicht schlicht insgesamt vorab als statische Seiten erzeugen kann) - oder wenn ein Passwortschutz (jenseits von Basic Auth) oder ein Session-Management implementiert werden soll. Dann braucht es etwas anderes. Nur was?

"Naives MVC" vollständig lesen

Webserver-Tuning

Alle paar Monate wieder turnt ein - weniger rücksichtsvoller - Crawler vorbei und spidert sich zügig durch alle Einträge meines Blogs. Damit brachte er meinen bisherigen Server gerne an den Rand seiner Leistungsfähigkeit, durfte dieser doch für jeden Link einen php-cgi-Prozess starten. Man merkte das recht schnell an den steigenden Antwortzeiten, und auch interaktiv auf der Shell machte sich die steigende load bemerkbar. Am Ende blieben meist einige php-cgi-Prozesse übrig, die man dann manuell mittels kill entsorgen durfte. (Vielleicht lag auch hier das eigentliche Problem, dass nämlich die genutzten Ressourcen nicht wieder freigegeben wurden. Hinter die Einzelheiten bin ich nie so recht gekommen.)

Die brandneue Maschine hingegen sollte durch FastCGI und massenhaft RAM sowie schnelle SSDs einem solchen Ansturm (auch bei weiterer Verwendung des doch eher schwergewichtigen Apachen) besser gewachsen sein - dachte ich mir. Bis eines Freitagmorgens die E-Mails des Monitoring-System eingingen, die mir mitteilten, dass der Webserver nicht mehr auf Anfragen reagiert. Gar nicht mehr.

"Webserver-Tuning" vollständig lesen

PHP-FPM - jetzt mit mod_proxy_fcgi

Vergangene Woche hatte ich darüber berichtet, wie man - unter Debian Jessie - PHP-FPM mit mod_fastcgi installieren kann. In den Kommentaren hatte Sven mir dann nachfolgend erläutert, wie sich die Einbindung einfacher und besser über mod_proxy_fcgi lösen lässt, vorausgesetzt, man hat (wie in Debian Jessie) einen Apache 2.4 vor sich.

Da mir das ebenfalls vorzugswürdig erscheint, beschreiben ich in der Folge nunmehr diese Variante.

"PHP-FPM - jetzt mit mod_proxy_fcgi" vollständig lesen

PHP-FPM mit Debian Jessie

Statische Webseiten sind nett (und durchaus wieder im Kommen), aber zumindest für manche Zwecke sind dynamisch generierte Seiten und die auf diese Weise ermöglichte Interaktivität doch dann besser oder gar notwendig. Facebook, bspw., würde sich als statische Seite dann doch eher schwierig gestalten.

Die Welt dynamischer Webseiten

Scriptsprachen

Dynamisch generierte Seiten bedingen, dass beim Aufruf einer Webseite nicht nur eine auf dem Server abgelegte Datei angezeigt wird, sondern dass ein Programm dort läuft, das die Ausgabe mehr oder weniger live generiert. Das hat ganz andere Implikationen für die Sicherheit des Servers, denn nunmehr läuft dort von außen erreichbarer Code, der schlimmstenfalls noch durch die Nutzer selbst aufgespielt werden kann. Nicht jeder, der seine ersten Gehversuche mit Scripts macht, hat dabei auch Fragen der IT-Sicherheit ausreichend im Blick - um das Problem einmal stark verharmlosend zu beschreiben. Gerade PHP hat nicht den Ruf, zumindest in den ersten Jahren seiner Entwicklung großes Gewicht auf das Fördern oder gar Erzwingen sicherer Praktiken gelegt zu haben, und viele lern(t)en es vor allem als eine Art Templating-Sprache kennen, die man irgendwie in seine HTML-Seiten einbettet, um ihnen damit eine erweiterte Funktionalität zu verleihen, ohne dabei groß an Konsequenzen zu denken (schuldig, euer Ehren!).

Rechteprobleme

Besondere Schwierigkeiten kommen hinzu, wenn mehr als ein Benutzer auf dem Server Scripts nutzen will. Denn wenn der Webserver bzw. der von diesem gestartete Interpreter das Script ausführen will, muss er es lesen können. Dann muss er aber - logischerweise - auch die Scripts aller anderen nutzer lesen können, was bedeutet, dass Nutzer A ein Sript schreiben kann, mit dem er sich die Scripts von Benutzer B anzeigen lassen kann, samt aller dort gespeicherten Informationen (Datenbankpassworte usw.), ebenso wie Dateien, die Benutzer B anlegt. Und wenn das Script irgendwelche Dateien anlegt (man denke an hochgeladene Bilder), dann werden diese Dateien unter der Nutzerkennung des Webservers angelegt, so dass der Benutzer dann keinen vollen Zugriff darauf hat. Das ist alles etwas unschön, weshalb man schon bald die Möglichkeit geschaffen hat, Scripts (sei es Perl, sei es Python, sei es PHP) unter der Benutzerkennung des jeweiligen Nutzers laufen zu lassen, dem das Script “gehört”.

suexec und suphp

Das schafft zwar andere Probleme, insbesondere im Bereich der Performance, denn nun kann ein Webserverprozess nicht mehr beliebig viele Scripts in parallelen Threads abarbeiten, weil diese ja vielleicht verschiedenen Nutzern gehören, so dass für jedes Script ein neuer Interpreter-Prozess gestartet werden muss, aber es ist doch in der Regel vorzugswürdig.

Für Scripts, die über die CGI-Schnittstelle (ja, ich weiß, das “I” steht schon für “Interface”) gestartet werden, stellt suexec die entsprechende Funktionalität bereit. Für PHP tat das traditionell suphp. suphp gibt es aber in Debian Jessie nicht mehr. Was also tun?

Als Lösung bietet sich PHP-FPM an.

"PHP-FPM mit Debian Jessie" vollständig lesen

Digitale Ausstellungsstücke

Wer (digitale) Fotos - in welcher Menge, Häufigkeit und Qualität auch immer - macht, der kennt das Problem, sie online verfügbar zu machen. Gut, das eigentliche Problem ist die Überwindung der eigenen Faulheit und das Auswählen, Sortieren, Umbenennen und ggf. Kommentieren einmal wirklich anzugehen, aber man möchte dazu auch die entsprechende, möglichst einfach verwendbare, aber alle notwendigen Funktionen bietende Software haben.

Man kann dazu Web-2.0-Dienste wie flickr nutzen, aber nicht jeder möchte das, sei es, daß man solchen Diensten generell nicht traut und/oder die Software lieber selbst installieren möchte, sei es, daß man am "Sharing" von Fotos gar nicht interessiert ist, sondern den Zugriff potentiell nur wenigen ermöglichen möchte. Insoweit habe ich dann schon einiges durch: mehr schlecht als recht selbst gebaute Implementationen für die Webseiten meiner Hilfsorganisation oder einer Newsgroup (seit ~ 2002), dann für meine private Homepage (ebenfalls seit ~ 2002) mig, ein sehr einfaches Script (auch deshalb, weil man von den Platzhirschen wie Gallery nicht viel Gutes über die Sicherheit hörte), und seit Anfang 2008 (nach dem Erhalt meiner neuen Kamera Weihnachten 2007) auch eine Gallery-2-Instanz, mit der ich allerdings nie so recht angefreundet hatte (zumal bis zu einem Kurzurlaub 2008 zurück noch Bilder zum Sortieren und Hochladen im Backlog liegen - siehe die einleitenden Worte zu diesem Artikel ;-)). Während ich jetzt darüber nachdachte, ob sich nicht ein Update auf Gallery 3 anbietet, bekam ich den weisen Rat, mir doch einmal piwigo anzusehen.

Und das hat mich überzeugt. Zumindest dann, wenn man eine Fotogalerie-Applikation nur für sich selbst ohne ausgefeiltes Benutzermanagement für mehrere Fotografen braucht (und wie oft teilt man sich eine Galerie wirklich zu mehreren?), ist piwigo eine tolle Lösung. Installation und Konfiguration sind einfach (Voraussetzungen: PHP und mySQL), wenn man das Prinzip einmal begriffen hat, der Upload ist übers Web wie auch einfach per FTP möglich, Thumbnails werden erstellt, Benutzer können in vorgegebene Rechtegruppen (Gast, Bekannter, Freund, Familie, …) oder in Nutzergruppen eingeteilt werden, und für Alben bzw. Fotos lassen sich dann die entsprechenden Zugriffsrechte setzen. Fotos lassen sich nicht nur in Alben, sondern in Kategorien zusammenfassen und zugleich noch beliebig taggen; der Benutzer kann sich die Fotos nach Kategorien oder Tags oder nach dem Kalender oder sonstwie anzeigen lassen, bekommt dabei aber immer nur die Fotos oder Kategorien zu sehen, für die er entsprechende Rechte hat. Außerdem gibt es eine Reihe vorgefertigter, recht ansehnlicher Skins.

Mir gefällt’s jedenfalls, und ich habe den heutigen Tag dann im wesentlichen dazu genutzt, aus den drei oder vier vorgenannten Quellen der letzten 10 Jahre die dort vorhandenen Fotos in einer Galerie zusammenzuführen und dann den Rest zu löschen. So gesehen also wie gestern ein weiterer Tag des Räumens und Sortierens. :-)

Mantis Bug Tracker und Mantis Graphs 1.0

Mantis (aktuell in der Version 1.2.1) ist ein ganz netter Bugtracker, also ein Ticketsystem (Fallbearbeitungssystem) für die Softwareentwicklung, dessen auffallendstes Manko allerdings die unterirdische Qualität der Dokumentation (weitgehend schlicht nicht vorhanden, ansonsten grob unvollständig oder weit veraltet) ist. *seufz*

"Mantis Graphs 1.0" ist ein Plugin für Mantis, das graphische Darstellungen ermöglicht, und ich habe heute längere Zeit damit verbracht, es in Betrieb zu setzen, nachdem es immer nur "unable to read/find font" von sich geben wollte. Einer der ersten Schritte war die Installation der msttcorefonts (aptitude install ttf-mscorefonts-installer), aber das genügte nicht. Längeres Debugging mit eingestreuten Statements im Quellcode ergab schließlich, daß Mantis weder das passende Font-Verzeichnis erkennen noch - bei expliziter Angabe des Verzeichnisses in der Konfiguration mit $g_system_font_folder - die Fontdatei laden wollte. Die Lösung dafür fand sich in der Dokumentation der PHP-Funktion file_exists(): diese liefert auch dann false zurück, wenn auf die entsprechende Datei aufgrund von safe_mode-Restriktionen nicht zugegriffen werden kann …

Und natürlich ist das der Fall: das Font-Verzeichnis - bpw. /usr/share/fonts/truetype/msttcorefonts/ - gehört root, und die Font-Dateien auch. Jedenfalls ist Owner dieser Dateien niemals der Webserver oder der Benutzer, unter dessen Kennung die PHP-Scripts dank su_php o.ä. ausgeführt werden. *brummel*

Es bleibt demnach nur der Verzicht auf die Grafiken oder die Deaktivierung von safe_mode (für Mantis).

Apache 2.x, php-cgi, mod_suphp und "No input file specified!"

Im Zusammenhang mit dem Update einer Maschine auf Debian Lenny bin ich auf das seltsame Phänomen einer - offensichtlich von PHP erzeugten - Fehlermedlung gestoßen: der Aufruf einer bestimmten Webseite (respektive des PHP-Scripts, das diese erzeugen sollte) ergibt nur die Meldung "No input file specified!". Google führt einen zu diversen Threads, die sich vor allem um die Konfiguration des richtigen Handlers für die Interpretation von PHP-Scripts und um hilflose Fragen von Benutzern, die eigentlich nur ein fertiges Paket installieren wollten und nun nicht mehr weiter wissen, drehen. Erst ein alter Blogeintrag in ixs’ Vodkamelone (nein, das hat nichts mit einem Kamel Nr. Eins zu tun!) von 2005 half mir auf die Sprünge.

Der Grund dieser Fehlermeldung ist offenbar ein ganz seltsames Zusammenspiel der Ausführung von PHP als mod_suphp, d.h. der CGI-Version von PHP in der Weise, daß Scripts unter den Rechten des jeweiligen Benutzers ausgeführt werden, mit der Vergabe von Datei- und Verzeichnisrechten. Die oben genannten Fehlermeldung tritt demnach genau dann auf, wenn zwar der Webserver auf die Datei bzw. ihr Verzeichnis zugreifen, sie also "finden" kann, der Benutzer selbst aber nicht. Dann findet der Webserver - unter der UID www-data - das Script, erkennt es, ruft den Handler auf, der als suid root installiert ist, sich Root-Rechte verschafft, damit auf die UID des Benutzers wechselt und dann mit diesen Rechten den PHP-Interpreter aufruft, um ihn das Script ausführen zu lassen. Dieser PHP-Prozess, der jetzt aber im Kontext des Benutzers läuft, kann dann selbst auf das entsprechende Verzeichnis nicht mehr zugreifen, das Script also auch nicht ausführen, und reagiert dann mit der obigen Fehlermeldung, denn er findet ja keine Datei, die er ausführen könnte.

Vielleicht hilfts ja jemanden, wenn ich ixs’ Analyse her noch einmal wiedergebe und verlinke. :-)