• Es freut uns dass du in unser Minecraft Forum gefunden hast. Hier kannst du mit über 130.000 Minecraft Fans über Minecraft diskutieren, Fragen stellen und anderen helfen. In diesem Minecraft Forum kannst du auch nach Teammitgliedern, Administratoren, Moderatoren , Supporter oder Sponsoren suchen. Gerne kannst du im Offtopic Bereich unseres Minecraft Forums auch über nicht Minecraft spezifische Themen reden. Wir hoffen dir gefällt es in unserem Minecraft Forum!

PlugIn TLS Verbindung, Verschlüsselung von Daten (Netty)

Blura_

Kuhfänger
Registriert
25 Juli 2019
Beiträge
79
Diamanten
300
Minecraft
Blura_
Hallo,
ich habe einen Netty Server-Client System verwendet, damit ich z. B. bei MultiProxy die Proxys kommunizieren lassen kann, etc. Ich verwende dabei eine TLS Verbindung. Daher wollte ich fragen, ob es nötig ist, die Daten, die ich übertrage zu verschlüsseln, oder ob es reicht das ich eine TLS-Verbindung nutze, da eine TLS-Verbindung bereits eine verschlüsselte Verbindung ist.

Und ich hätte noch eine Frage, wie ich abfrage, ob ein Netty-Client, der sich mit dem Netty-Server verbinden möchte, ein Proxy von meinem Server ist, oder ob es eine fremde Person ist, der sich in den Netty-Server einschleusen möchte, damit sich kein Fremder sich mit dem Server einfach verbinden kann. Ich könnte dabei zwar einfach die IP abfragen, von dem sich der Client verbindet, jedoch könnte man das durch IP-Spoofing umgehen. Da habe ich die Idee gehabt, ob es nicht gut wäre, einen Passwort einzubauen, das heißt wenn sich ein Netty-Client mit dem Netty-Server kommunizieren möchte, muss er nach der Verbindung zum Netty-Server den Passwort senden und erst dann nimmt der Server die Daten, die der Client sendet an. Da wäre ich aber wieder bei der 1. Frage, ob der Passwort beim übertragen auch wieder verschlüsselt werden muss, oder ob es reicht wenn die Verbindung durch TLS verschlüsselt ist.

Ich hoffe ich habe mich klar ausgedrückt.
Falls ihr etwas nicht versteht, könnt ihr gerne Fragen.
Danke schonmal für euere Antworten!
 

Chrisliebär❤️

nur echt mit ❤️
Moderator
Registriert
19 Mai 2014
Beiträge
1.675
Diamanten
830
Es wäre spannend zu wissen, wie du die TLS Verbindung realisiert hast. Sofern du das nämlich mit den korrekten Werkzeug tust, wäre die naheliegende Lösung, dass du zur Verifizierung deiner Server einfach TLS Client Auth verwendest. Das ist den meisten Normalsterblichen gar nicht bekannt, aber nicht nur der Server, sondern auch der Client kann sich in einem TLS Handshake mit einem Zertifikat authentifizieren. Dann hätte nämlich jeder deine Netty-Clients ein eigenes Clientzertifikat und würde sich damit gegenüber dem TLS-Server identifizieren.

Der weitere Vorteil ist, dass du dann auch lernst, was TLS alles so schönes kann.

Ansonsten wäre ein Passwort in der TLS Verbindung selbst natürlich auch sicher, aber dann benutzt halt jeder Server das selbe Passwort. Gibt noch ein paar andere Nachteile von Shared Secrets (der Fachbegriff, wenn beide Seiten das geheime Wort kennen).
 

Blura_

Kuhfänger
Registriert
25 Juli 2019
Beiträge
79
Diamanten
300
Minecraft
Blura_
Es wäre spannend zu wissen, wie du die TLS Verbindung realisiert hast. Sofern du das nämlich mit den korrekten Werkzeug tust, wäre die naheliegende Lösung, dass du zur Verifizierung deiner Server einfach TLS Client Auth verwendest. Das ist den meisten Normalsterblichen gar nicht bekannt, aber nicht nur der Server, sondern auch der Client kann sich in einem TLS Handshake mit einem Zertifikat authentifizieren. Dann hätte nämlich jeder deine Netty-Clients ein eigenes Clientzertifikat und würde sich damit gegenüber dem TLS-Server identifizieren.

Der weitere Vorteil ist, dass du dann auch lernst, was TLS alles so schönes kann.

Ansonsten wäre ein Passwort in der TLS Verbindung selbst natürlich auch sicher, aber dann benutzt halt jeder Server das selbe Passwort. Gibt noch ein paar andere Nachteile von Shared Secrets (der Fachbegriff, wenn beide Seiten das geheime Wort kennen).

Netty-Server:
                    SelfSignedCertificate ssc = new SelfSignedCertificate();
                    SslContext context = SslContextBuilder
                            .forServer(ssc.certificate(), ssc.privateKey()).protocols("TLSv1.3")
                            .build();

                    SslHandler sslhandler = context.newHandler(channel.alloc());
                    ChannelPipeline pipeline = channel.pipeline();
                    pipeline.addLast(sslhandler);
                    pipeline.addLast(new StringEncoder(CHARSET),
                            new LineBasedFrameDecoder(MAX_LINE_LENGTH), new StringDecoder(CHARSET),
                            new ServerListener());

Netty-Client:
                SslContext context = SslContextBuilder.forClient().protocols("TLSv1.3")
                        .trustManager(InsecureTrustManagerFactory.INSTANCE).build();
                SslHandler sslhandler = context.newHandler(channel.alloc(), SERVER_HOST, PORT);

                ChannelPipeline pipeline = channel.pipeline();
                pipeline.addLast(sslhandler);
                pipeline.addLast(new StringEncoder(CHARSET),
                        new LineBasedFrameDecoder(MAX_LINE_LENGTH), new StringDecoder(CHARSET),
                        Client.clientListener);

So habe ich die Verbindung über TLS aktiviert.
 

Chrisliebär❤️

nur echt mit ❤️
Moderator
Registriert
19 Mai 2014
Beiträge
1.675
Diamanten
830
Also dass du InsecureTrustManagerFactory benutzt ist natürlich Käse. Ich weiß nicht ob dir klar ist, was das für die Sicherheit deiner TLS Verbindung bedeutet. Damit hast du effektiv gesehen keine Verschlüsslung und auch kein TLS, da du alle Zertifikate akzeptierst.

Ich hab mal versuch rauszufinden, wie man mit Natty Client Auth benutzt, aber ohne IDE ist das zu viel Arbeit mit den Javadocs, ein Beispiel konnte ich leider auch nicht finden. Ich vermute du musst lediglich dem TLS Server mitteilen, dass er die Clients authentifizieren soll. Vermutlich hier: https://netty.io/4.1/api/index.html

Hier wäre noch ein bisschen unvollständiger Code: https://www.programcreek.com/java-api-examples/?api=io.netty.handler.ssl.ClientAuth

Du musst für TLS halt deinen Keystore korrekt aufsetzen, das scheinst du bisher aber gar nicht zu machen, da du einfach alle Zertifikate akzeptierst. Ansonsten gilt was ich schon eingangs erwähnt habe. Shared Secret kannste machen, hängt von deinem Anwendungsfall ab. Wenn ich TLS schon richtig einrichtige, würde ich persönlich auch noch die paar extra Schritte für Client Auth machen. Ist aber dir überlassen.
 

Blura_

Kuhfänger
Registriert
25 Juli 2019
Beiträge
79
Diamanten
300
Minecraft
Blura_
Ich habe den KeyStore aufgesetzt, aber es klappt irgendwie nicht...

Netty-Server:
                @Override
                protected void initChannel(SocketChannel channel) throws Exception {
                    SelfSignedCertificate ssc = new SelfSignedCertificate();
                    SslContext context = SslContextBuilder
                            .forServer(ssc.certificate(), ssc.privateKey()).protocols("TLSv1.3")
                            .build();

                    SslHandler sslhandler = context.newHandler(channel.alloc());
                    ChannelPipeline pipeline = channel.pipeline();
                    pipeline.addLast(sslhandler);
                    pipeline.addLast(new StringEncoder(CHARSET),
                            new LineBasedFrameDecoder(MAX_LINE_LENGTH), new StringDecoder(CHARSET),
                            new ServerListener());
                }

Netty-Client:
                @Override
                protected void initChannel(SocketChannel channel) throws Exception {
                    KeyStore keyStore = KeyStore.getInstance("JKS");
                    char[] password = "abctest".toCharArray();
                    keyStore.load(null, password);
                    TrustManagerFactory tmf = TrustManagerFactory
                            .getInstance(TrustManagerFactory.getDefaultAlgorithm());
                    tmf.init(keyStore);

                    SslContext context = SslContextBuilder.forClient().protocols("TLSv1.3")
                            .trustManager(tmf).build();
                    SslHandler sslhandler = context.newHandler(channel.alloc(), SERVER_HOST, PORT);

                    ChannelPipeline pipeline = channel.pipeline();
                    pipeline.addLast(sslhandler);
                    pipeline.addLast(new StringEncoder(CHARSET),
                            new LineBasedFrameDecoder(MAX_LINE_LENGTH), new StringDecoder(CHARSET),
                            Client.clientListener);

                }

Ich bekomme einen Fehler:
Fehler:
Dez 28, 2020 11:55:09 AM io.netty.channel.DefaultChannelPipeline onUnhandledInboundException
WARNUNG: An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: error:10000438:SSL routines:OPENSSL_internal:TLSV1_ALERT_INTERNAL_ERROR
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:478)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Unknown Source)
Caused by: javax.net.ssl.SSLHandshakeException: error:10000438:SSL routines:OPENSSL_internal:TLSV1_ALERT_INTERNAL_ERROR
    at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.shutdownWithError(ReferenceCountedOpenSslEngine.java:1031)
    at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.sslReadErrorResult(ReferenceCountedOpenSslEngine.java:1300)
    at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.unwrap(ReferenceCountedOpenSslEngine.java:1249)
    at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.unwrap(ReferenceCountedOpenSslEngine.java:1325)
    at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.unwrap(ReferenceCountedOpenSslEngine.java:1368)
    at io.netty.handler.ssl.SslHandler$SslEngineType$1.unwrap(SslHandler.java:206)
    at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1387)
    at io.netty.handler.ssl.SslHandler.decodeNonJdkCompatible(SslHandler.java:1294)
    at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1331)
    at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508)
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:447)
    ... 17 more

Dez 28, 2020 11:55:09 AM io.netty.channel.DefaultChannelPipeline onUnhandledInboundException
WARNUNG: An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: General OpenSslEngine problem
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:478)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Unknown Source)
Caused by: javax.net.ssl.SSLHandshakeException: General OpenSslEngine problem
    at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.handshakeException(ReferenceCountedOpenSslEngine.java:1772)
    at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.wrap(ReferenceCountedOpenSslEngine.java:777)
    at javax.net.ssl.SSLEngine.wrap(Unknown Source)
    at io.netty.handler.ssl.SslHandler.wrap(SslHandler.java:1086)
    at io.netty.handler.ssl.SslHandler.wrapNonAppData(SslHandler.java:977)
    at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1450)
    at io.netty.handler.ssl.SslHandler.decodeNonJdkCompatible(SslHandler.java:1294)
    at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1331)
    at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508)
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:447)
    ... 17 more
Caused by: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
    at sun.security.validator.PKIXValidator.<init>(Unknown Source)
    at sun.security.validator.Validator.getInstance(Unknown Source)
    at sun.security.ssl.X509TrustManagerImpl.getValidator(Unknown Source)
    at sun.security.ssl.X509TrustManagerImpl.checkTrustedInit(Unknown Source)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
    at io.netty.handler.ssl.OpenSslTlsv13X509ExtendedTrustManager.checkServerTrusted(OpenSslTlsv13X509ExtendedTrustManager.java:223)
    at io.netty.handler.ssl.ReferenceCountedOpenSslClientContext$ExtendedTrustManagerVerifyCallback.verify(ReferenceCountedOpenSslClientContext.java:261)
    at io.netty.handler.ssl.ReferenceCountedOpenSslContext$AbstractCertificateVerifier.verify(ReferenceCountedOpenSslContext.java:698)
    at io.netty.internal.tcnative.SSL.readFromSSL(Native Method)
    at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.readPlaintextData(ReferenceCountedOpenSslEngine.java:596)
    at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.unwrap(ReferenceCountedOpenSslEngine.java:1203)
    at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.unwrap(ReferenceCountedOpenSslEngine.java:1325)
    at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.unwrap(ReferenceCountedOpenSslEngine.java:1368)
    at io.netty.handler.ssl.SslHandler$SslEngineType$1.unwrap(SslHandler.java:206)
    at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1387)
    ... 21 more
    Suppressed: javax.net.ssl.SSLHandshakeException: error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED
        at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.sslReadErrorResult(ReferenceCountedOpenSslEngine.java:1288)
        at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.unwrap(ReferenceCountedOpenSslEngine.java:1249)
        ... 25 more
Caused by: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
    at java.security.cert.PKIXParameters.setTrustAnchors(Unknown Source)
    at java.security.cert.PKIXParameters.<init>(Unknown Source)
    at java.security.cert.PKIXBuilderParameters.<init>(Unknown Source)
    ... 37 more
 

UnityGaming

Workaholic
Registriert
25 Oktober 2015
Beiträge
527
Alter
26
Diamanten
312
Minecraft
FastFelix771
Nur so als Hinweis, TLSv1.3 ist noch relativ "neu". Du solltest evtl. noch TLSv1.2 zusätzlich supporten.
Java hat jetzt keine blühende Geschichte von exzellentem SSL Support., bezüglich Aktualität.


Code:
 Suppressed: javax.net.ssl.SSLHandshakeException: error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED

Hier scheint der Knackpunkt zu liegen, ich hab mir jetzt aber nicht den ganzen Code durchgelesen.
 

Blura_

Kuhfänger
Registriert
25 Juli 2019
Beiträge
79
Diamanten
300
Minecraft
Blura_
Nur so als Hinweis, TLSv1.3 ist noch relativ "neu". Du solltest evtl. noch TLSv1.2 zusätzlich supporten.
Java hat jetzt keine blühende Geschichte von exzellentem SSL Support., bezüglich Aktualität.


Code:
 Suppressed: javax.net.ssl.SSLHandshakeException: error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED

Hier scheint der Knackpunkt zu liegen, ich hab mir jetzt aber nicht den ganzen Code durchgelesen.

ja, ich mache irgendwo beim Handshake einen Fehler, bzw. seit dem ich den trustManager geändert habe, kommt ein exception, doch ich weiß nicht was ich daran falsch mache und was ich ändern muss...
 

Blura_

Kuhfänger
Registriert
25 Juli 2019
Beiträge
79
Diamanten
300
Minecraft
Blura_
Ich habe es nun geschafft, das kein error kommt, doch ich weiß nicht ob das so mit den Zertifikaten und TLS stimmt:
Netty-Server und Netty-Client:
        try {
            Server.bossGroup = new NioEventLoopGroup();
            Server.workerGroup = new NioEventLoopGroup();
            Server.bootstrap = new ServerBootstrap();

            Server.bootstrap.group(Server.bossGroup, Server.workerGroup);
            Server.bootstrap.channel(NioServerSocketChannel.class);

            KeyStore keyStore = KeyStore.getInstance("JKS");
            char[] password = "abctest".toCharArray();
            keyStore.load(null, password);
            SelfSignedCertificate ssc = new SelfSignedCertificate();
            keyStore.setCertificateEntry("aa", ssc.cert());
            try(FileOutputStream fos = new FileOutputStream("testKey.jks")) {
                keyStore.store(fos, password);
            }

            Server.bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {

                @Override
                protected void initChannel(SocketChannel channel) throws Exception {
                    TrustManagerFactory tmf = TrustManagerFactory
                            .getInstance(TrustManagerFactory.getDefaultAlgorithm());
                    tmf.init(keyStore);

                    SslContext context = SslContextBuilder
                            .forServer(ssc.certificate(), ssc.privateKey()).protocols("TLSv1.3")
                            .trustManager(tmf).build();
                    SslHandler sslhandler = context.newHandler(channel.alloc());
                    ChannelPipeline pipeline = channel.pipeline();
                    pipeline.addLast(sslhandler);
                    pipeline.addLast(new StringEncoder(CHARSET),
                            new LineBasedFrameDecoder(MAX_LINE_LENGTH), new StringDecoder(CHARSET),
                            new ServerListener());
                }
            });

            Server.bootstrap.option(ChannelOption.SO_BACKLOG, 50);
            Server.bootstrap.childOption(ChannelOption.SO_KEEPALIVE, KEEPALIVE);
            Server.future = Server.bootstrap.bind(SERVER_HOST, PORT).sync();

            Client.workerGroup = new NioEventLoopGroup();
            Client.bootstrap = new Bootstrap();
            Client.bootstrap.group(Server.workerGroup);
            Client.bootstrap.channel(NioSocketChannel.class);
            Client.bootstrap.option(ChannelOption.SO_KEEPALIVE, KEEPALIVE);
            Client.bootstrap.handler(new ChannelInitializer<SocketChannel>() {

                @Override
                protected void initChannel(SocketChannel channel) throws Exception {
                    TrustManagerFactory tmf = TrustManagerFactory
                            .getInstance(TrustManagerFactory.getDefaultAlgorithm());
                    tmf.init(keyStore);
                    SslContext context = SslContextBuilder.forClient().protocols("TLSv1.3")
                            .trustManager(tmf).build();
                    SslHandler sslhandler = context.newHandler(channel.alloc(), SERVER_HOST, PORT);
                    ChannelPipeline pipeline = channel.pipeline();
                    pipeline.addLast(sslhandler);
                    pipeline.addLast(new StringEncoder(CHARSET),
                            new LineBasedFrameDecoder(MAX_LINE_LENGTH), new StringDecoder(CHARSET),
                            Client.clientListener);

                }
            });
            Client.bootstrap.connect(SERVER_HOST, PORT);

Falls das so wie ich das gemacht habe richtig ist hätte ich da noch ein paar Fragen:
- Ich habe gehört, dass SelfSignedCertificate nicht sicher ist. Stimmt das und wenn ja was sollte ich statt dessen nutzen?
- Ich habe immer noch nicht herausgefunden, wie man die Clients mithilfe von TLS verifizieren kann. Hat da jemand vlt. eine Idee wo ich am besten nachschauen könnte. Es wäre auch ganz gut, wenn jemand einen Beispielcode dafür senden könnte.
 
Zuletzt bearbeitet von einem Moderator:

Chrisliebär❤️

nur echt mit ❤️
Moderator
Registriert
19 Mai 2014
Beiträge
1.675
Diamanten
830
- Ich habe gehört, dass SelfSignedCertificate nicht sicher ist. Stimmt das und wenn ja was sollte ich statt dessen nutzen?
Über TLS gibts leider sehr viel falsches Halbwissen von vermeindlich seriösen Quellen. Einen richtig guten Link, der dir die Grundlagen erklärt, habe ich daher leider nicht. Die Kurzversion ist: TLS ist erstmal nur ein Protokoll um eine verschlüsselte Verbindung auszuhandeln. Da es aber unmöglich ist eine sichere Verbindung zwischen zwei Partnern aufzubauen, ohne vorher IRGENDEIN Geheimnis geteilt zu haben, gibt es CAs. Das sind Certificate Authorities und im Kontext von TLS erstmal einfach nur eine Instanz, welcher beide Parteien vertrauen. Vertrauen bedeutet hier allerdings nur, dass die CA nur solche Zertifikate ausstellt, von welchen sie geprüft hat, dass sie tatsächlich dem entsprechenden Kontaktpartner gehören. In den meisten Fällen ist das einfach die Domain. Eine CA zertifiziert dir also, dass du tatsächlich der Besitzer der Domain bist.

Jeder TLS Client bringt einen Truststore mit (oder nutzt den das Betriebssystems) und wenn du eine TLS Verbindung aufbaust, schickt dir der Kontaktpartner das Zertifikat von einer CA, welches bestätigt, dass er tatsächlich der Inhaber der Domain ist. Wenn ihr beide nun eben dieser CA vertraut, dann könnt ihr darüber eine sichere Verbindung aushandeln. Es gibt also eine übergeordnete Instanz, die beide Parteien kennen und vertrauen. Und über diese Kette von vertrauen, vertrauen wir dann auch allen anderen Instanzen, welcher von dieser Instanz beglaubigt wurden. Das nennt sich "Chain-of-Trust". Was vielen nicht bewusst ist, ist die Tatsache, dass der TLS Server ebenfalls vom Client ein gültiges Zertifikat verlangen kann. Auf diese Weise wissen beide Teilnehmer, mit wem sie "sprechen". Auch wenn eigentlich jeder Webbrowser das kann, wird es nirgendwo genutzt. Stattdessen benutzt man meist Logins mit statischen Passwort.

Das ist eine starke Vereinfachung dessen, was da genau passiert. Ein selbstsigniertes Zertifikat ist ein Zertifikat, welches mit dem eigenen privaten Schlüssel signiert wurde. Das ist das Äquivalent von "Ich bin ich". Das heißt hier gibt es keine Chain of Trust. Du musst halt der Instanz selbst glauben. Du weißt aber nicht, ob es nicht noch eine andere Instanz gibt.

Dein InsecureTrustManager hat genau das getan: Er vertraut einfach jedem. Das ist für Testzwecke okay, ansonsten bietet es aber gegen aktive Angreifer gar keine Sicherheit. Da du in einem geschlossenen System arbeitest, brauchst du keine kommerzielle CA. Du kannst deine eigene CA betreiben. Mit dieser bekommt jeder deiner Netzwerkteilnehmer ein eigenes Zertifikat, welches du mit dieser signierst. Dann packst du das Zertifikat dieser CA in die Truststores deiner Netzwerkteilnehmer und schon können diese sich gegenseitig bestätigen.

Das ist die Highlevel Erklärung, was da genau passiert. Der Teufel steckt halt an ganz vielen Detailfragen und Möglichkeiten, welche dir TLS bietet sowie verschiedene Angriffszenarien vor denen man sich vielleicht ebenfalls schützen möchte. Im Grunde sollte die Aufgabe aber aus folgenden Schritten bestehen:
  1. Eigene Selbstsignierte CA einrichten
  2. Schlüsselpaare für Netzwerkteilnehmer erstellen (das fällt häufig mit dem nächsten Schritt zusammen, ist aber eigentlich unabhängig)
  3. Zertifikate für Schlüsselpare für TLS-Server und TLS-Clients erstellen (optional auch als Client und Server markieren)
  4. Den privaten Schlüssel der CA gut schützen
  5. Auf jeden Netzwerkteilnehmer das Zertifikat der CA packen.
  6. Bis hier hin ist das ganze unabhängig von Java und das allgemeine Vorgehen
  7. Truststore für jeden Client einrichten oder bei Softwarestart konfigurieren. Darin gehört:
    1. Private Key des Teilnehmers
    2. Zugehöriges Zertifikat, signiert von der CA
    3. Das Zertifikat der CA
  8. Das Ganze Geraffel in Nettys SSL Context klopfen
  9. Fertig
Aktuell erzeugst du bei jedem Start ein neues Zertifikat, das ist natürlich nicht möglich. Die Zertifikate werden einmal zentral erstellt und dann verteilt. Wie gesagt: Für eine sichere Verbindung muss man immer vorher irgendeine Art von Information geteilt haben.

Das ist leider nichts, was man in ein paar Tagen fertigstellt, wenn man mit TLS und der Trust of Chain nicht vertraut ist. Ich hab das selbst mit Netty vor vielen Jahren und der 3.x gemacht. Wenn du natürlich die Bereitschaft hast das zu Lernen, ist das natürlich auch ein wertvoller Skill. Leider kann ich keine guten Quellen empfehlen, die das Thema komplett erklären würden. Das sind allerdings auch mehrere kryptografische Verfahren, die in TLS verwendet werden, von daher auch nicht sonderlich verwunderlich.

Wenn dir das zu viel Arbeit ist, könntest du auch andere Optionen ausprobieren. Innerhalb des selben Hosts brauchst du natürlich keine Verschlüsslung und falls du ein VLAN oder ähnliches zwischen deinen Servern aufbauen kannst und deinem Hoster vertraust, brauchst du auch keine Verschlüsslung. Ein VPN wäre eine ähnliche Option, wobei du hier auch wieder Zertifikate erstellen musst und zusätzlich das Netzwerk konfigurieren musst. Wenn dein Hoster seine Hardware richtig konfiguriert hat, kannst du IP Spoofing innerhalb des selben Netzwerkes ebenfalls ausschließen. Mit Docker Swarm Mode oder Kubernetes würdest du die verschlüsselte Verbindung ebenfalls "kostenlos" bekommen, aber dafür hast du einen Haufen weiterer Dinge, die du berücksichtigen müsstest.

Testen kannst du sowas sehr gut mit den eingebauten Funktionen von OpenSSL:
* https://www.openssl.org/docs/man1.0.2/man1/openssl-s_client.html
* https://www.openssl.org/docs/man1.0.2/man1/openssl-s_server.html
 
Zuletzt bearbeitet:

Blura_

Kuhfänger
Registriert
25 Juli 2019
Beiträge
79
Diamanten
300
Minecraft
Blura_
Über TLS gibts leider sehr viel falsches Halbwissen von vermeindlich seriösen Quellen. Einen richtig guten Link, der dir die Grundlagen erklärt, habe ich daher leider nicht. Die Kurzversion ist: TLS ist erstmal nur ein Protokoll um eine verschlüsselte Verbindung auszuhandeln. Da es aber unmöglich ist eine sichere Verbindung zwischen zwei Partnern aufzubauen, ohne vorher IRGENDEIN Geheimnis geteilt zu haben, gibt es CAs. Das sind Certificate Authorities und im Kontext von TLS erstmal einfach nur eine Instanz, welcher beide Parteien vertrauen. Vertrauen bedeutet hier allerdings nur, dass die CA nur solche Zertifikate ausstellt, von welchen sie geprüft hat, dass sie tatsächlich dem entsprechenden Kontaktpartner gehören. In den meisten Fällen ist das einfach die Domain. Eine CA zertifiziert dir also, dass du tatsächlich der Besitzer der Domain bist.

Jeder TLS Client bringt einen Truststore mit (oder nutzt den das Betriebssystems) und wenn du eine TLS Verbindung aufbaust, schickt dir der Kontaktpartner das Zertifikat von einer CA, welches bestätigt, dass er tatsächlich der Inhaber der Domain ist. Wenn ihr beide nun eben dieser CA vertraut, dann könnt ihr darüber eine sichere Verbindung aushandeln. Es gibt also eine übergeordnete Instanz, die beide Parteien kennen und vertrauen. Und über diese Kette von vertrauen, vertrauen wir dann auch allen anderen Instanzen, welcher von dieser Instanz beglaubigt wurden. Das nennt sich "Chain-of-Trust". Was vielen nicht bewusst ist, ist die Tatsache, dass der TLS Server ebenfalls vom Client ein gültiges Zertifikat verlangen kann. Auf diese Weise wissen beide Teilnehmer, mit wem sie "sprechen". Auch wenn eigentlich jeder Webbrowser das kann, wird es nirgendwo genutzt. Stattdessen benutzt man meist Logins mit statischen Passwort.

Das ist eine starke Vereinfachung dessen, was da genau passiert. Ein selbstsigniertes Zertifikat ist ein Zertifikat, welches mit dem eigenen privaten Schlüssel signiert wurde. Das ist das Äquivalent von "Ich bin ich". Das heißt hier gibt es keine Chain of Trust. Du musst halt der Instanz selbst glauben. Du weißt aber nicht, ob es nicht noch eine andere Instanz gibt.

Dein InsecureTrustManager hat genau das getan: Er vertraut einfach jedem. Das ist für Testzwecke okay, ansonsten bietet es aber gegen aktive Angreifer gar keine Sicherheit. Da du in einem geschlossenen System arbeitest, brauchst du keine kommerzielle CA. Du kannst deine eigene CA betreiben. Mit dieser bekommt jeder deiner Netzwerkteilnehmer ein eigenes Zertifikat, welches du mit dieser signierst. Dann packst du das Zertifikat dieser CA in die Truststores deiner Netzwerkteilnehmer und schon können diese sich gegenseitig bestätigen.

Das ist die Highlevel Erklärung, was da genau passiert. Der Teufel steckt halt an ganz vielen Detailfragen und Möglichkeiten, welche dir TLS bietet sowie verschiedene Angriffszenarien vor denen man sich vielleicht ebenfalls schützen möchte. Im Grunde sollte die Aufgabe aber aus folgenden Schritten bestehen:
  1. Eigene Selbstsignierte CA einrichten
  2. Schlüsselpaare für Netzwerkteilnehmer erstellen (das fällt häufig mit dem nächsten Schritt zusammen, ist aber eigentlich unabhängig)
  3. Zertifikate für Schlüsselpare für TLS-Server und TLS-Clients erstellen (optional auch als Client und Server markieren)
  4. Den privaten Schlüssel der CA gut schützen
  5. Auf jeden Netzwerkteilnehmer das Zertifikat der CA packen.
  6. Bis hier hin ist das ganze unabhängig von Java und das allgemeine Vorgehen
  7. Truststore für jeden Client einrichten oder bei Softwarestart konfigurieren. Darin gehört:
    1. Private Key des Teilnehmers
    2. Zugehöriges Zertifikat, signiert von der CA
    3. Das Zertifikat der CA
  8. Das Ganze Geraffel in Nettys SSL Context klopfen
  9. Fertig
Aktuell erzeugst du bei jedem Start ein neues Zertifikat, das ist natürlich nicht möglich. Die Zertifikate werden einmal zentral erstellt und dann verteilt. Wie gesagt: Für eine sichere Verbindung muss man immer vorher irgendeine Art von Information geteilt haben.

Das ist leider nichts, was man in ein paar Tagen fertigstellt, wenn man mit TLS und der Trust of Chain nicht vertraut ist. Ich hab das selbst mit Netty vor vielen Jahren und der 3.x gemacht. Wenn du natürlich die Bereitschaft hast das zu Lernen, ist das natürlich auch ein wertvoller Skill. Leider kann ich keine guten Quellen empfehlen, die das Thema komplett erklären würden. Das sind allerdings auch mehrere kryptografische Verfahren, die in TLS verwendet werden, von daher auch nicht sonderlich verwunderlich.

Wenn dir das zu viel Arbeit ist, könntest du auch andere Optionen ausprobieren. Innerhalb des selben Hosts brauchst du natürlich keine Verschlüsslung und falls du ein VLAN oder ähnliches zwischen deinen Servern aufbauen kannst und deinem Hoster vertraust, brauchst du auch keine Verschlüsslung. Ein VPN wäre eine ähnliche Option, wobei du hier auch wieder Zertifikate erstellen musst und zusätzlich das Netzwerk konfigurieren musst. Wenn dein Hoster seine Hardware richtig konfiguriert hat, kannst du IP Spoofing innerhalb des selben Netzwerkes ebenfalls ausschließen. Mit Docker Swarm Mode oder Kubernetes würdest du die verschlüsselte Verbindung ebenfalls "kostenlos" bekommen, aber dafür hast du einen Haufen weiterer Dinge, die du berücksichtigen müsstest.

Testen kannst du sowas sehr gut mit den eingebauten Funktionen von OpenSSL:
* https://www.openssl.org/docs/man1.0.2/man1/openssl-s_client.html
* https://www.openssl.org/docs/man1.0.2/man1/openssl-s_server.html

Ich habe zwar auf meinem Server eine Firewall installiert, die Verbindungen von außerhalb blockiert und der auch alle Ports (außer die, die gebraucht werden) deaktiviert. Jedoch wollte ich trotzdem eine TLS Verbindung, damit ich das erstens lerne und damit es noch sicherer ist.

Also das mit den Zertifikaten habe ich glaube ich auch verstanden.

Sobald ich das jetzt verstanden habe, sollte ich nicht bei jedem Server start einen Zertifikat erstellen, sondern nur einmal erstellen und dann speichern. Das ist ja eigentlich soweit auch kein Problem, denn da kann ich doch den KeyStore File einfach auf alle Proxys packen und dann kann ich sie einfach beim Server start holen. Hinzu kommt noch das man auf diesen KeyStore nur mit einem Passwort drauf kommen kann. Wäre dieses Vorgehen Ok?

Ansonsten sollte ja auch alles stimmen?? Dann kann ich doch einfach einen selbstsignierten Zertifikat für den Netty-Server und einen für den Client erstellen und sie dann in den KeyStore hineingeben, den ich dann einfach speichere und beim Serverstart nehme. Dann sollte der Server ja wissen, dass er mit dem richtigen Client verbunden ist/kommuniziert und der Client, dass er mit dem richtigen Server verbunden ist/kommuniziert. oder liege ich gerade komplett falsch?
 
Zuletzt bearbeitet:
Oben