Archiv der Kategorie: DevOps Tutorials

Tutorials for DevOps & Scripting Deploying and Technical contribution for Professionals

SSL/TLS Verbindung Testen mit OpenSSL

HTTPS und IMAPS-Verbindung Testen und Analysieren

Verbindung Testen mit OpenSSL

OpenSSL kann vielseitig eingesetzt werden, so können nicht nur Schlüssel und Zertifikate für SSL/TLS Verschlüsselte Verbindungen generiert werden, auch sind deren Analysen und Tests möglich.

Dieser Beitrag zeigt die Anwendung von OpenSSL zur überprüfung und Analyse, beim Zugriff mit HTTPS auf Webserver über TCP Port 443, und STARTTLS über TCP 587, oder IMAPS TCP 993 zu Mailserver, dazu OpenSSL auf dem Computer benötigt wird.

Bei SSLLabs können SSL/TLS Server Tests durchgeführt werden, es wird der Verbindungsaufbau mit vielen verschiedenen Browsern durchgeführt und angezeigt, und welche Verschlüsselung erreicht wurde. So wird in der Auswertung ersichtlich, welche Verschlüsselungsverfahren und Schlüsselaustauschverfahren eingesetzt wurden.

HTTPS-Verbindung Testen mit OpenSSL

Sollen nur einzelne und individuelle Tests durchgeführt werden, zeigen dies die folgenden Beispiele. Es wird eine verschlüsselte Verbindung zu unblog.ch aufgebaut und anschließend die Webseite abgerufen.

$ openssl s_client -connect unblog.ch:443 -showcerts

In einer Situation bei dieser anstelle des Standard Port 443 für HTTPS ein alternativer Port genutzt wird, beispielsweise 4443, ist die Anwendung dieselbe, mit :4443 wird die Portnummer angegeben.

Möchte man das Public Zertifikat einer Webseite im RAW Text abrufen, kann durch folgende Kommandozeile das Zertifikat ausgegeben werden.

$ openssl s_client -connect think.unblog.ch:443 -showcerts | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'

Dieser Befehl wird in einem Linux Terminal, in macOS Terminal, in Git Bash, oder in einer WSL Session ausgeführt, die Ausgabe zwischen:
von —–BEGIN CERTIFICATE—–
bis —–END CERTIFICATE—–

-----BEGIN CERTIFICATE-----
MIIFajCCBFKgAwIBAgISAwYFPWKaEox8MgKHV5yqROeWMA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDA3MTcwMzAyMTZaFw0y
...
-----END CERTIFICATE-----

Mit Copy Paste in Notepad im PEM/CER Format (.cer) speichern.

Mit doppelklick auf das so gespeicherte öffentliche Zertifikat, öffnet sich dieses und zeigt sich unter Windows wie folgt.

Verbindung Testen mit OpenSSL

SMTPS STARTTLS Testen mit OpenSSL

Mit OpenSSL kann ermittelt werden, ob ein Mailserver (MTA) Verschlüsselte STARTTLS Verbindungen anbietet, mit folgender Kommandozeile.

$ openssl s_client -connect smtp-gw-246.server.com:587 -starttls smtp

Die Abfrage zeigt uns das öffentliche Zertifikat an, danach die Verschlüsselungsstärke, den Algorithmus (SHA256), die TLS Version (TLSv1.2), und Cipher (ECDHE-RSA-AES256-GCM-SHA384) und weitere Status Informationen.

subject=CN = smtp-gw-246.server.com

issuer=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3

---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 3441 bytes and written 480 bytes
Verification: OK
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
    Session-ID: E1528C64C3CC7A9B28C4E1C2EA33EA0BEF1BACB6602B066351A49C705E192EB5
    Session-ID-ctx:
    Master-Key: 573AB776B9954B51B7FE4908171752874EFCC3DE5F35ECC42AA5F04E48B736290DECC948DE252AD61188B5A94A8BAE9A
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 7200 (seconds)
    TLS session ticket:
    0000 - 0b 99 b3 3a 91 90 66 a8-86 8d 0e 41 8a 90 61 9e   ...:..f....A..a.

IMAPS Verbindung Analysieren

IMAPs mit OpenSSL in der Kommandozeile Analysieren, mit dieser Kommandozeile lässt sich eine IMAPS (SSL/TLS) Verbindung über TCP Port 993 überprüfen.

$ openssl s_client -crlf -connect imap.gmail.com:993

Der Output dann wie hier mit CONNECT zu imap.gmail.com über den SSL Port 993 in etwa wie folgt in verkürzter Form.

CONNECTED(00000174)
depth=1 C = US, O = Google Trust Services, CN = GTS CA 1O1
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 C = US, ST = California, L = Mountain View, O = Google LLC, CN = imap.gmail.com
verify return:1
---
Certificate chain
 0 s:C = US, ST = California, L = Mountain View, O = Google LLC, CN = imap.gmail.com
   i:C = US, O = Google Trust Services, CN = GTS CA 1O1
 1 s:C = US, O = Google Trust Services, CN = GTS CA 1O1
   i:OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIExjCCA66gAwIBAgIQN1SnMAZHJA0IAAAAAFMdITANBgkqhkiG9w0BAQsFADBC
MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZpY2VzMRMw
...
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID: 6074E0D401DD1E1DD5608CBC6F7CA4A2779A9AB4A9313732996D6C4DBD84BC68
    Session-ID-ctx:
    Resumption PSK:
...
read R BLOCK
* OK Gimap ready for requests from 12.34.56.78 t22mb67814ed
Q
DONE

Möchte man hier weitergehen, kann man versuchen sich am IMAP Server zu authentifizieren und nach neuen Mails abfragen.

A NO [ALERT] Application-specific password required: https://support.google.com/accounts/answer/185833 (Failure)

Gmail Antwortet nun mit A NO [ALERT], die Sicherheitseinstellungen zur Authentifizierung erfordert ein Application Passwort, da die Multi-Faktor-Authentifizierung (MFA) aktiviert ist.

* OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE LITERAL+ AUTH=PLAIN AUTH=LOGIN] Dovecot (Debian) ready.

Es folgt ein * OK mit der Ausgabe der verfügbaren Funktionalitäten (CAPABILITY), der IMAP Prompt wartet nun auf Eingaben.

Bei unserem Dovecot IMAP Server können wir uns anmelden.

A login imap-user passwort

Der Login besteht normalerweise aus der Email Adresse (imap-user) und einem Passwort.

Nach erfolgreichem Login erscheint die Ausgabe ähnlich wie diese.

A OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE SNIPPET=FUZZY LITERAL+ NOTIFY SPECIAL-USE QUOTA] Logged in

Jetzt welchseln zum IMAP Posteingang (INBOX).

A select INBOX

Der Output von select INBOX in etwa wie folgt.

* FLAGS (\Answered \Flagged \Deleted \Seen \Draft $Forwarded)
* OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft $Forwarded \*)] Flags permitted.
* 3 EXISTS
* 0 RECENT
* OK [UNSEEN 3] First unseen.
* OK [UIDVALIDITY 1590737718] UIDs valid
* OK [UIDNEXT 12197] Predicted next UID
* OK [HIGHESTMODSEQ 39953] Highest
A OK [READ-WRITE] Select completed (0.001 + 0.000 secs).

Es sind wie zu sehen 3 ungelesene Mails in der INBOX, von der ersten Mail öffnen wir den Header (beginnt mit . Punkt).

. fetch 1 rfc822.header

Der Output von . fetch 1 rfc822.header (die ersten 6 Zeilen).

* 1 FETCH (RFC822.HEADER {3338}
Return-Path: 
Delivered-To: maxmuster@server.com
Received: from mail.server.com
        by mail.server.com with LMTP
        id sbn9BAzYQF9sJBACykIyCA
        (envelope-from )
..
. OK Fetch completed (0.001 + 0.000 secs).

Die erste ungelesene Mail öffnet sich mit . fetch 1 rfc822.text

. fetch 1 rfc822.text

Output von . fetch 1 dann in etwa wie hier bei meiner Mail.

* 1 FETCH (RFC822.TEXT {596297}

--Apple-Mail-3B8B8770-2CCE-4083-B331-2E1EDAF97C84
Content-Type: text/plain;
        charset=us-ascii
Content-Transfer-Encoding: 7bit

Guten Tag.

Anbei das PDF in der Anlage.

Freundliche Grüsse

--Apple-Mail-3B8C8770-2CCE-4083-B331-2E2EDBF97C94
Content-Type: application/pdf;
        name="Doc-21.08.2020-10-36.pdf";
        x-apple-part-url=CCDB9E0F-432F-2719-AE44-000259172822
Content-Disposition: inline;
        filename="Doc-21.08.2020-10-36.pdf"
Content-Transfer-Encoding: base64

JVBERi0jLjMKJbe+7aoKMSAwIG9iago8PA0vVHlwZSAvQ2F0YWxvZwozUGFnZXMgMiAwIFIKPj4K
ZW5kc2JqCjIgMCBvYmoKPDwKL1R5cGUgL1BhZ2VzCi9LaWRzIFsgNCFxIFIgXQovQ291bnQgMQo+
...
. OK Fetch completed (0.003 + 0.034 secs).

Es handelt sich hier also um eine Mail mit PDF Anlage, diese base64 kodiert ist.

Mit Eingabe Q wird die Verschlüsselte IMAP Session beendet.

Python Loops mit Break- Continue- Pass

for- und while-Loops auf effiziente Weise für zyklische und automatisierte Aufgaben nutzen

 
Synopsis

Manchmal bestimmen externe Faktoren wie Schleifen in einem Programm durchlaufen werden. Wenn dies eintrifft, möchte man möglicherweise dass die Schleife in einer Routine vollständig beendet wird, oder einen Teil der Schleife überspringt, bevor sie fortfährt, oder es soll ein externer Faktor ignorieren werden. Diese Aktionen können mit der Anweisung breakcontinue und pass durchgeführt werden.

Anweisung break

In Python bietet die break Anweisung die Möglichkeit, eine Schleife zu verlassen, wenn eine externe Bedingung ausgelöst wird. Hierzu setzen wir die break Anweisung in den Codeblock unterhalb der Schleife, normalerweise nach einer bedingten if-Anweisung.

Schauen wir uns ein Beispiel an, das die break Anweisung in einer for-Schleife anwendet:

zahl = 0

for zahl in range(10):
   zahl = zahl + 1

   if zahl == 5:
      break    # break here

   print('Zahl ist ' + str(zahl))

print('loop ende')

In diesem kleinen Programm wird die Variable zahl auf 0 initialisiert. Dann wird eine for-Anweisung in die Schleife gelegt, diese durchläuft solange die Variable zahl kleiner als 10 ist.

Innerhalb der for-Schleife erhöht sich die Zahl bei jedem Durchlauf bedingt um inkrementell 1 zahl = zahl + 1.

Dann bei der if-Anweisung die den Zustand zeigt, wenn die Variable zahl der ganzen Zahl 5 entspricht, wird die Schleife abgebrochen.

Innerhalb der Schleife befindet sich auch eine print() Anweisung, die bei jeder Iteration der for-Schleife ausgeführt wird, bis die Schleife bei der break Anweisung abbricht.

Um zu sehen, wann wir außerhalb der Schleife sind, haben wir eine abschließende print() Ausgabe außerhalb der for-Schleife eingefügt.

Wenn wir diesen Code ausführen, erscheint unsere Ausgabe wie folgt:

Zahl ist 1
Zahl ist 2
Zahl ist 3
Zahl ist 4
loop ende

Es zeigt sich, sobald die Ganzzahl zahl als äquivalent zu 5 bewertet wurde, die Schleife abbricht, da das Programm dies durch die break-Anweisung tun soll.

Die break-Anweisung bewirkt also, dass ein Programm aus einer Schleife ausbricht.

Anweisung continue

Die continue-Anweisung gibt uns die Möglichkeit, den Teil einer Schleife zu überspringen, in diesem eine externe Bedingung ausgelöst wird, aber bis zum Rest der Schleife beendet wird. Das heißt, die aktuelle Iteration der Schleife wird unterbrochen, aber das Programm kehrt zum Anfang der Schleife zurück.

Die continue-Anweisung befindet sich innerhalb des Codeblocks unter der Schleifenanweisung, normalerweise nach einer bedingten if-Anweisung.

Wenn wir das selbe in einem for-Loop wie oben mit der Break-Anweisung anwenden, verwenden wir einfach eine continue-Anweisung anstelle der break-Anweisung:

zahl = 0

for zahl in range(10):
   zahl = zahl + 1

   if zahl == 5:
      continue    # continue here

   print('Zahl ist ' + str(zahl))

print('loop ende')

Der Unterschied bei der Verwendung der continue-Anweisung anstelle einer break-Anweisung besteht darin, dass unser Code trotz der Störung weiter durchläuft, wenn die Variable zahl gleich 5 bewertet wird. Schauen wir uns unsere Ausgabe an:

Zahl ist 1
Zahl ist 2
Zahl ist 3
Zahl ist 4
Zahl ist 6
Zahl ist 7
Zahl ist 8
Zahl ist 9
Zahl ist 10
loop ende

Hier sehen wir, dass die Linie „Zahl ist 5“ nie in der Ausgabe erscheint, aber die Schleife fährt nach diesem Punkt fort, und die Zahlen 6-10 werden ausgegeben, bevor die Schleife verlassen wird.

Mit der continue-Anweisung können in tief verschachtelten Code Fehler vermeiden werden, auch könne hierdurch Loops optimiert werden, indem man häufig auftretende Fälle, die man ablehnen möchten, eliminiert.

Die continue-Anweisung bewirkt, dass ein Programm bestimmte Faktoren überspringt, die innerhalb einer Schleife auftreten, und dann den Rest der Schleife fortsetzt.

Anweisung pass

Wenn eine externe Bedingung ausgelöst wird, kann mit der pass-Anweisung die Bedingung verarbeitet werden, ohne dass die Schleife in irgendeiner Weise beeinträchtigt wird. Der gesamte Code wird weiterhin gelesen, sofern keine break oder eine andere Anweisung auftritt.

Wie bei den anderen Anweisungen befindet sich die pass-Anweisung innerhalb des Codeblocks unter der Schleifenanweisung, normalerweise nach einer bedingten if-Anweisung.

Verwenden wir den gleichen Codeblock wie oben, ersetzen jedoch die Anweisung break oder continue durch eine pass-Anweisung:

zahl = 0

for zahl in range(10):
   zahl = zahl + 1

   if zahl == 5:
      pass    # pass here

   print('Zahl ist ' + str(zahl))

print('loop ende')

Die pass-Anweisung, die nach der if-bedingten Anweisung auftritt, teilt dem Programm mit, die Schleife weiterhin auszuführen und ignoriert die Tatsache, dass die Variable zahl während einer ihrer Iterationen als äquivalent zu 5 bewertet wird.

Wir werden das Programm ausführen und uns die Ausgabe ansehen:

Zahl ist 1
Zahl ist 2
Zahl ist 3
Zahl ist 4
Zahl ist 5
Zahl ist 6
Zahl ist 7
Zahl ist 8
Zahl ist 9
Zahl ist 10
loop ende

Bei Verwendung der pass-Anweisung in diesem Programm stellen wir fest, dass das Programm genauso ausgeführt wird, als wenn es keine bedingte Anweisung im Programm gäbe. Die pass-Anweisung weist das Programm an, diese Bedingung zu ignorieren und das Programm wie gewohnt weiter auszuführen.

Die pass-Anweisung kann minimale Klassen erstellen oder als Platzhalter fungieren, wenn an neuem Code gearbeitet wird und auf einer algorithmischen Ebene gedacht wird, bevor Details herausgearbeitet werden.

Fazit

Durch die break, continue und pass-Aussagen in Python ermöglicht es uns, for– und while-Loops im Code effektiver anwenden zu können.