Configurazione SSL per Apache

Spread the love

Piccolo tutorial su come configurare un accesso cifrato con SSL per un sito web. Sia myserver il nome sia dell’host che del dominio: ovviamente in questo tutorial non utilizzeremo il DNS, stiamo solo facendo esperimenti in rete locale per cui basta specificare il nome dell’host.

csfr hacking technique ssl
SSL

Ingredienti

  • una chiave privata
  • una richiesta di certificato
  • un certificato SSL
  • un virtualhost Apache
  • molta pazienza

Chiave SSL

Utilizzando OpenSSL generiamo una chiave privata RSA. Dalla directory in cui si desidera salvare la chiave privata (tipicamente /etc/ssl/private/) si esegue il seguente comando:

$ sudo openssl genrsa -out myserver.key 2048

Richiesta di firma

Utilizzando la chiave privata appena generata, creiamo una richiesta di firma del certificato (CSR).

Importante: Assicuriamoci di inserire correttamente il nome del dominio locale quando richiesto.

Muoviamoci adesso in un directory standard che contiene tutti i certificati SSL: /etc/ssl/certs/

Il comando è il seguente:

$ sudo openssl req -new -key /etc/ssl/private/myserver.key -out myserver.csr

Generazione del certificato

Desiderando creare un certificato autofirmato per soli scopi di sviluppo locale o di sollazzo, si può auto-firmare il CSR utilizzando il comando:

$ sudo openssl x509 -req -days 365 -in myserver.csr -signkey /etc/ssl/private/myserver.key -out myserver.crt

Configurazione del virtualhost Apache

Configuriamo ora Apache per utilizzare il certificato SSL per il sito “myserver”.

Apriamo il file di configurazione di Apache (apache2.conf, lavorando con una distribuzine Ubuntu) , o un file specifico per il sito: io per esempio ho un file in cui configuro tutti i virtualhost per le mie applicazioni Laravel che si chiama laravel.conf) e aggiungiamo il seguente blocco di configurazione:

<VirtualHost *:443>
    ServerName myserver
    DocumentRoot /var/www/myserver

    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/js.crt
    SSLCertificateKeyFile /etc/ssl/private/js.key

    # Opzionale: Specifica il file di catena dei certificati (CA bundle) se necessario
    # SSLCertificateChainFile /percorso/verso/ca-bundle.crt

    # Altri settaggi del virtual host...
    ErrorLog ${APACHE_LOG_DIR}/error_ssl.log
    CustomLog ${APACHE_LOG_DIR}/access_ssl.log combined
</VirtualHost>

Abbiamo configurato anche i file di log che conterranno accessi ed errori al virtual host https://myserver.

Non abbiamo invece specificato alcuna catena di autorità (CA bundle) proprio perché è un certificato autofirmato che non fa riferimento ad alcuna Autorità di certificazione standard.

Non resta che (ri)avviare Apache:

$ sudo apache2ctl restart
$ sudo systemctl status apache2
● apache2.service - The Apache HTTP Server
     Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2024-04-15 10:34:26 CEST; 29min ago
       Docs: https://httpd.apache.org/docs/2.4/
    Process: 45590 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS)
   Main PID: 45593 (/usr/sbin/apach)
      Tasks: 9 (limit: 9309)
     Memory: 48.0M
        CPU: 511ms
     CGroup: /system.slice/apache2.service
             ├─45593 /usr/sbin/apache2 -k start
             ├─45594 /usr/sbin/apache2 -k start
             ├─45595 /usr/sbin/apache2 -k start
             ├─45596 /usr/sbin/apache2 -k start
             ├─45597 /usr/sbin/apache2 -k start
             ├─45598 /usr/sbin/apache2 -k start
             ├─45599 /usr/sbin/apache2 -k start
             ├─45600 /usr/sbin/apache2 -k start
             └─45996 /usr/sbin/apache2 -k start

apr 15 10:34:26 jsbach systemd[1]: Starting The Apache HTTP Server...
apr 15 10:34:26 jsbach systemd[1]: Started The Apache HTTP Server.

Conflitto con altri Virtualhost

Se una stessa porta è utilizzata da altri virtualhost il sistema non funzionerà. Capire che è questo il problema può comportare un po’ di tempo.

I sintomi per questo tipo di errata configurazione sono parecchi:

  • Il browser lamenta genericamente un ERR_SSL_PROTOCOL_ERROR
  • Client e server abilitati antrambi a versioni di TLS compatibili
  • Porta crittografica non correttemente impostatata
  • analizzando il traffico anche con Wireshark si nota che non si ha nessun Server Hello in conseguenza al Client Hello e la risposta del server contiene un errore 400 Bad Request

Un controllo fatto con openssl da qualche informazione:

40F7C74FFA7F0000:error:0A00010B:SSL routines:ssl3_get_record:wrong version number:../ssl/record/ssl3_record.c:354:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 5 bytes and written 316 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)
---

Per sistemare queste cose ho impostato:

  • Nella configurazione del Virtualhost bisogna scegliere porte diverse per Virtualhost diversi: replicare una stessa porta per virtualhost diversi porta a errori.
  • Scegliere porte che non siano già utilizzate da altri software oltre Apache (ad esempio nel mio muletto Netxgen si è già occupato la porta 8443)
  • Nella configurazione generale di Apache vanno aggiunte tutte le porte che si vuole ascolti; per fare questo editare il file ports.conf:
<IfModule ssl_module>
        Listen 443
        Listen 9443 <--- ho aggiunto questa
</IfModule>
  • Nel file di configurazione del virtualhost scegliere la porta scelta per ports.conf
<VirtualHost *:9443>
  • In questo stesso blocco abilitare le versioni di TLS supporate da Apache che verranno comunicate al clinet:
        SSLEngine on
        SSLCertificateFile /etc/ssl/certs/myserver.crt
        SSLCertificateKeyFile /etc/ssl/private/myserver.key
        SSLProtocol -all +TLSv1.2 +TLSv1.3 <------ aggiunto

Chiaramente i percorsi dei certificati devono essere corretti e con i permessi corretti:

$ sudo ls -l /etc/ssl/certs/myserver.crt
-rw-r--r-- 1 root root 1334 mag 14 19:00 /etc/ssl/certs/myserver.crt
$ sudo ls -l /etc/ssl/private/myserver.key
-rw------- 1 www-data root 1704 mag 14 18:59 /etc/ssl/private/myserver.key

Nota l’abilitazione a RW della chiave privata al solo utente www-data.

Si può fare un controllo del funzionamento con il client s_client di openssl che stavolta da una risposta molto più prolissa di prima:

$ openssl s_client -connect mytech.local:9443
CONNECTED(00000003)
depth=0 C = IT, ST = ITALY, L = VENICE, O = MYTECH, OU = R&D, CN = mytech.local
verify error:num=18:self-signed certificate
verify return:1
depth=0 C = IT, ST = ITALY, L = VENICE, O = MYTECH, OU = R&D, CN = mytech.local
verify return:1
---
Certificate chain
0 s:C = IT, ST = ITALY, L = VENICE, O = MYTECH, OU = R&D, CN = mytech.local
i:C = IT, ST = ITALY, L = VENICE, O = MYTECH, OU = R&D, CN = mytech.local
a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
v:NotBefore: May 14 17:00:17 2024 GMT; NotAfter: May 14 17:00:17 2025 GMT
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIDqzCCApOgAwIBAgIUPutXcLp1H8o4J5qtNEWJSB7pwoEwDQYJKoZIhvcNAQEL
BQAwZTELMAkGA1UEBhMCSVQxDjAMBgNVBAgMBUlUQUxZMQ8wDQYDVQQHDAZWRU5J
Q0UxDjAMBgNVBAoMBUNBTU9OMQwwCgYDVQQLDANSJkQxFzAVBgNVBAMMDnlhY2F0
ZWNoLmxvY2FsMB4XDTI0MDUxNDE3MDAxN1oXDTI1MDUxNDE3MDAxN1owZTELMAkG
A1UEBhMCSVQxDjAMBgNVBAgMBUlUQUxZMQ8wDQYDVQQHDAZWRU5JQ0UxDjAMBgNV
BAoMBUNBTU9OMQwwCgYDVQQLDANSJkQxFzAVBgNVBAMMDnlhY2F0ZWNoLmxvY2Fs
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArzga2ElQ5Se/E1OKDODE
t2bLF707kjFqYTc5m4LXu1zPmXF/VZTbE80QN9/oB5OVOlYeRlE/hsjGuOTIYaI4
IWa4FvWgb1QGw5aHn4rKZ7Nm/QgG2yRagNoGQIgDE6S/G+WOrhNr9m3dgme0C+7j
uB2sYsBkCGgeqpEiTEKMSMTspElNeE8emCcTzKgnTQJkA6jpp65SKkuw6HBUC4x+
6x0prAzlUJeMLvuKlsT8MtLpj35kNWxsHxfwzhKKv0H7Wj8+kGTc8QYepFnHbpmc
qlRPNqcrXMLiYMUgkNr/aeXUIeDqpJSa1q2vbnXO1d+ToIYgt8uTpXz/yDqiVlfC
6wIDAQABo1MwUTAdBgNVHQ4EFgQUFIRqn2kn2o0KPCoM9qgITYHijiowHwYDVR0j
BBgwFoAUFIRqn2kn2o0KPCoM9qgITYHijiowDwYDVR0TAQH/BAUwAwEB/zANBgkq
hkiG9w0BAQsFAAOCAQEAJFIP8OnTFTHpFGdD6KKEmQbvidiNhDmimSqXCde6nK3B
q1R9wGdWu+zP+0ER7YmozTYJZmvUeYApArJM3Y42SLNj9RBP1RPeYi25MsUjI4JY
fKuhtwUvwy8H2G2zg6h0ObwsBoELMt2s3pP6aX9aVvpg8IIKADJO+ux182zYiK/F
1IEKW5u7YEYIS31VQ/e82QQAe2IK+EmWpnLHteVaOSpDRWd6xxkUtXwXQdSOi66q
oq6fA6t1xobngdVi7RHMLoDyzs6iuMK/naN6B/QbflRP5GNz2xjwOYuTUh7Uv3lZ
DHeV3glkgILZIYBnOsKX5SWb8mXbkId3GONkN3toUQ==
-----END CERTIFICATE-----
subject=C = IT, ST = ITALY, L = VENICE, O = MYTECH, OU = R&D, CN = mytech.local
issuer=C = IT, ST = ITALY, L = VENICE, O = MYTECH, OU = R&D, CN = mytech.local
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1503 bytes and written 396 bytes
Verification error: self-signed certificate
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 18 (self-signed certificate)
---
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
Session-ID: E66BC218BE742F264887D733676F053EA14CF057764032A6FCBD3ED3530738C5
Session-ID-ctx:
Resumption PSK: B42299493ED95287FF6DD7A28AE53EDF626F051A02F8A0262E51965356C2AFAA8C256000C8C965F61FB6BC57EA338917
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 300 (seconds)
TLS session ticket:
0000 - 4c 7a 89 1a d0 c9 e9 e9-b0 95 db de 19 12 a5 87 Lz..............
0010 - 1c 2e 32 d3 bf f9 39 c1-5c 3e 35 3f 78 b2 13 6e ..2...9.\>5?x..n
0020 - c1 cb 36 df 46 9b 64 fe-d0 f9 91 e9 72 3b dd 50 ..6.F.d.....r;.P
0030 - 4e 05 ab e5 6d e1 15 cc-5a f2 e1 09 c4 17 28 c8 N...m...Z.....(.
0040 - 2d d3 ba 98 1f 40 2a 19-46 9e 01 41 70 66 b3 f1 -....@*.F..Apf..
0050 - 65 38 8e 0d d0 5b 99 83-c5 d5 64 8f 48 8e ed 0f e8...[....d.H...
0060 - aa e9 7b 42 8e 97 06 69-52 ea d9 eb a5 94 f6 92 ..{B...iR.......
0070 - 75 73 e0 60 ba f9 29 c9-2d 72 e2 d9 b7 3d d8 65 us.`..).-r...=.e
0080 - 6b 4e 55 a3 2f 62 aa 3d-42 14 0c 36 bd 46 f0 1e kNU./b.=B..6.F..
0090 - 75 14 e7 2b fd ab 9f d0-d3 af 09 42 5b c2 e9 88 u..+.......B[...
00a0 - ca 5f dd 94 f6 20 c0 03-64 81 95 d0 04 a4 16 a9 ._... ..d.......
00b0 - cb 5e d0 f9 10 26 26 e7-4a bc 1b 6a 5a 1e 81 a4 .^...&&.J..jZ...
00c0 - bd 46 52 a8 79 38 17 d9-64 e6 5a fb cc b1 14 3d .FR.y8..d.Z....=
00d0 - e3 76 01 70 27 29 46 d2-bf e3 ca 8c 3f a9 bc 83 .v.p')F.....?...
00e0 - b2 9d ff 0a ff 68 89 43-1f 19 e7 27 9b 7c dd ff .....h.C...'.|..
00f0 - dd 64 ad 37 e7 0a 00 f3-f3 d3 33 e9 88 80 72 a1 .d.7......3...r.

Start Time: 1716285423
Timeout : 7200 (sec)
Verify return code: 18 (self-signed certificate)
Extended master secret: no
Max Early Data: 0
---
read R BLOCK
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
Session-ID: 9571C915486E6A0BBD0B2716E35EAAD6D0121EEFAA5FEE27D6966CA8C504F28B
Session-ID-ctx:
Resumption PSK: AB6C7FE7DEB60CF747ED96D6F1E51CF76A190B4F74C8BB71BDEE655FBD814AB56E4C23992B1D17F293328F6FF23DFB97
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 300 (seconds)
TLS session ticket:
0000 - 4c 7a 89 1a d0 c9 e9 e9-b0 95 db de 19 12 a5 87 Lz..............
0010 - 9a b8 e7 33 71 8c 49 5f-ac a4 ba 22 f0 89 e4 78 ...3q.I_..."...x
0020 - 6a f3 08 4a 0e 13 1c f1-2e 1a 07 d9 11 49 8b ca j..J.........I..
0030 - b3 89 87 5f fd 51 05 25-10 81 fa 00 d0 47 eb 2f ..._.Q.%.....G./
0040 - 2e 16 e3 92 e0 48 ab 92-1d f8 3e df 28 6a 35 49 .....H....>.(j5I
0050 - 8d 9e 6b 51 30 bf ad 3c-f7 6e b8 18 db 87 97 d3 ..kQ0..<.n......
0060 - 36 9a 4d 9e d6 cc d3 19-de b1 86 08 6c 0e e4 b3 6.M.........l...
0070 - 7f 28 95 08 c9 46 e2 7f-57 be 47 28 c2 02 8f b2 .(...F..W.G(....
0080 - 9c 3d 0d af cc 75 43 42-0d 7b a1 97 b2 ec 6a 3f .=...uCB.{....j?
0090 - b9 62 ae 70 d8 0d c4 4e-e6 01 b5 74 1b 7f 90 d1 .b.p...N...t....
00a0 - 07 7e b0 23 98 dd 22 d2-3d c5 74 31 9f 83 ad 66 .~.#..".=.t1...f
00b0 - 56 6b 40 6a 04 19 7e 1b-26 5d 6b 72 bb 35 5e f6 Vk@j..~.&]kr.5^.
00c0 - e5 3a a1 a3 d0 57 99 49-d5 cc b5 4f 94 1e d5 f2 .:...W.I...O....
00d0 - c0 28 c6 38 6b 28 41 d7-57 63 c0 da 8d 71 11 09 .(.8k(A.Wc...q..
00e0 - 96 09 67 1c 3d 0f 70 99-61 43 c7 7b a0 5c 1b 01 ..g.=.p.aC.{.\..
00f0 - 0d cf a9 1c 84 62 c5 50-8b 00 31 ba d3 a4 36 94 .....b.P..1...6.

Start Time: 1716285423
Timeout : 7200 (sec)
Verify return code: 18 (self-signed certificate)
Extended master secret: no
Max Early Data: 0
---
read R BLOCK
closed

Ultima cosa: il certificato è autofirmato e quindi non è collegato a nessuna Certification Authority, dunque in ogni caso il browser ci avverte:

errore scambio certificato https
errore scambio certificato https

Una volta data l’autorizzazione a scaricare il certificato autofirmato, posso vedere in Wireshsrk tutte le transazioni:

  • Client Hello
  • Server Hello
  • Change Cipher Spec

È istruttivo vedere il frammento di conversazione TCP/IP in cui il server comunica al client al versione di TLS che intende usare, il session ID, l’algoritmo di cifratura simmetrica per stabilire la chiave simmetrica DH con i parametri lunghezza e chiave:

Frammento dell'handshake (Server hello) con lo scambio dei parametri DH
Frammento dell’handshake (Server hello) con lo scambio dei parametri DH

Adozione di un certificato Let’s Encrypt

Un certificato Let’s Encrypt risolve ottimamente e senza costi il problema della verifica del certificato da parte dei browser, ma in questa fase mi interessava sapere come funzionano le cose, essendo queste delle prove eseguite in un ambiente isolato.

Riferimenti

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.