Uralter Software neues Leben einhauchen

Techniken: PHP, Javascript, BASH, Java

Ein Kunde von uns betreibt eine erfolgreiche Community-Chat-Webseite. Im Jahr 2018 wurde der Chat noch mit einer veralteten und schon lange nicht mehr gepflegten Java-Anwednung betrieben, auf deren Quellcode wir auch keinen Zugriff hatten. Kurz vor Weihnachten kam dann der Wunsch noch vor dem Jahresende das System unbedingt SSL-Fähig zu machen.

Der administrative Ansatz die SSL-Terminierung in einem Proxy vor der Anwendung zu machen scheitere leider an der falchlichen Anforderung, dass Moderatoren Besucher*innen anhand der IP-Adresse temporär sperren können sollten, die Anwendung dafür aber nur den IP-Header auswertete.

Mein erster Ansatz zu verscuhen die Software direkt im dekompilierten Quellcode so zu patchen, dass statt der IP-Sperren auf Basis von durchgereichten Headern (x-forwarded...) passieren würde wollte zumindest mir und zur Hilfe geeilten Kollegen nicht gelingen.

SSL-terminierung im eingebetteten Webserver erzwingen

Zum Glück war der Software ein eingebetterer Webserver (netty) als einfaches jar-Archiv beigelegt. Da Netty im Quellcode vorliegt (danke Open Source) habe ich mich dann entschieden dort die SSL-Terminierung zu machen. Dazu waren eigentlich nur zwei Schritte nötig:

  1. Da ich die Initalisierung von Netty aus dem proprietären Teil der Software nicht ändern konnte, habe ich den Netty angepasst, SSL per Default zu verwenden.
  2. Anschließend mussten nur noch die bestehenden Let’s Encrypt-Zertifikate in den Netty geladen werden (was einfacher klingt als es dann ist)

Mit den beiden recht einfachen Schritten konnte ich die Software noch mal über ein paar Jaare retten, bis sie vor wenigen Monaten durch eine kompletrt neue Lösung ersetzt wurde.

SSL Erzwingen

    public NioSocketChannel(
            Channel parent, ChannelFactory factory,
            ChannelPipeline pipeline, ChannelSink sink,
            SocketChannel socket, NioWorker worker) {

        super(parent, factory, pipeline, sink, worker, socket);
        if(socket.socket().getLocalPort()==41127){
		    //serve local api without ssl
        }
        else{
            //force ssl
            pipeline.addFirst("ssl", SSLHandlerProvider.getSSLHandler());
        }
        config = new DefaultNioSocketChannelConfig(socket.socket());
    }

Let´s encrypt konvertieren

#!/bin/sh

DOMAIN=EXAMPLE.com
KEYSTOREPW=123456
LIVE=/etc/letsencrypt/live/$DOMAIN

mkdir etc
cd etc

sudo openssl pkcs12 -export -in $LIVE/cert.pem -inkey $LIVE/privkey.pem -out cert_and_key.p12 -name myalias -CAfile $LIVE/fullchain.pem -caname root -password pass:$KEYSTOREPW
sudo keytool -importkeystore -destkeystore keystore.jks -srckeystore cert_and_key.p12 -srcstoretype PKCS12 -alias myalias -srcstorepass $KEYSTOREPW -deststorepass $KEYSTOREPW -destkeypass $KEYSTOREPW
sudo keytool -import -noprompt -trustcacerts -alias root -file $LIVE/fullchain.pem -keystore keystore.jks -srcstorepass $KEYSTOREPW -deststorepass $KEYSTOREPW -destkeypass $KEYSTOREPW

sudo openssl pkcs12 -export -in $LIVE/fullchain.pem -inkey $LIVE/privkey.pem -out pkcs.p12 -name glassfish-instance -password pass:$KEYSTOREPW
sudo keytool -importkeystore -destkeystore keystore.jks -srckeystore pkcs.p12 -srcstoretype PKCS12 -alias glassfish-instance -srcstorepass $KEYSTOREPW -deststorepass $KEYSTOREPW -destkeypass $KEYSTOREPW
sudo openssl pkcs12 -export -in $LIVE/fullchain.pem -inkey $LIVE/privkey.pem -out pkcs.p12 -name s1as -password pass:$KEYSTOREPW
sudo keytool -importkeystore -destkeystore keystore.jks -srckeystore pkcs.p12 -srcstoretype PKCS12 -alias s1as -srcstorepass $KEYSTOREPW -deststorepass $KEYSTOREPW -destkeypass $KEYSTOREPW

sudo keytool -list -keystore keystore.jks -storepass $KEYSTOREPW

sudo cp -f keystore.jks /opt/ssl_certs/$DOMAIN.jks
cd ..
sudo rm -rf etc