Shared-Secrets: Geheimnisse über verschlüsselte Links austauschen

Im Internet gibt es inzwischen eine größere Anzahl an Diensten, über die es möglich ist, Texte auszutauschen - der bekannteste davon dürfte wohl Pastebin.com sein. Einige davon haben zudem begonnen, damit zu werben, dass man über sie Geheimnisse austauschen kann, die wahlweise verschlüsselt auf dem Server abgelegt werden oder nur einen einzigen Abruf des Geheimnisses ermöglichen - beispielsweise OneTimeSecret.com.

Auf Arbeit haben wir vor kurzem nach einer Möglichkeit gesucht, Informationen möglichst sicher an einen Empfänger zu übertragen, ohne, dass auf dessen Seite Software installiert oder eine spezifische Konfiguration vorgenommen werden muss. Dabei bot sich solch ein einfacher Webdienst regelrecht an.

Allerdings sahen wir die vorhandenen Lösungen als eher kritisch an - denn obwohl ein Passwortschutz besteht, werden die Informationen (meistens unverschlüsselt) auf dem Server abgelegt. Dadurch hat der entsprechende Betreiber die Möglichkeit, auf sie zuzugreifen - natürlich auch jeder Hacker, dem es gelingt, in den jeweiligen Dienst einzudringen. Eine zusätzliche Verschlüsselung wiederum würde die Hürde auf der Seite des Empfängers wieder erhöhen - eine Alternative musste her.

Also begann ich damit, eine neue Lösung zu implementieren - das Ergebnis der Entwicklung wurde als Shared-Secrets auf Github veröffentlicht. Zudem ist in unserem Firmenblog ein begleitender Artikel veröffentlicht worden.

Im Gegensatz zu den üblichen Lösungen im Netz haben wir dabei auf mehrere Faktoren Wert gelegt:

  • Die Geheimnisse sollen nicht auf dem Server gespeichert werden.
  • Die Geheimnisse sollen nur ein Mal abrufbar sein, um einen Vertraulichkeitsverlust erkennen zu können.
  • Es muss möglich sein, ein Geheimnis zu teilen, ohne, dass der Server es lesen kann.
  • Es muss möglich sein, ein Geheimnis zu teilen, ohne, dass der Server bei der Verteilung involviert ist.

Dabei herausgekommen ist folgende Lösung: Das zu teilende Geheimnis wird via GPG verschlüsselt und Base64-encodiert. Der Base64-encodierte String wird in eine URL überführt. Bei Aufruf der URL wird der Base64-encodierte String an einen Server übertragen, der ihn decodieren und entschlüsseln kann. Das entschlüsselte Ergebnis wird anschließend angezeigt. Die Prüfsumme des Base64-encodierten Strings wird in einer Datenbank abgelegt. Zudem besteht die Möglichkeit, das Geheimnis vor dem Versand an den Server symmetrisch zu verschlüsseln und nach dem Abruf vom Server wieder zu entschlüsseln.

Auf diese recht einfache Weise konnten alle Designziele erfüllt werden:

  • Dadurch, dass das verschlüsselte Geheimnis direkt in der URL enthalten ist, muss es nicht auf dem Server gespeichert werden. Auch nach einem Abruf wird lediglich die Checksumme der URL und nicht das eigentliche Geheimnis gespeichert.
  • Durch das Speichern der Checksummen von bereits abgerufenen URLs ist es möglich, zu erkennen, wenn ein Geheimnis mehrfach abgerufen werden soll. Dieser Abruf kann dann unterbunden werden.
  • Mit der Möglichkeit, ein Geheimnis zusätzlich lokal zu ver- und entschlüsseln, besteht die Möglichkeit, ein Geheimnis auszutauschen, ohne, dass der Server dieses im Klartext lesen kann. Das verwendete Passwort kann bspw. über einen zweiten Kanal übertragen werden.
  • Dadurch, dass für die Erstellung der URL Standardverfahren eingesetzt werden, können diese lokal mit Hilfe einer einzelnen Shell-Befehlszeile erzeugt werden. Das erspart zudem die Bereitstellung einer API.

Ein weiterer Vorteil der gewählten Lösung ist, dass der Speicherbedarf recht gering ausfällt. Es muss großteilig nur die Checksumme eines tatsächlich abgerufenen Geheimnisses gespeichert werden. Geheimnisse, für die URLs erzeugt wurden, die aber nicht abgerufen werden, verbrauchen daher im Umkehrschluss auch keinen Speicherplatz.

Getestet werden kann die Anwendung unter secrets.syseleven.de - der Referenzinstallation der Anwendung. Über sie wird auch sichergestellt, dass es möglich ist, mit einem korrekten Setup ein A+ Rating im Mozilla Observatory zu erhalten.

Wenn ihr Feedback oder Verbesserungsvorschläge habt, hinterlasst einfach einen Kommentar. 🙂

Ausgetauschte Grüße, Kenny

CentOS 7 mit Two-Factor-Authentication absichern

Vor einiger Zeit hatte ich mal beschrieben, wie man SSH unter Debian mit Two-Factor-Authentication absichern kann. Das wollte ich nach meiner Migration zu CentOS 7 natürlich auch wieder haben. Allerdings musste ich feststellen, dass es für CentOS 7 keine aktuellen Pakete des PAMs gibt. So musste ich wohl oder übel das ganze selbst kompilieren. Die Fallstricke, die mir dabei begegnet sind, wollte ich einfach mal an dieser Stelle dokumentieren.

Bevor man loslegen kann, benötigt man zuerst einmal ein paar zusätzliche Pakete:

1
sudo yum install autoconf automake libtool make pam-devel unzip wget zip

Nun können wir mit der eigentlichen Installation beginnen:

1
2
3
4
5
wget https://github.com/google/google-authenticator/archive/master.zip
unzip ./master.zip
cd ./google-authenticator-master/libpam
./bootstrap.sh
./configure

Bis hierhin sollte alles funktioniert haben. Leider enthält die erstellte Konfiguration einen kleinen Fehler. Deshalb müssen wir händisch an den Anfang der Datei "./Makefile" folgende Zeile einfügen:

1
LDFLAGS="-lpam"

Nun kann es mit dem Kompilieren weitergehen:

1
2
3
4
5
6
7
make
sudo make install
sudo cp /usr/local/lib/security/pam_google_authenticator.so /lib64/security
make clean
cd ../..
rm ./master.zip
rm -R ./google-authenticator-master

Ab hier geht es weiter, wie bisher auch schon. Zuerst legen wir nun einen Gruppe "google-auth" an:

1
sudo groupadd google-auth

Zudem ändern wir in der Datei "/etc/ssh/sshd_conf" eine Einstellung:

1
ChallengeResponseAuthentication yes

Danach schreiben wir folgendes in die Datei "/etc/pam.d/sshd" (z.B. unter die restlichen "auth"-Einträge):

1
2
auth [success=1 default=ignore] pam_succeed_if.so user notingroup google-auth
auth required pam_google_authenticator.so

Mit einem Restart des SSH-Servers sind die Änderungen aktiv:

1
sudo systemctl restart sshd.service

Nun müssen die Nutzer, für die die Two-Factor-Authentication aktiviert werden soll, das Script zur Einrichtung der Two-Factor-Authentication in ihrem Account aufrufen:

1
google-authenticator

Und abschließend müssen diese Nutzer in die Gruppe "google-auth" aufgenommen werden:

1
sudo usermod -a -G google-auth <username>

Das war's! Mit diesen Schritten lässt sich unter CentOS 7 eine Two-Factor-Authentication einrichten. 🙂

Zwei-Faktor-Grüße, Kenny

PHP 7 unter CentOS 7 installieren

Nachdem ich letzte Woche gezeigt habe, welche Probleme man sich einhandeln kann, wenn man von PHP 5.6 auf PHP 7 wechselt, möchte ich heute einmal zeigen, wie man überhaupt zu PHP 7 wechseln kann. Da ich inzwischen mit allen Servern zu CentOS migriere, wird es das erste Mal sein, dass es sich nicht um ein Debian-Beispiel handelt. Das Gute an CentOS ist, dass es eine recht stabile Distribution ist - jedes Major Release erhält 10 Jahre lang Support. Das Schlechte an CentOS ist, dass viele Pakete dadurch in einer recht alten Version vorliegen, die lediglich mit Bug- und Security-Fixes versorgt werden. Bei meinen Webserverinstallationen möchte ich hingegen lieber neue Versionen betreiben, um neue Features zu erhalten.

Bei der Installation einer neueren Version hat man mehrere Möglichkeiten: entweder, man kompiliert PHP 7 selbst oder man setzt ein Dritt-Repository ein, in dem bereits vorkompilierte Pakete für PHP 7 enthalten sind. In diesem Fall habe ich mich für zweiteres entschieden. Mit ius.io gibt es für CentOS 7 ein Repository, in dem die wichtigsten Pakete enthalten sind und das aufgrund der Unterstützung des Hosters Rackspace lange erhalten bleiben sollte.

Um das Repository von IUS verwenden zu können, muss man im ersten Schritt deren RPM-Paket installieren, das sich darum kümmert, das Repository im System einzukonfigurieren:

1
2
3
wget "https://centos7.iuscommunity.org/ius-release.rpm"
sudo rpm -i ./ius-release.rpm
rm ./ius-release.rpm

Zusätzlich muss noch der öffentliche Schlüssel importiert werden, mit dessen Hilfe die Signaturen der heruntergeladenen Pakete überprüft werden können:

1
sudo rpm --import /etc/pki/rpm-gpg/IUS-COMMUNITY-GPG-KEY

Wenn man es noch nicht getan hat, sollte man weiterhin das EPEL-Repository mit einbinden, das weitere hilfreiche - und meist aktuellere - Software enthält. Das lässt sich durch die Softwareverwaltung realisieren:

1
sudo yum install epel-release

In meinem Fall installiere ich neben PHP auch immer gleich MariaDB und NGINX. Das IUS-Repository enthält auch eine aktuellere Version von MariaDB. Damit man diese installieren kann, müssen jedoch vorher die bereits vorhandenen "mariadb-libs" entfernt werden. Im Zuge dessen wird auch Postfix deinstalliert - wir werden es einfach im Anschluss erneut installieren:

1
sudo yum remove mariadb-libs

Nun können wir die gewünschte Software über die Softwareverwaltung installieren - Pakete, die über IUS installierten werden, enthalten immer den Suffix "u", um sie leichter erkennen zu können und Kollisionen mit Standardpaketen zu vermeiden:

1
sudo yum install mariadb101u-server nginx php70u-cli php70u-fpm php70u-gd php70u-imap php70u-intl php70u-json php70u-ldap php70u-mbstring php70u-mcrypt php70u-mysqlnd php70u-pdo php70u-pear php70u-pgsql php70u-process php70u-pspell php70u-recode php70u-soap php70u-xml php70u-xmlrpc postfix

Im Grunde ist man an dieser Stelle nun fertig und hat sein CentOS 7 mit PHP 7 ausgestattet. In meinem Fall gab es jedoch noch ein paar Dinge mehr zu tun, da ich SSH-Support in meinem PHP benötige. Da es hierfür von IUS noch kein fertiges Paket gibt (wohl deshalb, weil der SSH-Support für PHP 7 noch nicht stable ist), musste ich mir die Erweiterung selbst zusammen kompilieren.

Um das zu tun, müssen wir erst einmal noch weitere, benötigte Pakete installieren:

1
sudo yum install autoconf automake make openssl-devel php70u-devel unzip wget zip

Als nächstes holen, kompilieren und installieren wir die aktuelle Version der "libssh2"-Bibliothek:

1
2
3
4
5
6
7
8
9
10
wget https://www.libssh2.org/download/libssh2-1.7.0.tar.gz
tar -xzvf ./libssh2-1.7.0.tar.gz
cd ./libssh2-1.7.0
./configure
make
sudo make install
make clean
cd ..
rm ./libssh2-1.7.0.tar.gz
rm -R ./libssh2-1.7.0

Auf Github hat sich jemand die Mühe gemacht, die Quellen für PHP 7 kompilierbar einzurichten - dessen Änderungen werden auch die Basis für das zukünftige SSH-Modul sein. An dieses Github-Repository habe ich mich gehangen und alles selbst kompiliert. Sobald das stabilisierte Pakete bei IUS aufgenommen wurde, sollte man natürlich lieber auf dieses wechseln:

1
2
3
4
5
6
7
8
9
10
11
12
wget https://github.com/Sean-Der/pecl-networking-ssh2/archive/master.zip
unzip ./master.zip
cd ./pecl-networking-ssh2-master
phpize
./configure
make
sudo make install
make clean
cd ..
rm ./master.zip
rm -R ./pecl-networking-ssh2-master
sudo sh -c "echo 'extension=ssh2.so' >/etc/php.d/20-ssh2.ini"

Und schon hat man PHP 7 auf seinem CentOS 7 installiert und ist weiterhin bleading-edge unterwegs. 🙂

Aktualisierte Grüße, Kenny

Link Indication Plugin unter PHP 7 nutzen

Mit dem Wechsel von PHP 5.6 auf PHP 7 sind leider auch ein paar altgediente Plugins bei mir kaputt gegangen. Ein weiteres davon ist das Link Indication-Plugin, das ich vor einiger Zeit schon mal ein wenig angepasst hatte.

Um das Plugin unter PHP 7 wieder lauffähig zu bekommen, gehen wir in die Datei "./link-indication.php". Dort muss eine einzige Änderung vorgenommen werden, da das Plugin noch die Funktion eregi_replace() verwendet, die inzwischen entfernt wurde.

Hierzu suchen wir in der Funktion "LinkIndicationMain" nach dem einzigen Aufruf von "eregi_replace" und ersetzen die gesamte Zeile durch folgende neue Version:

1
2
3
4
5
                // ...

                $final_stuff = preg_replace('/[[:space:]]+/i', ' ', $final_stuff);

                // ...

Voila! Nun sollte das Plugin endlich wieder funktionieren.

Erneut reparierte Grüße, Kenny

P.S.: Ja, mir ist bekannt, dass auch dieses Plugin inzwischen bereits ziemlich outdated ist. Da ich allerdings aktuell an einem größeren Umbau werkele, lohnt sich ein Wechsel auf ein neues Link-Indication-Plugin im Moment einfach nicht. 😀

CodeColorer Plugin unter PHP 7 nutzen

Mit dem Wechsel von PHP 5.6 auf PHP 7 sind leider auch ein paar altgediente Plugins bei mir kaputt gegangen. Eines davon ist das CodeColorer-Plugin, das ich für das Syntax-Highlighting im Blog verwende.

Um das Plugin unter PHP 7 wieder lauffähig zu bekommen, gehen wir in die Datei "./codecolorer-core.php". Dort müssen drei kleinere Änderungen vorgenommen werden, da das Plugin noch den "/e"-Modificator in preg_replace()-Aufrufen verwendet, der inzwischen entfernt worden ist.

Als erstes suchen wir die Funktion "BeforeHighlightCodeBlock" und ersetzen sie durch diese neue Fassung:

1
2
3
4
5
6
  function BeforeHighlightCodeBlock($content) {
    $content = preg_replace_callback('#(\s*)\[cc([^\s\]_]*(?:_[^\s\]]*)?)([^\]]*)\](.*?)\[/cc\2\](\s*)#si', function ($params) { return $this->PerformHighlightCodeBlock($params[4], $params[3], $content, $params[2], $params[1], $params[5]); }, $content);
    $content = preg_replace_callback('#(\s*)\<code(.*?)\>(.*?)\</code\>(\s*)#si', function ($params) { return $this->PerformHighlightCodeBlock($params[3], $params[2], $content, '', $params[1], $params[4]); }, $content);

    return $content;
  }

Als nächstes suchen wir die Funktion "BeforeProtectComment" und ersetzen diese durch folgende neue Fassung:

1
2
3
4
5
6
  function BeforeProtectComment($content) {
    $content = preg_replace_callback('#(\s*)(\[cc[^\s\]_]*(?:_[^\s\]]*)?[^\]]*\].*?\[/cc\1\])(\s*)#si', function ($params) { return $this->PerformProtectComment($params[2], $content, $params[1], $params[3]); }, $content);
    $content = preg_replace_callback('#(\s*)(\<code.*?\>.*?\</code\>)(\s*)#si', function ($params) { return $this->PerformProtectComment($params[2], $content, $params[1], $params[3]); }, $content);

    return $content;
  }

Abschließend gehen wir noch in die Funktion "PerformHighlightCodeBlock". Hier ersetzen wir einen einzelnen if-Block durch eine neue Fassung:

1
2
3
4
5
6
7
8
9
    // ...

    if ($options['escaped']) {
      $text = html_entity_decode($text, ENT_QUOTES);
      $text = preg_replace_callback('~&#x0*([0-9a-f]+);~i', function ($params) { return chr(hexdec($params[1])); }, $text);
      $text = preg_replace_callback('~&#0*([0-9]+);~', function ($params) { return chr($params[1]); }, $text);
    }

    // ...

Voila! Schon sollte das Plugin auch unter PHP 7 wieder funktionieren, wie am ersten Tag.

Reparierte Grüße, Kenny

P.S.: Ja, mir ist bekannt, dass das Plugin inzwischen bereits ziemlich outdated ist. Da ich allerdings aktuell an einem größeren Umbau werkele, lohnt sich ein Wechsel auf ein neues Syntax-Highlighting-Plugin im Moment einfach nicht. 😀

Seite 1 von 87123...Letzte »