Sicheres Surfen unter Privacy-Aspekten – Tracker, Cookies, Cookie-Banner und Werbung blockieren

Cookie-Banner der Webseite thomann.de
Keine Kekse? Die Firma Thomann fragt danach in einem schön gestalteten Cookie-Banner – trotzdem kann so etwas nerven.

Beim Surfen im Web begegnet man heutzutage quer durch die Bänke der verschiedenen Browser und Betriebssysteme einigem, das das angenehme Surfen erschwert: Entweder nerven Cookie-Banner, man wird über sämtliche Webseiten mit der immer gleichen Werbung bombardiert und im Hintergrund sammeln Google und Co. fleißig Daten über unsere Webseitenbesuche oder Online-Käufe.

In diesem Beitrag geht es um folgende Fragen:

  • Wie kann man „sicher“ surfen, ohne dass Daten über mich und mein Surfverhalten abfließen?
  • Was kann ich tun, um trotzdem einigermaßen bequem zu Surfen, ohne von Cookiewarnungen gestört zu werden? Und:
  • Wie bekommt man das Blockieren von Cookies in den Griff, ohne dass mein Browser die Webseiten vor lauter Datenschutzeinstellungen nicht mehr richtig anzeigen kann (bespielsweise weil im Hintergrund die nötigen Funktionen zur Anzeige blockiert werden)?

Die c’t hat sich mit diesen Themen auch vor einiger Zeit beschäftigt. Hier versuchen wir, mit noch etwas weniger Aufwand möglichst viel zu erreichen und gehen dabei möglicherweise nicht ganz so weit wie die c’t.

Worum es hier nicht geht

Natürlich gibt es weitere Themen, die ebenso beachtenswert sind, wie beispielsweise „Das absolut sichere Betriebssystem fürs Online-Banking“ oder sehr effektive Skript-Blocker wie NoScript – eines der wirkungsvollsten Tools beim Blockieren von Webinhalten, aber auch eines der am schwierigsten zu bedienenden Tools, wo täglich viel Handarbeit beim Surfen nötig ist. Aber: Geht man so tief, dann bewegt man sich erstens an den Grenzen dessen, was man einem „normal-IT-informierten“ Menschen zumuten kann. Das ist also nur in den seltensten Fällen etwas, das man seinen Eltern empfehlen oder gar einstellen mag.

Zum anderen soll es hier ja um bequeme Lösungen gehen, die alltagstauglich und für alle schnell umsetzbar sind.

Auch das anonyme Surfen ist nicht Ziel dieser Betrachtung.

Der richtige Browser

Bei der Browser-Wahl ist man immer am Rande der Gretchenfrage: Wie hast Du’s mit dem Webbrowser? Firefox? Chrome? oder gar: Edge? Sicherlich kann man die Entscheidung, welches Programm man nutzt, guten Gewissens als Geschmacksfrage betrachten. Objektiv gesehen gibt es Browser, die privacyfreundlicher sind als andere. Erst vor kurzem gab es in der c’t 14/2021 vom heise-Verlag einen Browsertest dazu, siehe hier. Der eigentliche Test in der Onlinefassung befindet sich leider hinter einer Paywall, aber an der Überschrift lässt sich schon das Ergebnis erahnen: Vorne liegen der Brave-Browser (auf dem Google-freien Chromium-Browser basierend), dicht gefolgt von dem bekannten Mozilla Firefox und der Apple-Browser Safari.

Würde man eine Empfehlung aussprechen, ist der Brave-Browser ohne weitere Einschränkungen zu empfehlen. Will man aber noch einige Add-Ons einsetzen, die das bequeme, privacy-bewusste Surfen wirksam unterstützen, hat der Firefox die Nase vorn. Es gibt sicherlich auch für Chrome/Chromium/Brave gute Erweiterungen, aber hier legen wir den Fokus auf den Mozilla-Browser – wobei viele der hiesigen Erweiterungsempfehlungen sowohl für den Firefox als auch für chromium-artige Browser verfügbar sind.

Damit gibt es auch eine klare Warnung vor dem von Google entwickelten Chrome-Browser: Hier werden sämtliche Websuchen, Google-Ergebnisse und aufgerufene URLs mit Google geteilt. <ironie>Falls Sie als Chrome-User:in also mal vergessen haben sollten, auf welcher Webseite Sie dies oder jenes gefunden hatten: Einfach mal bei Google nachfragen, dort wissen sie das sicherlich noch.<ironie /> Bei Chromium und bei Brave ist dies nicht der Fall. Zudem avisiert Google seinen User:innen, dass es zukünftig jegliche Erweiterungen, die die Übermittlung von Werbeanzeigen einschränken, nicht mehr zulassen will.

Kekse ja/nein und wenn ja, wie viele? Cookie-Banner blockieren

Wer es satt ist, bei jeder neuen Seite die Bestätigung für mehr oder weniger Cookies geben zu müssen, und sich darüber zu ärgern, dass die Banner fast alle unterschiedlich aussehen  (und wo war jetzt nochmal die Funktion zum Konfigurieren, wie viel Cookies was an welche Firma weitergeben?), dafür ist das Add-on „I don’t care about Cookies“ geeignet. Nicht ausnahmslos, aber doch in einem größeren Anteil werden sämtliche Cookie-Banner im Hintergrund ohne menschliches Zutun „beantwortet“. Dies jeweils möglichst privacyfreundlich. Wer mag, kann bei fehlgeschlagenen Cookiebannerblockierungsversuchen die URL an den Betreiber übermitteln, in der Hoffnung, dass zukünftig auch diese URL cookie-banner-frei sein wird.

Cookies automatisiert löschen

Der Firefox bringt von sich aus einige cookie-freundliche Einstellungen mit, die man unter den Einstellungen findet. Werden dort Cookies generell blockiert, kann das zu Problemen beim Surfen führen, gerade dann, wenn man beispielsweise bei Webshops eingeloggt ist. Sicherlich ist der Inkognitomodus hier auch eine Möglichkeit, aber wenn man „einfach nur“ möchte, dass nach dem Besuch einer Webseite das dazugehörige Sessioncookie und andere gelöscht werden, leistet dies das Add-on „Cookie Auto-Delete“ (für Firefox und Chrome/ium). Dies lässt sich außerdem konfortabel einstellen, wo wann und in welcher Frequenz Cookies nach Webseitenbesuchen gelöscht werden sollen.

Übermittlung von Daten an Drittanbieter überwachen/deaktivieren

Wissen Sie, wer im Hintergrund eigentlich mitliest, wo und auf welchen Seiten Sie surfen? Das zu analysieren kann schon mal zu überraschenden Erkenntnissen führen. Dazu brauchen Sie das Add-on uBlock origin. Dies gibt es ebenfalls für Firefox und Chrome/ium.

Wenn Sie es ausprobieren wollen, gehen Sie einmal auf die Webseite der Süddeutschen Zeitung oder noch besser: dem Spiegel und schauen Sie, wo die Daten hinfließen! Übrigens: Bei der Zeit besteht übrigens die spannende Option, sich von der Datenübermittlung freizukaufen, für ein paar Euro pro Woche…

Ebenso wirkungsvoll ist der „Privacy Badger„. Hier eine Entscheidung zu fällen, ob uBlock oder der Privacy Badger seine Dienste besser leistet, ist schwer abzuwägen. Beide Add-ons lassen sich bestens nebeneinander betreiben, und meistens werden beide Erweiterungen „fündig“.

Werbung blockieren

Auch das Ermitteln von Werbeanzeigen und das Eintragen in eine Blocklist erledigt das uBlock Origin. Zudem werden Übermittlungen von Webseiten, die bekanntermaßen Schadsoftware verteilen, wirkungsvoll blockiert.

AdBlock Plus ließe sich unter Umständen auch als Werbeblocker verwenden, wobei in den letzten Jahren bekannt wurde, dass bestimmte Werbeeinblendungen bewusst durchgelassen wurden. Offiziell heißt es „einige, nicht aufdringliche Werbung„. Jedoch gab es in der Vergangenheit gewisse Verdachtsmomente, dass sich Werbetreibende auf eine Allowlist einkaufen konnten. Hierzu sei auch auf ein Gerichtsurteil hingewiesen.

Ganz abzuraten ist von AdBlock Plus also nicht. Aber uBlock origin erfüllt sehr ähnliche Zwecke, und zwar sehr wirkungsvoll, so dass die Empfehlungstendenz hier eher in Richtung uBlock geht.

Noch etwas zur Suchmaschinennutzung

Viele Webinhalte sind so ausgelegt, dass die Datenkrake Google sie möglichst gut finden kann. Die Technik der Search Engine Optimization („SEO“) macht leider dort Halt. Beispielsweise schafft es die deutlich datenschutzfreundlichere Suchmaschine duckduckgo.com nicht, sämtliche Inhalte der uni-koeln.de-Webseiten auszulesen. Sucht man etwas auf den universitären Portal- oder Verwaltungsseiten, ist Google derzeit oft die einzige Suchmaschine, die zu den richtigen Stellen führt.

Aus Privacy-Sicht ist duckduckgo.com fraglos die Suchmaschine der Wahl. Aber sie ist leider eben nicht so effektiv, wie man sich das wünscht. Immerhin ist zumindest ein Großteil der Seiten darüber auffindbar. Für uni-koeln-Ergebnisse aber steige ich hin und wieder temporär auf Google um (beispielsweise im Inkognito-Modus).

Fazit

Wer will, kann etwas dafür tun, weniger transparent im Netz unterwegs zu sein. Letztlich ist das Katz- und Mausspiel des Datensammelns durch die DSGVO zwar nicht völlig ausgeschlossen worden, aber zumindest ist das Thema des Schützens der eigenen (Surf-)Daten den Menschen nun etwas bewusster geworden. Mit dem Interesse wuchsen auch die Anreize für Entwicklungsteams, mit Browsererweiterungen wirksam die Übermittlung von Surfdaten zu unterbinden. So ganz intransparent ist man als User:in natürlich nie, aber zumindest fällt es den Datensammelstellen so etwas schwerer, uns allzusehr zu einem vollständigen Profil zusammenzusetzen.

Firefox 89 und sein neues Design: Möchte noch jemand zurück zum alten Firefox?

Firefox Proton
Firefox – Protoneinstellungen

Seitdem ich den Browser Firefox in der Version 89 installiert habe, ist deutlich weniger Platz auf meinem Notebook-Bildschirm: Die obere Tab-Leiste erhält mehr Höhe im Vergleich zu vorher, und für die runden Ecken um jeden Tab herum werden wieder weitere Pixel verschenkt. Mag sein, dass dies viele User:innen so mögen – aber mir ist die alte, platzsparendere Variante beispielsweise auf meinem 13″-Bildschirm deutlich lieber.

So ging es wohl auch weiteren Firefoxer:innen – und kurz nach Veröffentlichung der Version 89 kursierten einige Anleitungen, wie man mit Hilfe der about:config wieder zurück zum alten Design springen kann. Ich verlinke mal auf eine schöne Schritt-für-Schritt-Anleitung:
https://news.itsfoss.com/firefox-old-design-switch

Leider wird diese Änderungsmöglichkeit vom Entwicklungsteam aber nicht gern gesehen. In den offiziellen Bug-Foren findet sich ein entsprechender Eintrag. Es dürfte also nur eine Frage der Zeit sein, bis diese Anpassung nicht mehr möglich ist, weil man die Einträge in der about:config löschen möchte. Bleibt nur zu hoffen, dass sich Fans finden, die vielleicht ein entsprechendes Small-Theme programmieren werden.

Disclaimer: Wie einigen hier schon bekannt sein dürfte, sind Änderungen im Bereich der „about:config“ natürlich mit Vorsicht zu genießen… man kann dort seine Browserkonfiguration komplett zerschießen, wenn man an den falschen Schrauben dreht.

Besondere Zeiten erfordern besondere Videokonferenzen: Wie führt man eine Online-Feierstunde durch?

Benjamin D. Ferencz ist der letzte noch lebende Ankläger der Nürnberger Prozesse. Für seine Verdienste wurde er vor kurzem mit der Ehrendoktorwürde ausgezeichnet. Wie die Online-Feierstunde aus technischer Sicht verlief, beschreiben wir hier als Erfahrungsbericht – auch als Beispiel für zukünftige, ähnliche Nutzungsszenarien.

Screenshot der Feierstundenaufzeichnung

Was hat das mit IT – beziehungsweise mit dem RRZK – zu tun? Wir wurden gebeten, diese mit rund 400 Teilnehmenden etwas größere Veranstaltung mit technischer Unterstützung zu begleiten und Fragen rund um die Durchführung im Vorfeld der Feierstunde zu klären.

Vorbereitungen

Geplant war die Veranstaltung als Videokonferenz beziehungsweise als Webinar über das Zoom-Portal der Uni Köln. Ein Zoom-Webinar hat den Vorteil, dass die Sprecher*innen auf dem virtuellen Podium als „Panelists“ für alle sichtbar sind. Die (passiv) Teilnehmenden der Feierstunde bleiben unsichtbar, können sich aber jederzeit mit Wortbeiträgen – wie beispielsweise Gratulationen – äußern.

Administration durch mehrere Hosts

In den Einstellungen wurden drei Hosts benannt. Dies hat den Vorteil, dass die Videokonferenz bei möglichen Verbindungsproblemen eines der drei Hosts zum einen aufrecht erhalten werden kann. Zum anderen hätten jederzeit bestimmte administrative Aufgaben (wie das Hineinlassen weiterer Teilnehmender aus dem Warteraum) von den jeweils anderen durch- oder weitergeführt werden können.

Aufzeichnung

Die Feierstunde sollte mit Bild und Ton aufgezeichnet werden. Um diese Aufzeichnung unabhängig von der Verbindungsqualität des jeweiligen Hosts zu erstellen, nutzten wir die Cloud-Aufnahmefunktion von Zoom, die mehrere Videos und Audiospuren als mp4- und mp3-Dateien nach dem Ende des Webinars bereitstellte. Warum mehrere Spuren und Dateien? Auf diese Weise gab es eine „Videogesamtspur“, die alle Panelisten in der Galerieansicht von Zoom zeigte. Zusätzlich wurden die Einzelansichten der Redner*innen separat aufgezeichnet. Am Ende ermöglichte uns das einen dynamischen Zusammenschnitt der Aufnahmen mit einem Wechsel zwischen Einzel- und Gesamtansicht. Wie man dies einstellen kann, beschreibt Zoom in seinem Help-Center.

Absprache zum Wechseln zwischen den Reden

Hätte man die Feierstunde in Präsenz abgehalten (vermutlich im größeren Rahmen der Aula der Universität) wären die Redner nacheinander aufs Podium vor das Mikrofon getreten. Im Virtuellen ist dies durch Zoom ebenfalls möglich, wenn man die Einzelansicht wählt. Zoom erkennt automatisch (leider mit ein paar Sekunden Verzögerung), wer gerade spricht und schaltet dann in der Einzelansicht auf die sprechende Person um. Deshalb sollten die jeweiligen Redenden zunächst einige Sekunden warten, um einen guten Übergang zu gewährleisten.

„Generalprobe“

Durch einen Probedurchlauf wurden die Panelisten vorab instruiert. Dies bezog sich auf den Ablauf der Feierstunde sowie auf die Reihenfolge der Ansprachen. So klärte man die technischen Details zur Einwahl in die Konferenzoberfläche, die Informationen zur Aufzeichnung und weitere Fragen sinnvollerweise im Vorhinein – gute Voraussetzungen für einen reibungslosen Ablauf.

Die Feierstunde

Wie zeigt man ein virtuelles Bühnenbild?

Alternatives Bühnenbild, Text als Überleitung zu Rektor A. Freimuth
Als Alternative zum Bühnenbild hier die Überleitungsgrafik zur Rede von Rektor A. Freimuth

Neben den Redner*innen zeigte man eine per Bildschirm geteilte Präsentation; sie diente sozusagen als Bühnenbild-Ersatz. Eine Folie visualisierte zu Beginn den Titel beziehungsweise den Anlass der Feierstunde sowie die (die Feierstunde ausrichtende) Rechtswissenschaftliche Fakultät mitsamt Fakultätslogo/-siegel. Zwischen den einzelnen Redebeiträgen leitete eine Folie mit Namen und Titel zu den angekündigten Personen über. So konnte die Moderation – in diesem Fall moderierte Prof. Dr. Claus Kreß – von visuellen Überleitungen unterstützt werden (die Reden selbst fanden ohne geteiltes Hintergrundbild statt). Danach blendete man zum Abschluss der Feierstunde einige Fotos aus dem Leben des Gewürdigten ein.

Voraufgezeichnetes Video vorführen

Höhepunkt der Feierstunde war ein Video des Geehrten, das wenige Tage vor der Veranstaltung aufgezeichnet wurde. Dieses blendeten wir mit Bild und Ton über die Bildschirm-Teilen-Funktion ein. Dabei muss man unbedingt darauf achten, die Audioausgabe des eigenen Rechners mit zu übertragen und am besten die Ausgabe für Videoclip zu optimieren.

Hosts / Technik ausgeblendet

Panelisten der Feierstunde
Nur die Redner*innen sollten während der Feierstunde sichtbar sein.

Sichtbar waren während der gesamten Feierstunde nur die Panelisten selbst. Die technisch Verantwortlichen, also die Hosts, hatten Mikrofon und Kamera deaktiviert. Über die Funktion „Teilnehmer ohne Videoübertragung ausblenden“ war sichergestellt, dass es nicht die üblichen „schwarzen Kacheln“ im Webinar zu sehen gab. Nur die Namen der Hosts waren in der Liste der Panelisten sichtbar. Diese angezeigten Namen konnten jedoch so angepasst werden, dass nur noch der jeweilige Einrichtungsname zu sehen war (zum Beispiel „RRZK“). Dies lässt sich entweder direkt im laufenden Meeting ändern oder gleich dauerhaft im eigenen Zoom-Profil einstellen.

Die Videoaufzeichnung

Um die Eindrücke der Feierstunde auch nachträglich verfügbar zu machen, haben wir ein Video aus der Aufzeichnung zusammengeschnitten.

Wie oben benannt, aktivierten wir im Vorhinein die Cloud-Aufzeichnungsfunktion von Zoom. Diese lässt die Hosts (beziehungsweise zunächst nur die Person, die das Webinar erstellt hat!) die Inhalte als mp4-Video- und mp3-Tondateien herunterladen. Zwar erhält man auch eine von Zoom bereitgestellte Webseite mit der bereits eingebetteten Aufzeichnung, die so problemlos auch der Öffentlichkeit hätte zugänglich gemacht machen können. Diese Seite wird jedoch nach 30 Tagen gelöscht. Somit wäre das Video dort nicht dauerhaft erhalten geblieben.

Darüberhinaus wollten wir das von Zoom bereitgestellte Video am Schluss nicht „einfach so“ veröffentlichen und haben dazu mit der Videoschnittsoftware Adobe Premiere Pro noch ein wenig nachbearbeitet. Warum? Zum einen wollten wir das Video etwas „schöner“ machen und hier und da die „leere“ Zeit zwischen den Sprecherwechseln etwas verkürzen. Durch Überblendungen wirkten die Übergänge nicht so hart und direkt. Sinnvollerweise haben wir die beiden Videospuren mit Einzel- und Galerieansicht zu allererst übereinandergelegt und durch entsprechende Schnitte eine passgenaue Überblendung erreichen können. Deshalb wirkt dies so, als wären wie bei einer Präsenzveranstaltung verschiedene Kameras eingesetzt worden.

Hätte es bei einem der Panelisten zwischendurch Audiostörungen (oder Nebengeräusche durch fälschlicherweise aktivierte Mikrofone) gegeben, könnte man durch eine separate mp3-Spur, die nur die jeweils Sprechenden aufgezeichnet hat, als Überbrückung mit hineinsynchronisieren. In diesem Fall war das aber nicht nötig (als Backup ist es aber sinnvoll).

Die während der Veranstaltung eingeblendeten Folien haben wir nachträglich als Grafikdateien eingebunden, so dass jeweils die unkomprimierten Grafiken zu sehen waren – anstatt die bei der Übertragung kleingerechneten, mit Artefakten versehenen Varianten.

So kam ein schöner, leicht dynamischer Bild-Mix zwischen Einzel- und Galerieansicht sowie den präsentierten Fotos zustande. Wer sich das Ergebnis anschauen möchte: Das fertige Video ist hier veröffentlicht. Bereitgestellt wird dies über die Opencast-Plattform der Uni Köln. Über das entsprechende Video-Modul im Typo3-Content-Management-System bindet man den Videoplayer direkt in die Webseite ein.

Fazit

Aus technischer Sicht darf man dieses Webinar als gelungen betrachten, denn: Alles funktionierte reibungslos, die Redebeiträge verliefen technisch einwandfrei, und darüberhinaus gab es keinerlei Störungen während der Übertragung. Nota bene: Nach nun fast einem Jahr Pandemie und ihrer Auswirkungen auf die Forschung und die Arbeitswelt zeigte sich erfreulicherweise, dass die Beteiligten mit der Durchführung von Videokonferenzen gut zurechtkamen und mit den Funktionen (in diesem Fall von Zoom) bestens vertraut waren. Dies wurde aber zusätzlich dadurch sichergestellt, dass das Vorbereitungsteam des Lehrstuhls für Völkerrecht  im Vorhinein gut geplant hatte, und dass alle Panelisten bei einer Testvideokonferenz ausführlich vom Vorbereitungsteam instruiert worden sind.

Inhaltlich lässt sich das Resümee ziehen, dass die Verantwortlichen sehr viel dafür getan haben, die Feierlichkeit einer solchen Zeremonie möglichst angemessen ins Digitale zu übertragen – auch dies ist dem Organisationsteam und den Durchführenden gut gelungen! Davon zeugen die vielen positiven, per Chat am Schluss der Veranstaltung eingegangenen Rückmeldungen der Teilnehmenden. Und für die verantwortliche RRZK-Mitarbeiterin war es abseits aller technischer Unterstützung ein eindrückliches und besonderes Erlebnis, dabei gewesen sein zu dürfen.

 

Visual Regression Testing mit Puppeteer und Resemble.js (Teil 2)

In meinem letzten Artikel habe ich mit einem Beispiel beschrieben, wie man mittels Puppeteer automatisert Screenshots von Websites erstellt. Das Problem stellte sich für uns, weil wir im großen Umfang CMS-Unterseiten auf Frontend-Probleme nach einem Upgrade testen wollten.

Ziel war es, ein Skript zu erstellen, welches vor einem Upgrade gestartet werden kann und zunächst den Status Quo von Websites in Screenshots festhält.
Nachdem die Upgrades an den Websites durchgeführt wurden, kann das Skript erneut gestartet werden und es werden automatisch visuelle Vergleichtests durchgeführt.

Test-Logik

Zum Ablauf der Visual Regression Tests habe ich folgende kleine Test-Logik entwickelt:

Flowchart

Wenn ich keinen Screenshot finde, erstelle ich einen für einen späteren Vergleich. Finde ich einen vor, dann erstelle ich einen neuen und vergleiche ihn direkt.

Visual Regression Testing mit Puppeteer und Resemble.js

Um den obigen Test-Algorithmus abzubilden, muss die app.js aus meinem letzten Artikel um eine Testschleife, die zusätzliche Library Resemble.js und das File System-Modul von Node.js erweitert werden.

Die folgende Vorgehenswiese lässt sich auch anhand meiner Commits im Github-Repository nachverfolgen.

Dateizugriff einrichten

Für den Zugriff auf das Dateisystem stellt Node.js das fs-Modul bereit. Damit lassen sich klassische Dateioperationen durchführen (copy, move etc.).

Um das Modul zu verwenden, muss es mittels require in der app.js eingebunden werden:

const fs = require('fs')

Bisher war der Pfad- und Dateiname der Screenshots, die in der takeScreenshot()-Funktion erstellt werden noch hard coded. Weil die Funktion zukünftig sowohl Vorher- als auch Nachher-Screenshots festhalten soll, werden folgende Änderungen vorgenommen:

const screenshotsFolder = './screenshots/'

und

await page.screenshot({ path: filename, fullPage: true })

Test-Logik aufbauen

Jetzt kann die eigentliche Test-Logik aufgebaut werden. Ziel ist es, die Screenshots noch nicht zu vergleichen, aber schon die nötige Schleife zusammenzubasteln. Ich habe dafür eine Funktion erstellt, welche den Test startet. Hierfür eignet sich in diesem Fall die Verwendung der Immediately-invoked Function Expression.

Die Immediately-invoked Function Expression ist eine Möglichkeit, Funktionen sofort auszuführen, sobald sie erstellt werden:

(() => {
  /* Befehle */
})()

Unsere asynchrone Funktion sieht dann so aus:

// Immediately-invoked arrow function after launch
(async () => { 
    // Create screenshots folder if it does not exist
    if (!fs.existsSync(screenshotsFolder)) {
        fs.mkdir(screenshotsFolder, (err) => {
            if (err) throw err
        })
    }

    for (const website of websites) {
        const orgScreenshotPath = screenshotsFolder + website.filename + '.png'
        const testScreenshotPath = screenshotsFolder + website.filename + '_test.png'
        // Check if both original and testing screenshot already exist
        if (fs.existsSync(orgScreenshotPath) && fs.existsSync(testScreenshotPath)) {
            // Both exist run regressionTest()
        } else {
            if (fs.existsSync(orgScreenshotPath)) {
                // Original exists create test screenshot
                await takeScreenshot(website.url, testScreenshotPath)
                    .then(console.log('Created test: ' + website.filename))
                // run regressionTest()
            } else {
                // No Original exists, let's create a new one
                await takeScreenshot(website.url, orgScreenshotPath)
                    .then(console.log('Created original: ' + website.filename))
            }
        }
    }
})()

Mit fs.existsSync() wird geprüft, ob eine Datei unter dem angegeben Pfad existiert. Dies könnte auch mittels Promises/await asynchron und ohne Callbacks gemacht werden (Momentan noch experimental).

Vergleichen von Screenshots mit Resemble.js

Jetzt fehlt nur noch die regressionTest()-Funktion, damit wir unsere Tests durchführen können.

Hierfür muss zunächst Resemble.js mittels npm installiert und eingebunden werden:

$ npm install resemblejs --save

In unserer app.js:

const resemble = require('resemblejs')

Die asynchrone regressionTest()-Funktion sieht wie folgt aus:

const regressionTest = async (filename, orgScreenshotPath, testScreenshotPath) => {
    console.log('Visual Regression: ' +  filename)

    const diffFolder = screenshotsFolder + 'diff/'

    resemble(orgScreenshotPath).compareTo(testScreenshotPath).onComplete(data => {
        if (data.misMatchPercentage > 0) {
            console.log('Missmatch of ' + data.misMatchPercentage + '%')

            // Create screenshots/diff folder only when needed
            if (!fs.existsSync(diffFolder)) {
                fs.mkdir(diffFolder, (err) => {
                    if (err) throw err
                })
            }

            // Set filename and folder for Diff file
            const diffScreenshotPath = diffFolder + filename + '_' + data.misMatchPercentage + '_diff.png'
            fs.writeFile(diffScreenshotPath, data.getBuffer(), (err) => {
                if (err) throw err
            })
        }
    })
}

Die Funktion erhält die Parameter filename aus dem websites-Array, sowie den zusammengesetzten Pfad zum Original. Dazu kommt ein Vergleichsscreenshot (orgScreenshotPath, testScreenshotPath).

Diese werden nun durch resemble verglichen:

resemble(orgScreenshotPath).compareTo(testScreenshotPath)

Wenn ein Unterschied zwischen orgScreenshotPath und testScreenshotPath besteht wird eine Differenzgrafik erstellt. Diese zeigt standardmäßig die Unterschiede in Magenta an. Damit Fehler schneller gefunden werden können, werden diese Differenzbilder im Unterverzeichnisscreenshots/diff abgelegt.

In folgenden Screenshots fehlen Seiteninhalte. Resemble.js findet den Unterschied und stellt ihn gut sichtbar dar:

Resemble.js Animation

Schneller Vergleichen von einzelnen Screenshots

Wenn eine einzelne URL verglichen werden soll, ist es etwas mühselig diese immer in das websites-Array in app.js einzufügen. Deshalb habe ich in dem Skript die Möglichkeit ergänzt, beim Aufruf URL(s) als Kommandozeilenargumente anzuhängen:

$ node app.js https://rrzk.uni-koeln.de/

let websites = []

process.argv = process.argv.slice(2) // Slice away the first two command line arguments

if (process.argv.length == 0) { 
    // If no command line arguments are given add hardcoded examples
    websites = [
        { url: 'https://rrzk.uni-koeln.de/', filename: 'homepage' },
        { url: 'https://rrzk.uni-koeln.de/aktuelles.html', filename: 'news' },
        { url: 'https://typo3.uni-koeln.de/typo3-angebote.html', filename: 'typo3-offerings' },
        { url: 'https://typo3.uni-koeln.de/typo3-links-und-downloads.html', filename: 'typo3-links-and-downloads' }
    ]
} else {
    process.argv.forEach((val, index) => {
        try { // Check if argument is a URL
            let screenshotURL = new URL(val)
            // Add URL to websites array if valid and create filename
            websites.push({ url: screenshotURL.href, filename: index + '_' + screenshotURL.host})
        } catch (err) {
            console.error('"' + val + '" Is not a valid URL!')
        }
    })
}

Mittels der Klasse URL, wird die Zeichenkette in ein URL-Objekt konvertiert. Wenn dies fehlschlägt, enthält die Zeichenkette keine gültige URL.

Das finale app.js-Skript:

Das finale app.js Skript ist nun fertig app.js Download

Zum Starten einfach app.js ausführen: $ node app.js.

Wenn Screenshots von einzelnen Websites verglichen werden sollen, kann dies folgendermaßen gemacht werden:

$ node app.js https://rrzk.uni-koeln.de/
Created test: 0_rrzk.uni-koeln.de
Visual Regression: 0_rrzk.uni-koeln.de
Missmatch of 58.22%

Ausführen mittels Docker

Dieses Skript kann auch in einer containerbasierten Umgebung ausgeführt werden. Als Basis-Image verwende ich zenato/puppeteer. Das Image enthält einen standardisierten „Chrome“-Browser und stellt eine Umgebung bereit, in der Screenshots in konsistenter Weise erstellt werden.

Mein Dockerfile dafür sieht so aus:

FROM zenato/puppeteer:latest
USER root
COPY package.json /app/
COPY app.js /app/
RUN cd /app && npm install --quiet
WORKDIR /app
ENTRYPOINT [ "node" , "app.js" ]

Image erstellen:

$ docker build -t movd/puppeteer-resemble-testing:latest .

Container ausführen:

$ docker run --rm -v "${PWD}/screenshots:/app/screenshots" movd/puppeteer-resemble-testing:latest http://example.com

Das Image kann auch direkt vorgebaut von „Docker Hub“ geladen werden:

$ docker pull movd/puppeteer-resemble-testing:latest

Die hier erstellte Lösung basiert auf den Anforderungen im RRZK. Ich freue mich über Feedback und weitere Use-Cases, weil die Test-Logik eine einfache Schleife ist, ließe sich diese auch für andere Testreihenfolgen anpassen. Resemble.js ließe sich auch besonders gut in automatisierte Test mit Mocha oder Jest verwenden.

Visuelle Tests von Websites nach Updates und Änderungen

An der Uni Köln wird seit mehreren Jahren auf das Content-Managment-System (CMS) TYPO3 gesetzt. Immer mehr Institute und universitäre Einrichtungen greifen dafür auf die TYPO3-Angebote des RRZK zurück, sodass aktuell über 50.000 Seiten, auf über 960 Domains bereitgestellt werden. CMS und Webapplikationen erfordern regelmäßige Wartung und Bugfixes. Jedoch birgt jede Änderung oder Korrektur die Gefahr, dass Nebenwirkungen auftreten und Fehler vielleicht an einer unerwarteten Stelle im System verursacht werden. Regressionstests haben die Aufgabe dies vorzubeugen und Fehler zu finden. Das Ziel lautet: Das, was vorher funktioniert hat, soll auch nach einem Upgrade funktionieren.

Als im vergangenen Sommer die Upgrades unserer Systeme auf die Long Term Support Version v8 des CMS anstanden, haben wir deshalb nach einer Lösung gesucht. Ziel war es ein Programm zu finden, mit der die Front-Ends der Websites auf mögliche “Macken” nach den Upgrades getestet werden können.

Im Web-Bereich wurden in den letzten Jahren einige Libraries und Tools für visuelle Regressionstest entwickelt. Ein visueller Regressionstest führt Front-End- oder User-Interfacetests durch, indem es die Screenshots des User-Interface erfasst und mit den Originalbildern vergleicht. Wenn ein neuer Screenshot vom Referenzscreenshot abweicht, warnt das visuelle Regressionstool.

Visual Regression Testing mit Puppeteer und Resemble.js

“Puppeteer Logo” erstellt von Google, geteilt gemäß der CC BY 3.0-Lizenz

Seit 2017 stellt das EntwicklerInnen-Team des Chrome-Browsers mit Puppeteer eine Open-Source Node.js Library bereit, mit welcher ein Chrome Browser ohne eine grafische Oberfläche über eine API angesteuert und automatisiert werden kann. Mittels Puppeteer lassen sich z.B. Screenshots von Websites erstellen aber auch Interaktionen mit dem Front-End einer Website simulieren.

Die mit Puppeteer erstellten Screenshots, gilt es zu vergleichen. Hierfür bietet sich die gut gepflegte Library Resemble.js an. Diese ist darauf spezialisiert Bilddateien abzugleichen und Unterschiede auszugeben.

Teil 1: Screenshots erzeugen

Mit folgenden Tutorial will ich zeigen wie man mit Puppeteer Screenshots mehrerer Seiten erstellt. Ziel ist es am Ende einen Ordner mit Screenshots zu haben, welche anschließend als Ausgangsbilder für Tests dienen werden.

In einem weiteren Artikel werde ich darauf eingehen, wie diese Screenshots mit einem späteren Zustand verglichen werden können.

Der Code zu dieser Anleitung ist auch auf GitHub zu finden. Link zum Stand dieses Artikels

Node.js und Puppeteer installieren

Vorraussetzung: Zum Ausführen wird die JavaScript Runtime node samt der mitgelieferten Packetverwaltung npm benötigt.

Installationsanleitung für verschiedene Betriebssysteme gibt es auf nodejs.org. Für die Verwendung in Linux-Distributionen bietet NodeSource Repositories mit kompilierten Binaries an.

Nachdem nun Node.js installiert ist, muss noch ein Ordner erstellt und in das Verzeichnis gewechselt werden:

mkdir puppeteer-resemble-testing
cd puppeteer-resemble-testing

Als nächstes muss ein neues Projekt erstellt werden:

npm init

Für den Zweck dieser Anleitung, kann jede Frage mittels der Return-Taste bestätigt werden. Dabei wird eine neue package.json erstellt.

Nun muss Puppeteer installiert werden:

npm install puppeteer --save

Die Installation kann eine kurze Weile dauern. Denn es wird auch automatisch eine Version von Chromium heruntergeladen und innerhalb des Projekts abgespeichert.

Einzelnen Screenshot erstellen

Puppeteer steht jetzt bereit und kann verwendet werden. Unser erstes Skript erzeugt einen Screenshot der kompletten RRZK-Startseite. Das Ergebnis wird als screenshot.png abgelegt.

Inhalt von app.js:

const puppeteer = require('puppeteer')

const takeScreenshot = async () => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()

  await page.setViewport({ width: 1920, height: 1080 })
  await page.goto('https://rrzk.uni-koeln.de/')
  await page.screenshot({ path: './screenshot.png', fullPage: true })
  await page.close()
  await browser.close()
}

takeScreenshot()

Puppeteer hat eine umfassende API-Dokumentation, alle obigen Parameter sind dort ausführlich beschrieben.

Puppeteer ist eine Promise-basierte Bibliothek, in diesem Fall bedeutet dies, dass die Aufrufe an die Chrome-Instanz asynchron durchgeführt werden. Damit der Code des Skript einfach zu lesen ist, wird async/await verwendet. Unsere takeScreenshot() Pfeilfunktion muss deshalb als async definiert werden.

Das Skript wird ausgeführt mit dem Befehl:

node app.js

Im folgenden werden wir auf dieses Skript aufbauen und nach und nach mehr Features hinzufügen.

Mehrere Screenshots in Stapelverarbeitung

Ziel ist es, weiterhin Screenshots vieler Seiten zu erstellen. Um etwas Ordnung zu waren, erstellen wir deshalb zunächst das Unterverzeichnis “screenshots”:

mkdir screenshots

Danach legen wir in app.js ein Array aus Objekten an. In einem Objekt wird jeweils die URL und der Screenshot-Dateiname hinterlegt.

const websites = [
  { url: 'https://rrzk.uni-koeln.de/', filename: 'homepage' },
  { url: 'https://rrzk.uni-koeln.de/aktuelles.html', filename: 'news' },
  { url: 'https://typo3.uni-koeln.de/typo3-angebote.html', filename: 'typo3-offerings'},
  { url: 'https://typo3.uni-koeln.de/typo3-links-und-downloads.html', filename: 'typo3-links-and-downloads'}
]

Zum Test kann dieses Array nun durchlaufen werden:

for (const website of websites) {
  console.log(website.url)
  console.log(website.filename)
}

Beim erneuten Ausführen des Skripts werden nun die Inhalte des websites-Arrays ausgegeben.

Bisher ist in unserer takeScreenshot() Funktion die URL und der Dateiname hartkodiert. Die Funktion muss jetzt mit url und filename gefüttert werden. Daraus ergeben sich folgende Änderungen:

const takeScreenshot = async (url, filename) => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()

  await page.setViewport({ width: 1920, height: 1080 })
  await page.goto(url)
  await page.screenshot({ path: './screenshots/' + filename + '.png', fullPage: true })
    .then(console.log('Screenshot: ' + filename))
  await page.close()
  await browser.close()
}

Fast geschafft, nun noch beim durchlaufen des Arrays die takeScreenshot()-Funktion aufrufen und die Werte übergeben:

for (const website of websites) {
  // console.log(website.url)
  // console.log(website.filename)
  takeScreenshot(website.url, website.filename)
}

Unsere finale kompakte app.js sieht dann wie folgt aus:

const puppeteer = require('puppeteer')

const websites = [
  { url: 'https://rrzk.uni-koeln.de/', filename: 'homepage' },
  { url: 'https://rrzk.uni-koeln.de/aktuelles.html', filename: 'news' },
  { url: 'https://typo3.uni-koeln.de/typo3-angebote.html', filename: 'typo3-offerings'},
  { url: 'https://typo3.uni-koeln.de/typo3-links-und-downloads.html', filename: 'typo3-links-and-downlods'}
]

const takeScreenshot = async (url, filename) => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()

  await page.setViewport({ width: 1920, height: 1080 })
  await page.goto(url)
  await page.screenshot({ path: './screenshots/' + filename + '.png', fullPage: true })
    .then(console.log('Screenshot: ' + filename))
  await page.close()
  await browser.close()
}

for (const website of websites) {
  // console.log(website.url)
  // console.log(website.filename)
  takeScreenshot(website.url, website.filename)
}

Nach dem Ausführen liegen nun unter „/screenshots“ vier PNG-Dateien.

Durch den .then Handler wird nach einlösen des Promise screenshot kurz Rückmeldung gegeben. Hiermit zeigt sich auch schön die asynchrone Arbeitsweise von Puppeteer.

In meinem nächsten Artikel werde ich das Skript um einen Vorher-Nachher-Vergleich mit Resemble.js erweitern, sowie das ganze mittels Docker so abpacken, dass man es einfach auf einem Linux-Server ausführen kann.

UniNow – Bequem durch’s Studium?

UniNow liefert genau das, was viele Studierende sich schon lange wünschen: Eine App fürs Studium, die alles kann, unter einer Oberfläche. Sich nicht mehr an gefühlt tausend unterschiedlichen Systemen anmelden zu müssen, die zudem für eine mobile Ansicht häufig nicht geeignet sind. Toll.

Der Haken an der Sache? Die App stammt von keiner Uni, sondern von einem Drittanbieter. Diesem Anbieter müsst Ihr die Zugangsdaten zu Eurem Studierendenaccount anvertrauen, an dem mittlerweile eine ganze Reihe von Diensten hängen: Mail, Klips, Ilias, Wlan, VPN, Eduroam, SOFS, Softwareshop, lizenzierte Zugänge u.s.w. Dienste also, die sehr persönliche Daten beinhalten bzw. Dienste mit hohem Missbrauchspotenzial. Mit Euren Zugangsdaten wird sich UniNow dann mittels seiner Server bei den unterschiedlichen Diensten der Uni anmelden und Eure Daten abfischen. Dass die Weitergabe der Accountdaten gegen jegliche Benutzungsordnungen verstoßen, eine Exmatrikulation bzw. fristlose Kündigung zur Folge haben kann, soll hier jetzt gar nicht das Thema sein. Vielmehr soll es um den Schutz Eurer Daten gehen und Euren eigenverantwortlichen Umgang mit diesen.

Die Uni Köln betreibt ziemlich viel Aufwand, um Eure Daten vor unberechtigten Zugriffen zu schützen. Es ist zudem penibel reglementiert, was gespeichert werden darf und wer zu welchem Zweck Einsicht in Eure Daten erhält. Sobald an der Uni irgendetwas mit personenbezogenen Daten passieren soll, müssen Datenschutzbeauftragter und ggf. Personalrat in langen Verfahren diesem zustimmen. Ein Beispiel dazu aus dem Tagesgeschäft des Helpdesk: Diesen erreichen häufig Anfragen, Euch Euer Passwort des Studierendenaccounts zuzumailen, da Ihr dieses vergessen habt. Das wird aus vielerlei Gründen nicht passieren: Der Helpdesk hat keine Einsicht auf diese Daten. Selbst wenn, wäre das nutzlos, da das Passwort nur verschlüsselt vorliegt. Und zu guter Letzt würde der Helpdesk solch sensiblen Daten nie über eine ungesicherte Mailverbindung hinauspusten.

All solche Bemühungen um Datenschutz würden natürlich ad absurdum geführt, wenn Ihr freiwillig Eure Daten aus der Hand gebt. Als Ausweg aus diesem Dilemma bliebe letztendlich nur der Rückgriff auf eine „vertrauenswürdige“ App bzw. einer App, die wenigstens den gleichen Datenschutzbestimmungen unterliegt, wie alle anderen Dienste der Uni auch. Eine solche App gibt es aber noch nicht. Die Gründe hierfür sind vielfältig. Positiv ist zu erwähnen, dass die Uni Köln – über das RRZK sowie das Prorektorat für Lehre und Studium – zur Zeit gemeinsam mit anderen Hochschulen am Projekt „StApps“ arbeitet, welches die Erstellung eigener Uni-Apps zum Ziel hat. Mehrere Mitarbeiter wollen dafür sorgen, dass wir Euch diese App möglichst bald bereitstellen können.

Verschlüsselung dank Let’s Encrypt

Dank der Initiative „Let’s Encrypt“ kann nun jede(r) Betreiber(in) von Webseiten diese kostenfrei auch per https bereitstellen, also den Transportweg mit SSL verschlüsseln. Dies war zwar bislang auch mit anderen Anbietern möglich, aber die damit erstellten Zertifikate waren nicht in den gängigen Browsern vertreten, sodass beim ersten Besuch der Seite stets eine Warnmeldung erschien. Bei „Let’s Encrypt“ ist dies nicht mehr so.

Dementsprechend habe ich auch die Domains auf meinem eigenen privaten Server nun per https verfügbar gemacht. Eigentlich wollte ich an dieser Stelle eine kleine Anleitung verfassen, da ich mir meinen Erfolgsweg bei diversen Blog- und Foreneinträgen zusammengesucht hatte. Inzwischen habe ich aber einen Beitrag entdeckt, der exakt meine Vorgehensweise beschreibt, incl. mehrerer Domains in einem Server und Auto-Renew per Cronjob. Daher verweise ich unten auf diesen Artikel von Dominic Pratt und ergänze lediglich, dass man inzwischen das Auto-Renew auch einfacher machen kann, nämlich per Crontab-Eintrag á la:

30 2 * * 1 /opt/letsencrypt/letsencrypt-auto renew >> /var/log/le-renew.log

Zudem sollte man unbedingt darauf achten, ausschließlich sichere Protokolle und Cipher Suites zu aktivieren. Leider unterstützen nicht alle Server und Clients automatisch die neuesten und besten Einstellungen. Ein guter Kompromiss ist derzeit im Apache z.B.:

SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite HIGH:MEDIUM:!ADH:!MD5:!RC4

Damit erreicht man im SSL-Test (https://www.ssllabs.com/ssltest) immerhin Grade A. Besser ginge es noch bspw. mit der Aktivierung von Forward Secrecy.

Hier nun der angesprochene Artikel:

Let’s Encrypt nutzen – eine Anleitung

Web-Browser und -Server… was reden die da eigentlich??? Server-Sockets mit nc

Wer sich mit Webservern und -browsern beschäftigt, wird irgendwann an den Punkt kommen, wo man einfach mal wissen will, „Was zur Hölle der Browser und der Server da genau bereden“

Tools wie wget helfen einem zwar, zu überprüfen, ob ein Server eine Datei wirklich ausliefert, aber viele Funktionen werden im HTTP-Header ausgehandelt und die Server reagieren dabei speziell auf die unterschiedlichen, browserspezifischen Anfragen.

Wenn es also so aussieht, als würde der Server einem Firefox andere Daten schicken, als einem Chrome, möchte man sicherlich wissen, ob es wirklich so ist und wie sich die Kommunikation generell unterscheidet.

Hier kann ein Trick helfen, über den ich kürzlich gestolpert bin. Er beruht auf dem Befehl nc (netcat), der in vielen Konstellationen hilfreich sein kann.

nc (netcat)

nc öffnet entweder eine Verbindung zu einem Server-Port (z.b. dem HTTP-Port (80) eines Webservers) und verhält sich dabei sehr ähnlich zu telnet.
Im Gegensatz zu telnet kann nc jedoch auch selbst einen Socket öffnen und auf eingehende Anfragen antworten. Hierfür wird der Switch -l verwendet.

Egal, in welcher Richtung die Kommunikation aufgebaut wird, verbindet nc immer die Standard-Eingabe (stdin) mit dem Kommunikationspartner.
Wird der Befehl also einfach so verwendet, können Sie direkt mit der Tastatur eingeben, was dem Kommunikationspartner gesendet werden soll.
Startet man auf einem Rechner ein lauschenden Server-Socket auf Port 54321:

# nc -l 54321

… kann man sich von einem anderen Rechner aus damit verbinden:

# nc hostname.des.servers 54321

Nun hat man eine Verbindung, die man zum Chatten verwenden kann.

Auf dem üblichen Weg lassen sich per Pipe auch die Ausgaben anderer Befehle über diese Leitung zu übertragen, statt die Tastatur Eingabe zu verbinden.
Startet man den Server z.B. so:

# ls -l | nc -l 54321

… bekommt man beim Verbinden mit dem Socket das aktuelle Verzeichnis, in dem der Server gestartet wurde angezeigt. Danach schließt sich die Verbindung und sowohl Server- als auch Client-Prozesse werden gestoppt.

Sehen was der Browser sendet:

So ist nc also schon nützlich: Man kann einen Server-Socket öffnen und im Webbrowser dessen Adresse eingeben. Im obigen Beispiel also http://localhost:54321/. Zwar wird im Browser so nicht unbedingt etwas sinnvolles angezeigt, weil unser nc-Server kein HTTP spricht, aber auf der Konsole können wir nun sehen, welche Anfrage genau der Browser an unseren Server geschickt hat:

GET / HTTP/1.1
Host: localhost:54321
Connecdern: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36 Vivaldi/1.0.403.20
Accept-Encoding: gzip, deflate, sdch
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: _pk_id.2478.1fff=bda69bf5b5894886.1457526065.1.1457526065.1457526065.

Dies ist nun aber nur eine einzelne Anfrage und wir können nicht die Antwort des Servers sehen, der uns eigentlich interessiert.

Umleiten einer Verbindung

Hier kommt nun eine weitere praktische Zutat ins Spiel: Named Pipes. Während wir mit dem Pipe-Symbol (Senkrechter Strich: |) nur die Ausgabe eines Programms mit der Eingabe des direkt folgenden Programms verbinden können, werden Named Pipes im Filesystem abgelegt und können auf diese Weise angesprochen. Diese Pipes werden mit dem Befehl mkfifo angelegt, sie verhalten sich dabei weitgehend wie Dateien.

Named Pipes können wir nun dazu verwenden, zwei nc-Prozesse miteinander zu verbinden: Einen, der auf Verbindungen vom Browser wartet, einen der eine Verbindung zu einem Webserver herstellt:

Anlegen der Named Pipe (der Name und Pfad können frei gewählt werden):

# mkfifo /tmp/proxyfifo

Zwei nc-Prozesse starten und verbinden

# nc -l -p 54321 </tmp/proxyfifo | nc server.domain.de 80 >/tmp/proxyfifo

Löschen der Pipe:

#rm /tmp/proxyfifo

Statt http://server.domain.de geben wir nun im Browser ein: http://localhost:54321.

Der Browser zeigt uns nun die Webseite des Servers an. Da unsere nc-Prozesse aber nur jeweils eine Verbindung aufbauen und sich danach beenden, werden wahrscheinlich Bilder und CSS-Dateien nicht vollständig geladen. Beherrschen Browser und Webserver beide „Keep-Alive“ werden jedoch durchaus mehrere Ressourcen übertragen bevor die Verbindung beendet wird – nur halt nicht alle.

Dies ist bis jetzt noch wenig sinnvoll, aber da die Verbindung nun durch unsere Hände geleitet wird, können wir uns einklinken, und mitlesen, was die beiden Gesprächspartner miteinander austauschen.

Belauschen der Verbindung:

# mkfifo /tmp/proxyfifo
# nc -l -p 8080 </tmp/proxyfifo | tee /dev/stderr | nc server.domain.de 8480 | tee /dev/stderr >/tmp/proxyfifo
# rm /tmp/proxyfifo

Der Einfachheit halber werden hier beide Kommunikationsrichtungen per tee zusätzlich auf der Standard-Fehlerausgabe (stderr) ausgegeben, was zum Mitlesen ausreicht.

In manchen Fällen möchte man darüber hinaus in die Kommunikation Eingreifen und die übertragenen Daten „on-the-fly“ manipulieren, auch dies ist mit diesem Ansatz möglich.

Da der Browser im obigen Beispiel glaubt mit „localhost“ zu kommunizieren, überträgt er in seinem HTTP-Request einen falschen Host, dies könnte man beispielsweise mit sed korrigieren wollen:

# mkfifo /tmp/proxyfifo
# nc -l -p 8080 </tmp/proxyfifo | sed -u "s/Host: localhost:8080/Host: rrzk.uni-koeln.de/g" | tee /dev/stderr | nc rrzk.uni-koeln.de 80
# rm /tmp/proxyfifo

Mit diesem Beispiel kann man die Webseite des RRZK über den Aufruf http://localhost:8080 laden und sich anschauen welche Daten ausgetauscht werden. (Wie erwähnt wird die Seite so nicht vollständig geladen).

Aufräumen:

Damit keine Bruchstücke liegenbleiben sollte man eine Named Pipe immer wieder neu anlegen und nach dem Aufruf direkt löschen.

Andere Anwendungsgebiete:

nc kann hier mit jeder Art TCP/IP-Verbindung umgehen, es ist also nicht auf Webkommunikation begrenzt. Besonders bei Anwendungen mit dauerhaft gehaltenen Verbindungen kann nc hier sein volles Potenzial ausspielen. Dies kann besonders Interessant sein bei:

  • Mail-Servern
  • Chat-Servern
  • Spiele-Servern
  • generell allem, bei dem man eine Serveradresse angeben muss

Sie können so rausfinden, welches Protokoll Ihr Netzwerkdrucker spricht und ob eine angeblich verschlüsselte Verbindung wirklich verschlüsselt ist (nc zeigt Binärdaten, wie verschlüsselte oder komprimierte Verbindungen und Dateiinhalte natürlich nur in Form von Datenmüll an).

Fazit:

Mit nc lassen sich auf viele Weisen Daten sammeln, die einem bei der Fehlersuche und -analyse hilfreich sein können.
Obige Beispiele sind nur ein erster Ansatz, sicherlich gibt es noch raffiniertere Kombinationen. Schreiben Sie gerne Ihre eignen Tricks zu diesem Thema in die Kommentare.

Die Zwickmühle beim Betreiben von verschlüsselten Netzdiensten aus Betreibersicht

Angesichts der Schwachstellen rund um bestimmte Verschlüsselungsarten (Poodle und Logjam waren die bekanntesten in letzter Zeit) hat man es als Betreiber schwer, die „optimale“ Konfiguration für Netzdienste zu finden, die verschlüsselte Kommunikation anbieten. Auf der einen Seite möchte man nach Möglichkeit Benutzer mit älteren Geräten, die noch nicht die neuesten Verfahren implementiert haben, nicht völlig von der Nutzung ausschließen, auf der anderen Seite gelten bestimmte Verfahren inzwischen als so unsicher, dass man diese als Serverbetreiber auf gar keinen Fall mehr anbieten möchte, um Nutzer nicht in trügerischer Sicherheit zu wägen.

Das gilt insbesondere dann, wenn als Szenario droht, dass ein Angreifer sich in die Verbindung zwischen Server und Client einklinken kann und dann dafür sorgt, dass die beiden eigentlichen Kommunikationspartner sich auf eine Primitiv-Verschlüsselung einlassen, weil der Angreifer vortäuscht, der jeweils andere Partner würde keine starke Verschlüsselung unterstützen („Downgrade-Attack“). In einem solchen Fall braucht der Angreifer dann nur noch die Primitiv-Verschlüsselung zu knacken anstelle der starken Verschlüsselung, die die beiden Kommpunikationspartner im Normalfall untereinander vereinbart hätten.

Webserver und andere Dienste

Weiter verkompliziert wird die Lage dadurch, dass Angriffsszenarien bei verschiedenen Netzdiensten unterschiedlich zu beurteilen sind. So sind Angriffe, die darauf beruhen, dass einer der Kommunikationspartner unfreiwillig dazu gebracht werden kann, häufig Datenpakete mit annähernd gleichem Inhalt zu senden, bei Webseiten bis zu einem gewissen Grad realistisch. Schafft es der Angreifer, das Opfer auf eine Webseite unter seiner Kontrolle zu locken, so sind automatisierte Datenabrufe durch eingebetteten Skriptcode denkbar, ohne dass es direkt auffällt. Bei anderen Diensten, beispielsweise E-Mail mit einem Mailclient, gibt es hingegen kein ernstzunehmendes Szenario, wie ein Angreifer von außerhalb den Computer des Opfers automatisiert dazu bringen kann, selbständig mit gewisser Regelmäßigkeit gleichartige Datenpakete zu verschicken. Das ist umso mehr eine Besonderheit des Webs gegenüber anderen Netzdiensten, weil das Angriffsziel „Session-Cookie“ auch nur im WWW-Bereich wirklich existiert.

Alte Software überall

Als wäre dieses Spannungsfeld nicht schon vertrackt genug, kann als weitere Schwierigkeitsstufe noch dazukommen, dass man nicht nur bei den fremden Kommunikationspartnern nicht die neuesten Verschlüsselungsverfahren voraussetzen kann, sondern dass man auch als Anbieter nicht all das nutzen kann, was theoretisch verfügbar ist. So steht am RRZK für den Betrieb von Webservern i.d.R. als Betriebsystem Red Hat Enterprise Linux 6 (RHEL6) zur Verfügung. Dieses bringt aber nicht die jeweils neuesten Programmversionen mit, sondern im Regelfall diejenigen Versionen, die bei Erscheinen des Betriebssystems aktuell waren, jedoch natürlich um in der Zwischenzeit bekanntgewordene Sicherheitslücken bereinigt.

Für RHEL6 bedeutet das ganz konkret, dass nur die Funktionen von openssl 1.0.1 zur Verfügung stehen (anstelle von openssl 1.0.2) sowie der Apache-Webserver aus der 2.2er Versionslinie (anstatt 2.4). Damit sind einige der Empfehlungen für Serverbereiter, wie Sie beispielsweise von den Entdeckern des Logjam-Problems gegeben werden, nicht umsetzbar. Das Definieren individueller sog. Diffie-Hellman-Parameter etwa ist erst mit den neuesten Versionen des Apache-Webservers (ab 2.4.8) möglich.

Empfehlung für Apache 2.2 unter RHEL6

Um nun unter RHEL6 einen Apache-Webserver zu betreiben, der Webseiten ausschließlich verschlüsselt (per https) ausliefert, und das unter den gegebenen Umständen mit einem als möglichst sicher geltenden Kompromiss, kann man folgende Einstellungen in der allgemeinen Apache-Konfiguration verwenden:


SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite HIGH:MEDIUM:!ADH:!MD5:!RC4
SSLHonorCipherOrder on

Das ist zunächst einmal wenig spektakulär und kaum anders als das, was von den Logjam-Entdeckern empfohlen wird. In der Praxis läuft es darauf hinaus, dass die hier vorgeschlagene Konfiguration keine Präferenz für AES-128-Verschlüsselung enthält, so dass von den meisten heutigen Clients eine AES-256-Verschlüsselung verwendet werden wird. Ob man in dem gegebenen Kontext (Abruf von Webseiten) nun AES-128 oder AES-256 den Vorzug geben sollte ist für mich nicht zu beurteilen und wird in der Praxis wohl auch kaum eine Rolle spielen. Die theoretische Angreifbarkeit von AES-256 gegenüber AES-128 (hier ein alter und bekannter Blogartikel von Bruce Schneider dazu) bezieht sich auf mögliche Related-Key-Angriffe und ist in dieser Frage von untergeordneter Bedeutung.

Lässt man die oben genannte Einstellung SSLHonorCipherOrder hingegen auf dem Standardwert off, statt sie wie empfohlen auf on zu setzen, so ändert sich in der Praxis bei den meisten Browsern wenig. Durch das Setzen von SSLHonorCipherOrder on sorgt man de facto nur dafür, dass Benutzer mancher Versionen des Internet Explorers unter Windows 7 zu ihrem Glück gezwungen werden und auch bei ihnen eine Verbindung mit Forward Secrecy aufgebaut wird. Auf die Belange von Nutzern, die auch heute noch die extrem veraltete und per se unsichere Kombination von Internet Explorer 6 und Windows XP einsetzen, wird hier keine Rücksicht mehr genommen. Diese früher nicht ganz kleine Gruppe an Webseitenbesuchern machte in der Vergangenheit viele faule Kompromisse notwendig.

Dem Browser den Weg zur Verschlüsselung weisen

Legt man Wert darauf, in dem beliebten SSL-Servertest von Qualys besonders gut abzuschneiden, ist SSLHonorCipherOrder on unbedingt notwendig. Jedoch reicht das Setzen dieser und der anderen allgemeinen Verschlüsselungseinstellungen nicht aus. Für ein gutes Testergebnis muss man auch dafür sorgen, dass Besucher ausschließlich verschlüsselt mit dem Server kommunizieren. Solange unverschlüsselte Kommunikation im Web der Normalfall ist, sind dazu noch ein paar weitere Anstrengungen in der Apache-Konfiguration notwendig.

Webseitenbesucher, die – aus welchem Grund auch immer – eine unverschlüsselte Verbindung zum Server aufbauen möchten, müssen also von diesem Vorhaben abgehalten werden. Verwendet man dazu virtuelle Hosts in der Apache-Konfiguration, so kann man die Besucher, die keine Verschlüsselung verwenden, per


<VirtualHost *:80>
  RedirectMatch permanent (.*) https://meinhostname.uni-koeln.de$1
</VirtualHost>

umlenken. Für Named Virtual Hosts wäre hier natürlich noch eine weitergehende Konfiguration nötig. Gezeigt werden soll anhand dieses Konfigurationsschnipsels eigentlich nur, dass man die Besucher am besten mit einer dauerhaften Umleitung (permanent) auf die verschlüsselte Version der Website lenkt.

https und nur https, in guten wie in schlechten Zeiten

Als Kür sendet man dann noch die Information an die Browser der Webseitenbesucher, es in Zukunft gar nicht erst über eine unverschlüsselte Verbindung zu probieren, sondern ausschließlich per https mit dem Server zu kommunizieren:


<VirtualHost *:443>
  # hier stehen normalerweise Einstellungen wie ServerName, DocumentRoot etc.
  
  # vvv Einschalten von HSTS aka HTTP Strict Transport Security, RFC 6797
  Header always set Strict-Transport-Security: max-age=31536000
  # ^^^ Strict Transport Security, funktioniert mit Apache 2.2.15
</VirtualHost>

In diesem Beispiel wird der abrufende Browser instruiert, dass die Information, mit diesem Server nur verschlüsselt zu kommunizieren, ca. ein Jahr lang (31536000 Sekunden) gültig ist. Dies kann man zum Glück auch schon mit dem bei RHEL6 mitgelieferten Webserver Apache 2.2.15 so einstellen.

Mit den auf diese Weise optimierten Einstellungen erhält der Webserver dann von dem erwähnten SSL-Test die Bestnote A+ attestiert, vorausgesetzt die übrigen Einstellungen (zum Zertifikat und der Kette der Zwischenzertifizierungsstellen etc.) sind ebenfalls in Ordnung. Diese Einstellungen sind aber nicht spezifisch für RHEL6, daher soll hier darauf nicht weiter eingegangen werden.

Streaming auf AppleTV über Subnetzgrenzen hinweg

airplay_appletvMit dem Update auf Softwareversion 6.1 bekam das AppleTV in Verbindung mit iOS 7.1 und höher ein neues Feature: AirPlay Discovery via Bluetooth. Dies ermöglicht nun viel einfacher die Verbindung zwischen AppleTV und AirPlay-Klienten, wenn sich diese nicht im selben IP-Subnetz befinden. Einrichtungen mit vielen IT-Anwendern sind gezwungen, einzelnen Abteilungen oder Arbeitsgruppen eigene getrennte IP-Subnetze zuzuordnen. Oft wird dem WLAN-Netz auch ein eigener IP-Bereich zugewiesen. Befindet sich das AppleTV dann netztechnisch im IP-Bereich einer Arbeitsgruppe, müssen die Klienten einige Barrieren überwinden.

Haben beide Geräte Bluetooth aktiviert und die aktuelle Softwareversion installiert, wird auf dem iPad/iPod/iPhone das AppleTV angezeigt. Unter Umständen ist jedoch keine Kommunikation zwischen den Klienten möglich. AirPlay erfordert, dass vom AppleTV eine neue TCP/UDP-Session zum Endgerät aufgebaut werden kann, obwohl die ursprüngliche Session vom Endgerät initiiert wurde.

Damit schließt AirPlay Umgebungen aus, die NAT mittels Port-Addresstranslation durchführen. Diese Hürde kann man jedoch durch Aufbau einer VPN-Verbindung überwinden. Verteilt das VPN-Gateway jedem Endgerät eine eigene IP, kann so doch AirPlay eingesetzt werden.

Nun müssen gegebenenfalls noch Freigaben eingerichtet werden, wenn die Subnetze durch eigene Firewalls abgesichert sind. Leider verwendet AirPlay dynamische Ports, so dass ganze Bereiche freigegeben werden müssen. Dabei verläuft die Kommunikation von hohen Ports (49152 – 65535) zu hohen Ports.

Folgende Freigaben sollten eingerichtet werden:Firewallregeln

Je nach Firewall-Typ müssen auch die Rückantworten zu den fünf Freigaben eingetragen werden, also Quellnetz/-port und Zielnetz/-port vertauscht.

Mit diesen Freigaben sollte AirPlay funktionieren. Wir konnten mit den gewählten Einstellungen Videos, Musik und den Bildschirminhalt erfolgreich auf das AppleTV streamen.