Synapse SSL Verbindungen, aber wie ?

Alle Fragen zur Netzwerkkommunikation
Stevie
Beiträge: 200
Registriert: Di 27. Feb 2024, 22:40

Re: Synapse SSL Verbindungen, aber wie ?

Beitrag von Stevie »

... ich habe es mal ausprobiert und insbesondere dann, wenn Du beide Seiten selbst kontrollierst, sollte es bei Größen um die 10MB einfach mit "Bordmitteln" gehen, indem Du deine Datenbank mittels Base64 kodierst und dann per HTTP GET bzw. HTTP PUT liest und schreibst.

Ich habe das mal folgendermaßen ausprobiert:

1. Simulierte Datenbank mit 'dd' erstellt:

Code: Alles auswählen

# dd if=/dev/random of=some.db bs=1024 count=10000
2. Datenbank mittels base64 kodiert und für den späteren Vergleich einen Hash erzeugt:

Code: Alles auswählen

# base64 < some.db > some.db.b64
# openssl sha1 some.db.b64
SHA1(some.db.b64)= 4930eb3f16c7b8308dd9b71e62c095c2fbd2a934
#
3. Folgendes Programm als Server kompiliert. Es stellt am Port 8443 per HTTPS einen kleinen REST-Server bereit, der am Endpunkt '/db' den Inhalt der Datei some.db als Base64-String liefert:

Code: Alles auswählen

program SimpleServer;
{$mode objfpc}{$H+}

uses
  SysUtils, Classes, Base64, FPHttpApp, HTTPRoute, HTTPDefs, OpenSslSockets;

procedure sendDbFile(aRequest: TRequest; aResponse: TResponse);
var
  Filestream           : TFileStream;
  RawBody, EncodedBody : String;
begin
  Filestream := TFileStream.Create('some.db', fmOpenRead or fmShareDenyWrite);
  try
    SetLength(RawBody, Filestream.Size);
    Filestream.Read(RawBody[1], Filestream.Size);
  finally
    Filestream.Free;
  end;

  EncodedBody := EncodeStringBase64(RawBody);

  aResponse.Code := 200;
  aResponse.ContentLength := EncodedBody.Length;
  aResponse.Content := EncodedBody;
  aResponse.SendContent;
end;

begin
  Application.Initialize;
  HTTPRouter.RegisterRoute('/db', @sendDbFile);
  Application.Port := 8443;
  Application.UseSSL := true;
  Writeln('Starte Webserver...');
  Application.Run;
end.
4. Programm Kompiliert und gestartet:

Code: Alles auswählen

# ./simpleserver
Starte Webserver...
5. Endpunkt per 'curl' abgefragt:

Code: Alles auswählen

# curl -ks https://localhost:8443/db -o some.db.received
#
6. Hash der abgefragten Daten für den Vergleich erzeugt:

Code: Alles auswählen

# openssl sha1 some.db.received
SHA1(some.db.received)= 4930eb3f16c7b8308dd9b71e62c095c2fbd2a934
#
Die Hashes sind identisch, die 10MB an Zufallsdaten sind also erfolgreich vom Mini-Server eingelesen, per Base64 enkodiert und per HTTPS an den Client übertragen worden. Ich habe mir aus Platzgründen an dieser Stelle die Gegenseite als Pascal-Programm bzw. ein Beispiel mit einer echten SQLite-Datenbank gespart, aber da würde es ebenso laufen. Und natürlich bräuchstest Du auch noch eine Authentisierungs-/Autorisierungsschicht, damit Dir nicht einfach jeder die Datenbank abzieht, der zufällig an Deinem Server vorbeikommt.

Fazit: Für das, was Du vor hast, brauchst Du vermutlich kein VPN und auch kein Synapse, sondern kannst Du einfach mit dem arbeiten, was Dir FPC und seine Standardbibliotheken bieten können.

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1730
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Synapse SSL Verbindungen, aber wie ?

Beitrag von corpsman »

@Stevle
Sry hat a bissl gedauert, aber nu hab ich mal versucht aus zu probieren was du da geschrieben hast, denn an sich liest sich das mega.

Deinen Anweisungen folgend habe ich den Server in der Anlage erstellt und gestartet.
Der curl Befehl beendet sich immer ohne irgendwas, und in der Console passiert leider nichts :/

Ich glaube dir, dass es bei dir getan hat, was habe ich also in meiner "app" falsch gemacht ?
Dateianhänge
Server.zip
(1.45 KiB) 209-mal heruntergeladen
--
Just try it

Stevie
Beiträge: 200
Registriert: Di 27. Feb 2024, 22:40

Re: Synapse SSL Verbindungen, aber wie ?

Beitrag von Stevie »

... geht bei mir auch mit Deinem Code. Kannst Du mal bitte folgenden Befehl (natürlich ohne Hash) eingeben und die gesamte Bildschirmausgabe posten?

Code: Alles auswählen

# curl -ksv https://localhost:8443/db -o some.db.received

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1730
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Synapse SSL Verbindungen, aber wie ?

Beitrag von corpsman »

corpsman@corpsman:~/Desktop$ curl -ksv https://localhost:8443/db -o some.db.received
* Host localhost:8443 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:8443...
* connect to ::1 port 8443 from ::1 port 41486 failed: Connection refused
* Trying 127.0.0.1:8443...
* Connected to localhost (127.0.0.1) port 8443
* ALPN: curl offers h2,http/1.1
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* Recv failure: Connection reset by peer
* OpenSSL SSL_connect: Connection reset by peer in connection to localhost:8443
* Closing connection
--
Just try it

Stevie
Beiträge: 200
Registriert: Di 27. Feb 2024, 22:40

Re: Synapse SSL Verbindungen, aber wie ?

Beitrag von Stevie »

... auf Deiner Maschine nimmt der Server den Call zwar an, baut aber keine SSL-Verbindung auf.

Ich tippe auf ein Problem beim Handshake, aber um das zu ergründen, benötigen wir ein paar mehr Informationen. Kannst Du etwas genauer sagen, mit was für einer Linux-Variante / Distribution wir es bei Dir zu tun haben?

Was Du auch noch mal machen kannst, ist folgendes:

Code: Alles auswählen

# openssl s_client -connect localhost:8443
Was bekommen wir da für eine Ausgabe?

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1730
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Synapse SSL Verbindungen, aber wie ?

Beitrag von corpsman »

sers, ich hab ein ganz normales Linux Mint Mate
corpsman@corpsman:~$ uname -a
Linux corpsman 6.8.0-90-generic #91-Ubuntu SMP PREEMPT_DYNAMIC Tue Nov 18 14:14:30 UTC 2025 x86_64
x86_64 x86_64 GNU/Linux
corpsman@corpsman:~$ neofetch
OS: Linux Mint 22.2 x86_64
Kernel: 6.8.0-90-generic
Shell: bash 5.2.21
DE: MATE 1.26.1
WM: Metacity (Marco)
Theme: Mint-X-Blue [GTK2/3]
Terminal: mate-terminal
und der andere Befehl hat das hier zur Ausgabe:
corpsman@corpsman:~$ openssl s_client -connect localhost:8443
CONNECTED(00000003)
write:errno=104
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 293 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
--
Just try it

Stevie
Beiträge: 200
Registriert: Di 27. Feb 2024, 22:40

Re: Synapse SSL Verbindungen, aber wie ?

Beitrag von Stevie »

Danke für die Informationen. Wie es aussieht, sendet der Server bei Dir kein selbst signiertes Default-Zertifikat. Ich schaue mir das noch mal bei mir an, da tut er das nämlich.

Weißt Du, wie man ein Zertifikatspaar erstellt? Dann können wir dem Server auch explizit einen Schlüssel und ein Zertifikat "umhängen" und es damit versuchen.

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1730
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Synapse SSL Verbindungen, aber wie ?

Beitrag von corpsman »

Das Zertifikat erstellt man doch so ?
openssl req -x509 -newkey rsa:2048 -nodes \
-keyout server.key \
-out server.crt \
-days 365
--
Just try it

Stevie
Beiträge: 200
Registriert: Di 27. Feb 2024, 22:40

Re: Synapse SSL Verbindungen, aber wie ?

Beitrag von Stevie »

Genau!

Und dieses Pärchen referenzierst Du nun in Deinem Server:

Code: Alles auswählen

  ...
  Application.UseSSL := true;
  Application.CertificateData.Certificate.FileName := 'server.crt';
  Application.CertificateData.PrivateKey.FileName := 'server.key';
  Writeln('Starte Webserver...');
  ...
  
Einmal kompilieren und starten. Was sagt danach 'openssl s_client' ?

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1730
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Synapse SSL Verbindungen, aber wie ?

Beitrag von corpsman »

ui ui ui, nu hat er was gesendet ;).

Nu muss ich es nur noch hin bekommen, eine DB an den Server zu senden, mich ordentlich zu authentifizieren und verstehen was dein Code gemacht hat ;)
--
Just try it

Stevie
Beiträge: 200
Registriert: Di 27. Feb 2024, 22:40

Re: Synapse SSL Verbindungen, aber wie ?

Beitrag von Stevie »

Toppi! :)

Die nächsten Schritte hängen natürlich sehr stark von Deiner Anwendungsarchitektur ab, aber Authentisierung & Autorisierung sind auf jeden Fall superwichtig, sofern Dein Server wirklich am Internet hängen soll.

Sofern Du Deinen Server auf HTTPS beschränkst, ist es dabei wohl am einfachsten, auf Basic Authentication zu setzen. Dabei sendet der Client einen speziellen Authorization Header, in dem Benutzername und Passwort im Klartext (!) per Base64 enkodiert übermittelt werden. Der Server kann den dann aus dem Request ziehen und zur Zugriffsentscheidung verwenden.

Der Client sendet das folgendermaßen:

Code: Alles auswählen

# curl -u gru:t0psecr3t -ksv https://localhost:8443/db -o some.db.received
* Host localhost:8443 was resolved.
...
* using HTTP/1.x
* Server auth using Basic with user 'gru'
> GET /db HTTP/1.1
> Host: localhost:8443
> Authorization: Basic Z3J1OnQwcHNlY3IzdA==
> User-Agent: curl/8.7.1
> Accept: */*
>
* Request completely sent off
...
Der Server kann das dann ganz einfach im Endpunkt verwenden. Ich habe hier mal ein SUPER SIMPLES Beispiel, wie so eine Prüfung aussehen kann. Das ist kein Produktions-Code, aber so ungefähr kann man vorgehen.

Code: Alles auswählen

Program server;

{$MODE objfpc}{$H+}

Uses
  SysUtils, Classes, Base64, FPHttpApp, HTTPRoute, HTTPDefs, OpenSslSockets,
  StrUtils, Types,

Procedure sendDbFile(aRequest: TRequest; aResponse: TResponse);
Var
  Filestream             : TFileStream;
  RawBody, EncodedBody,
  DecodedHeader,
  Username, Password     : String;
  StringArray            : TStringDynArray;

Begin
  //---
  // Simpler Auth Check...
  //---
  StringArray   := SplitString(aRequest.Authorization, ' ');
  DecodedHeader := DecodeStringBase64(StringArray[1]);
  StringArray   := SplitString(DecodedHeader, ':');
  Username      := StringArray[0];
  Password      := StringArray[1];

  if Not ((Username = 'gru') and (Password = 't0ps3cret')) then
  begin
    aResponse.code := 401;
    aResponse.SendContent;
    exit;
  end;
  //---

  If FileExists('db.db') Then Begin
    writeln('Found db, sending..');
  ...
Besser ist es dann natürlich, mit so etwas wie JWT oder OAuth2 zu arbeiten, aber das sprengt hier den Rahmen...

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1730
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Synapse SSL Verbindungen, aber wie ?

Beitrag von corpsman »

OK bevor ich mich verrenne hier mal ein paar gedanken ..

Der Server erlaubt es mir nun verschlüsselt zu kommunizieren, der HTML Header bleibt aber im Klartext.

Was ist wenn ich eine Art Cookie Authentifizierung mache ?

Also der server lehnt alles ab, was nicht ein "gültiges" Cookie im Header mit sendet, das Cookie selbst ist ein 2k Random Block, den der Server vorher nach Authentifizierung erstellt und übermittelt hat.

Zum Authentifizieren macht der Client ne Get Abfrage auf /getRndBytes und verschlüsselt diese mit seinem User und PW und sendet diese dann an /authentificateRnd, wenn alles gut ist sendet der Server das oben beschriebene Cookie welches dann 10 mins gültig ist, wenn nichts fehler.

Damit muss ich keine PW's im Klartext via Header senden, und kann alles raus werfen was sich nicht authentifizieren konnte.


Das ganze bedingt natürlich, dass ich raus kriege wie man auch daten an den Server sendet ;)
--
Just try it

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1730
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Synapse SSL Verbindungen, aber wie ?

Beitrag von corpsman »

Hmm, also ich habe beim Server nun folgendes hinzugefügt:

Code: Alles auswählen


Procedure Send42(aRequest: TRequest; aResponse: TResponse);
Begin
  writeln('Send 42');
  aResponse.code := 200;
  aResponse.ContentLength := 2;
  aResponse.Content := '42';
  aResponse.SendContent;
End;
          
..

  HTTPRouter.RegisterRoute('/42', @send42); 
  
Und versuche nun Programatisch diese 42 von der Gegenstelle zu lesen:

Code: Alles auswählen


Procedure TForm1.Button1Click(Sender: TObject);
Var
  h: THTTPSend;
Begin
  Memo1.Clear;
  h := THTTPSend.Create;
  h.HTTPMethod('GET', 'https://localhost:8443/42');
  memo1.Append(format('Resultcode: %d', [h.ResultCode]));
  h.free;
End;   
Dann bekomme ich als antwort leider eine 500 und mein Eventhandler wird gar nicht erst aufgerufen :/. Da habe ich wohl noch was falsch verstanden ..

[Edit]

Code: Alles auswählen

Procedure TForm1.Button1Click(Sender: TObject);
Var
  h: THTTPSend;
Begin
  Memo1.Clear;
  h := THTTPSend.Create;
  If h.HTTPMethod('GET', 'https://localhost:8443/42') Then Begin
    memo1.Append('Succeed.');
    memo1.Append(inttostr(h.Document.Size));
  End
  Else Begin
    memo1.Append('HTTP.ResultCode: ' + inttostr(h.ResultCode) + ' ; ' + h.ResultString);
    memo1.Append('HTTP.Sock.LastError: ' + inttostr(h.Sock.LastError) + ' ; ' + h.Sock.LastErrorDesc);
    memo1.Append('HTTP.Sock.SSL.LastError: ' + inttostr(h.Sock.SSL.LastError) + ' ; ' + h.Sock.SSL.LastErrorDesc);
  End;
  h.free;
End; 
Hat eine Verbesserung gebracht und gezeigt dass ich vergessen hatte die Unit ssl_Openssl ein zu binden ;)
--
Just try it

Stevie
Beiträge: 200
Registriert: Di 27. Feb 2024, 22:40

Re: Synapse SSL Verbindungen, aber wie ?

Beitrag von Stevie »

Bist Du sicher, dass Dein Client die SSL-Library findet und nutzt?

Ich habe hier mal einen CLI-Client zum Ausprobieren:

Code: Alles auswählen

{$mode objfpc}{$H+}
uses base64, fphttpclient, opensslsockets;

Var
  Result, Username, Password, AuthHeader : String;

begin
  Username := 'gru';
  Password := 't0ps3cret';
  AuthHeader := 'Basic ' + EncodeStringBase64(Username + ':' + Password);

  with TFPHttpClient.Create(Nil) do
    try
      AddHeader('Authorization', AuthHeader);
      Result := Get('https://localhost:8443/db');
    finally
      Free;
    end;
  Writeln('Content: ', Result);
end.

[Edit] Da haben sich unsere Posts überschnitten... [/Edit]

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1730
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Synapse SSL Verbindungen, aber wie ?

Beitrag von corpsman »

Also ich bin ja nun schon ein ganz schönes Stückchen gekommen, aber nun brauche ich noch mal deine Hilfe.

Auf der Client Seite habe ich nun auch den TFPHttpClient genommen, dann passt das irgendwie zusammen ;)

Gerade versuche ich den Login zu schreiben, hier der Client Code, der aktuell Letzte Schritt sendet die Challenge responce an der Server

Code: Alles auswählen

Function Login(URL, UserName, Password: String): Boolean;
Var
{$IFDEF Debug}
  i: integer;
  b: Byte;
{$ENDIF}
  rndString, AuthHeader, Challengeres: String;
  m, unEncryptedSeed, EncryptedSeed: TMemoryStream;
  EncrytpStream: TDCP_rijndael;
Begin
  result := false;
  Logout;
  client := TFPHttpClient.Create(Nil);
  // 1. Anfrage des 2K Random
  AuthHeader := 'Basic ' + EncodeStringBase64(Username);
  client.AddHeader('Authorization', AuthHeader);
  rndString := client.Get(URL + '/challenge');
  rndString := DecodeStringBase64(rndString);
  unEncryptedSeed := TMemoryStream.Create;
  unEncryptedSeed.Write(rndString[1], length(rndString));
{$IFDEF Debug}
  writeln('Got challenge:');
  unEncryptedSeed.Position := 0;
  b := 0;
  For i := 0 To unEncryptedSeed.Size - 1 Do Begin
    unEncryptedSeed.read(b, sizeof(b));
    write(format(' %0.2X', [b]));
  End;
  writeln('');
{$ENDIF}
  unEncryptedSeed.Position := 0;
  // 2. Verschlüsseln des Random mit eigenem PW
  EncryptedSeed := TMemoryStream.Create;
  EncrytpStream := TDCP_rijndael.Create(Nil);
  EncrytpStream.InitStr(Password, TDCP_sha256);
  EncrytpStream.CipherMode := cmCBC; // Cipher-Block Chaining (CBC)
  EncrytpStream.EncryptStream(unEncryptedSeed, EncryptedSeed, unEncryptedSeed.Size);
  EncrytpStream.free;
  unEncryptedSeed.free;
  // 3. Senden Verschlüsseltes Random an Server
  setlength(rndString, EncryptedSeed.Size);
  EncryptedSeed.Read(rndString[1], EncryptedSeed.Size);
{$IFDEF Debug}
  writeln('Send challenge responce:');
  EncryptedSeed.Position := 0;
  b := 0;
  For i := 0 To EncryptedSeed.Size - 1 Do Begin
    EncryptedSeed.read(b, sizeof(b));
    write(format(' %0.2X', [b]));
  End;
  writeln('');
{$ENDIF}
  EncryptedSeed.free;
  rndString := EncodeStringBase64(rndString);
  m := TMemoryStream.Create;
  m.Read(rndString[1], length(rndString));
  m.Position := 0;
  Client.RequestBody := m; // -- Hier wird die Responce an den Post mit angehängt, sollte also gehen ...
  Challengeres := Client.Post(url + '/challengeresult');
  m.free;
  // 3.1 Antwort Akzeptiert
  // 3.2 Antwort nicht Akzeptiert, nichts zu tun
End;
Auf der Server Seite wird auch der dafür Passende Event Handler aufgerufen:

Code: Alles auswählen

Procedure SendchallengeResult(aRequest: TRequest; aResponse: TResponse);
Var
  StringArray: TStringDynArray;
  ChallengeString, Username: String;
  i: Integer;
Begin
  StringArray := SplitString(aRequest.Authorization, ' ');
  Username := DecodeStringBase64(StringArray[1]);
  writeln('Got a challenge responce from user: ' + Username);
  ChallengeString := DecodeStringBase64(aRequest.Content); // -- Das ist aber leider leer :/
{$IFDEF Debug}
  For i := 1 To length(ChallengeString) Do Begin
    write(format(' %0.2X', [ord(ChallengeString[i])]));
  End;
  writeln('');
{$ENDIF}
End;  
Das Problem ist nun aber, dass der ChallengeString leer ist :(. Nun weiß ich nicht sendet der das erst gar nicht oder muss man beim Empfangen noch was machen ?

[Edit]

Code: Alles auswählen

  m.Read(rndString[1], length(rndString)); // -- ist falsch, das muss write sein ..
--
Just try it

Antworten