🌐 Расшифровка зашифрованного TLS HTTP-трафика для отладки

Мануал

Для отладки HTTP-запросов может оказаться полезным перехват трафика и просмотр пакетов, которые отправляются туда и обратно между клиентом и сервером.

Это тривиально, если HTTP-запросы отправляются по незашифрованному каналу.

В этом случае достаточно просто использовать инструмент типа tcpdump для захвата пакетов и просмотреть их с помощью инструмента типа Wireshark.

Для демонстрации вместо Wireshark используется tshark.

Tshark – это версия Wireshark, основанная на CLI, и предоставляет примерно те же возможности для анализа сетевых пакетов.

Разумеется, показанная здесь отладка может быть выполнена и с помощью Wireshark с графическим интерфейсом.

Для начала давайте рассмотрим пример отладки HTTP-трафика с помощью tshark.

Сначала мы запустим простой httpd-сервер Apache, который принимает обычные текстовые соединения на порту 80 и шифрованные TLS-соединения на порту 443.

Для удобства мы запустим Apache httpd внутри контейнера Docker, но он будет работать и без контейнера, независимо от того, установлен ли Apache httpd из репозитория дистрибутива или скомпилирован самостоятельно.

Чтобы запустить контейнер Apache httpd, создайте файл Dockerfile со следующим содержимым.

Система установит веб-сервер Apache httpd, который по умолчанию принимает обычные текстовые соединения на порту 80.

Кроме того, мы включаем TLS-шифрованные соединения на порту 443 и для этого используем сертификаты, предоставляемые пакетом ssl-cert.

Это самоподписанные сертификаты, которые можно использовать для тестирования.

Поскольку они самоподписанные, они не будут распознаны как доверенные сертификаты большинством пользовательских агентов, но это не проблема.

FROM httpd:2.4

# install snakeoil certificates
RUN apt update && apt install -y ssl-cert

# enable https on port 443 with snakeoil certificates
RUN sed -i \
   -e 's/^#\(Include .*httpd-ssl.conf\)/\1/' \
   -e 's/^#\(LoadModule .*mod_ssl.so\)/\1/' \
   -e 's/^#\(LoadModule .*mod_socache_shmcb.so\)/\1/' \
   conf/httpd.conf
RUN sed -i \
   -e 's|^\(SSLCertificateFile\).*|\1 /etc/ssl/certs/ssl-cert-snakeoil.pem|' \
   -e 's|^\(SSLCertificateKeyFile\).*|\1 /etc/ssl/private/ssl-cert-snakeoil.key|' \
   conf/extra/httpd-ssl.conf

# additionally expose port 443
EXPOSE 443

Затем соберите его с помощью этой команды:

docker build -t simple-apache-httpd .

Теперь запустите httpd-сервер Apache в качестве контейнера:

docker run -it --rm --net="host" --name simple-apache-httpd simple-apache-httpd

В отдельном терминале запустите tcpdump для захвата трафика:

sudo tcpdump -v -i any "src localhost || dst localhost" -w dump.pcap

В другом терминале выполните команду curl для выполнения запроса к контейнеру в открытом виде:

$ curl -v http://localhost
*   Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Thu, 02 Dec 2021 12:55:40 GMT
< Server: Apache/2.4.51 (Unix) OpenSSL/1.1.1k
< Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
< ETag: "2d-432a5e4a73a80"
< Accept-Ranges: bytes
< Content-Length: 45
< Content-Type: text/html
< 
<html><body><h1>It works!</h1></body></html>
* Connection #0 to host localhost left intact

Остановите tcpdump и просмотрите захват пакетов с помощью tshark:

$ tshark -r dump.pcap -Y http
   48  11.912607    127.0.0.1 → 127.0.0.1    HTTP 141 GET / HTTP/1.1 
   50  11.919104    127.0.0.1 → 127.0.0.1    HTTP 353 HTTP/1.1 200 OK  (text/html)

Мы можем четко увидеть HTTP-запрос, который мы только что выполнили с помощью curl.

🖧 В чем разница между curl и Wget?

С зашифрованными соединениями TLS это уже не так просто.

Мы вообще не увидим никакого HTTP-трафика, вместо этого мы увидим только рукопожатие TLS и зашифрованные пакеты данных.

Обратите внимание, что теперь нам нужно указать флаг -k для curl, поскольку сертификаты являются самоподписанными и поэтому не заслуживают доверия:

$ curl -v -k https://localhost
*   Trying 127.0.0.1:443...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: CN=f31d50e8d088
*  start date: Dec  2 10:39:24 2021 GMT
*  expire date: Nov 30 10:39:24 2031 GMT
*  issuer: CN=f31d50e8d088
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.68.0
> Accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Thu, 02 Dec 2021 13:00:23 GMT
< Server: Apache/2.4.51 (Unix) OpenSSL/1.1.1k
< Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
< ETag: "2d-432a5e4a73a80"
< Accept-Ranges: bytes
< Content-Length: 45
< Content-Type: text/html
< 
<html><body><h1>It works!</h1></body></html>
* Connection #0 to host localhost left intact

Мы больше не видим HTTP-запрос:

$ tshark -r dump.pcap -Y http

Мы можем видеть только зашифрованные пакеты TLS:

$ tshark -r dump.pcap -Y tls
   13   1.492489    127.0.0.1 → 127.0.0.1    TLSv1 585 Client Hello
   15   1.496532    127.0.0.1 → 127.0.0.1    TLSv1.3 1381 Server Hello, Change Cipher Spec, ...
   17   1.497260    127.0.0.1 → 127.0.0.1    TLSv1.3 148 Change Cipher Spec, Application Data
   19   1.497486    127.0.0.1 → 127.0.0.1    TLSv1.3 163 Application Data
   21   1.497556    127.0.0.1 → 127.0.0.1    TLSv1.3 355 Application Data
   23   1.497709    127.0.0.1 → 127.0.0.1    TLSv1.3 355 Application Data
   25   1.498220    127.0.0.1 → 127.0.0.1    TLSv1.3 375 Application Data
   27   1.498655    127.0.0.1 → 127.0.0.1    TLSv1.3 92 Application Data
   29   1.498830    127.0.0.1 → 127.0.0.1    TLSv1.3 92 Application Data

Теперь трафик зашифрован, и нам потребуется расшифровать захваченные пакеты, чтобы проверить HTTP-трафик.

В целях проверки трафика TLS-соединения можно разделить на две группы.

Соединения, которые используют Perfect Forward Secrecy (PFS), и соединения, которые не используют.

Основное различие между этими двумя типами соединений заключается в том, что соединения без PFS могут быть расшифрованы постфактум с помощью долгоживущего закрытого ключа сервера.

Для соединений с PFS это невозможно, поскольку между клиентом и сервером согласовываются недолговечные, эфемерные ключи.

Обычно это достигается путем обмена ключами Диффи-Хеллмана или его производной. Эфемерные ключи, созданные во время обмена ключами, никогда не сохраняются и не используются повторно для других соединений.

Это предотвращает расшифровку трафика без участия в первоначальном рукопожатии соединения.

Сначала рассмотрим соединения без PFS. Здесь для расшифровки трафика достаточно передать Wireshark закрытый ключ сервера.

Для этого примера мы должны убедиться, что используем параметры TLS, которые не задействуют PFS. Для этого мы явно указываем curl использовать протокол TLSv1.2 и набор шифров CAMELLIA128-SHA.

Мы повторяем приведенный выше пример, перехватывая трафик:

$ curl -v -k --tlsv1.2 --tls-max 1.2 --ciphers CAMELLIA128-SHA https://localhost
*   Trying 127.0.0.1:443...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: CAMELLIA128-SHA
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / CAMELLIA128-SHA
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: CN=f31d50e8d088
*  start date: Dec  2 10:39:24 2021 GMT
*  expire date: Nov 30 10:39:24 2031 GMT
*  issuer: CN=f31d50e8d088
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Thu, 02 Dec 2021 13:34:01 GMT
< Server: Apache/2.4.51 (Unix) OpenSSL/1.1.1k
< Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
< ETag: "2d-432a5e4a73a80"
< Accept-Ranges: bytes
< Content-Length: 45
< Content-Type: text/html
< 
<html><body><h1>It works!</h1></body></html>
* Connection #0 to host localhost left intact
$ tshark -r dump.pcap -Y tls
    6   0.420061    127.0.0.1 → 127.0.0.1    TLSv1 216 Client Hello
    8   0.420403    127.0.0.1 → 127.0.0.1    TLSv1.2 943 Server Hello, Certificate, Server Hello Done
   10   0.420756    127.0.0.1 → 127.0.0.1    TLSv1.2 414 Client Key Exchange, Change Cipher Spec, ...
   12   0.421699    127.0.0.1 → 127.0.0.1    TLSv1.2 147 Change Cipher Spec, Encrypted Handshake Message
   14   0.421923    127.0.0.1 → 127.0.0.1    TLSv1.2 189 Application Data
   16   0.422142    127.0.0.1 → 127.0.0.1    TLSv1.2 397 Application Data
   18   0.422378    127.0.0.1 → 127.0.0.1    TLSv1.2 125 Encrypted Alert
   20   0.422497    127.0.0.1 → 127.0.0.1    TLSv1.2 125 Encrypted Alert

Теперь мы извлекаем закрытый TLS ключ сервера:

docker exec -it simple-apache-httpd cat /etc/ssl/private/ssl-cert-snakeoil.key > ssl-cert-snakeoil.key

Это позволит нам использовать закрытый ключ в tshark, указав его с помощью флага -o:

$ tshark -o tls.keys_list:,,,ssl-cert-snakeoil.key -r dump.pcap -Y tls
    6   0.420061    127.0.0.1 → 127.0.0.1    TLSv1 216 Client Hello
    8   0.420403    127.0.0.1 → 127.0.0.1    TLSv1.2 943 Server Hello, Certificate, Server Hello Done
   10   0.420756    127.0.0.1 → 127.0.0.1    TLSv1.2 414 Client Key Exchange, Change Cipher Spec, Finished
   12   0.421699    127.0.0.1 → 127.0.0.1    TLSv1.2 147 Change Cipher Spec, Finished
   14   0.421923    127.0.0.1 → 127.0.0.1    HTTP 189 GET / HTTP/1.1 
   16   0.422142    127.0.0.1 → 127.0.0.1    HTTP 397 HTTP/1.1 200 OK  (text/html)
   18   0.422378    127.0.0.1 → 127.0.0.1    TLSv1.2 125 Alert (Level: Warning, Description: Close Notify)
   20   0.422497    127.0.0.1 → 127.0.0.1    TLSv1.2 125 Alert (Level: Warning, Description: Close Notify)

Как было сказано выше, этот подход не будет работать с PFS.

Это означает, что если доступны только параметры TLS с PFS, то невозможно будет использовать описанный выше подход для расшифровки трафика для отладки.

Для TLSv1.3 это всегда так, потому что TLSv1.3 требует PFS.

Нам не нужно указывать это явно, так как curl будет автоматически использовать TLSv1.3.

Чтобы проиллюстрировать это, мы покажем пример, как и раньше.

$ curl -v -k https://localhost
*   Trying 127.0.0.1:443...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: CN=f31d50e8d088
*  start date: Dec  2 10:39:24 2021 GMT
*  expire date: Nov 30 10:39:24 2031 GMT
*  issuer: CN=f31d50e8d088
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.68.0
> Accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Thu, 02 Dec 2021 14:06:14 GMT
< Server: Apache/2.4.51 (Unix) OpenSSL/1.1.1k
< Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
< ETag: "2d-432a5e4a73a80"
< Accept-Ranges: bytes
< Content-Length: 45
< Content-Type: text/html
< 
<html><body><h1>It works!</h1></body></html>
* Connection #0 to host localhost left intact

При использовании PFS мы снова видим только рукопожатие TLS.

Несмотря на предоставление серверам закрытого ключа, как и раньше, пакеты остаются зашифрованными.

$ tshark -o tls.keys_list:,,,ssl-cert-snakeoil.key -r dump.pcap -Y tls
   20   1.660863    127.0.0.1 → 127.0.0.1    TLSv1 585 Client Hello
   22   1.676658    127.0.0.1 → 127.0.0.1    TLSv1.3 1381 Server Hello, Change Cipher Spec, ...
   24   1.677228    127.0.0.1 → 127.0.0.1    TLSv1.3 148 Change Cipher Spec, Application Data
   26   1.677406    127.0.0.1 → 127.0.0.1    TLSv1.3 355 Application Data
   27   1.677415    127.0.0.1 → 127.0.0.1    TLSv1.3 163 Application Data
   30   1.677504    127.0.0.1 → 127.0.0.1    TLSv1.3 355 Application Data
   32   1.680826    127.0.0.1 → 127.0.0.1    TLSv1.3 375 Application Data
   34   1.681131    127.0.0.1 → 127.0.0.1    TLSv1.3 92 Application Data
   36   1.681262    127.0.0.1 → 127.0.0.1    TLSv1.3 92 Application Data

Чтобы расшифровать этот трафик, нам придется регистрировать эфемерные ключи либо на стороне клиента, либо на стороне сервера.

Все больше и больше технологий используют переменную окружения SSLKEYLOGFILE как способ указать файл журнала, в который могут записываться эфемерные ключи.

Эти журналы могут быть переданы в tshark для расшифровки трафика, аналогично тому, как мы использовали закрытый ключ сервера ранее.

Обратите внимание, что эфемерные ключи вообще не записываются в журнал, если эта переменная окружения не установлена.

Для проверки трафика переменная окружения SSLKEYLOGFILE должна быть установлена на стороне сервера или клиента во время генерации трафика.

После создания этого журнала перехват и расшифровка трафика работают точно так же, как и раньше.

Давайте сначала выполним пример, в котором мы установим переменную окружения SSLKEYLOGFILE на стороне клиента с помощью curl.

Убедитесь, что вы используете curl 7.58 или более новую версию, чтобы это работало.

$ SSLKEYLOGFILE=sslkeylogfile.log curl -v -k https://localhost
*   Trying 127.0.0.1:443...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: CN=f31d50e8d088
*  start date: Dec  2 10:39:24 2021 GMT
*  expire date: Nov 30 10:39:24 2031 GMT
*  issuer: CN=f31d50e8d088
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.68.0
> Accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Thu, 02 Dec 2021 14:17:04 GMT
< Server: Apache/2.4.51 (Unix) OpenSSL/1.1.1k
< Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
< ETag: "2d-432a5e4a73a80"
< Accept-Ranges: bytes
< Content-Length: 45
< Content-Type: text/html
< 
<html><body><h1>It works!</h1></body></html>
* Connection #0 to host localhost left intact

С помощью журнала ключей, записанного curl, мы можем снова расшифровать трафик.

Обратите внимание, что закрытый ключ сервера больше не требуется, нам нужен только файл журнала ключей.

$ tshark -o tls.keylog_file:sslkeylogfile.log -r dump.pcap -Y tls
    4   0.007706    127.0.0.1 → 127.0.0.1    TLSv1 585 Client Hello
    6   0.009024    127.0.0.1 → 127.0.0.1    TLSv1.3 1381 Server Hello, Change Cipher Spec, ...
    8   0.009576    127.0.0.1 → 127.0.0.1    TLSv1.3 148 Change Cipher Spec, Finished
   10   0.009790    127.0.0.1 → 127.0.0.1    HTTP 163 GET / HTTP/1.1 
   11   0.009796    127.0.0.1 → 127.0.0.1    TLSv1.3 355 New Session Ticket
   14   0.009941    127.0.0.1 → 127.0.0.1    TLSv1.3 355 New Session Ticket
   16   0.010132    127.0.0.1 → 127.0.0.1    HTTP 375 HTTP/1.1 200 OK  (text/html)
   18   0.010355    127.0.0.1 → 127.0.0.1    TLSv1.3 92 Alert (Level: Warning, Description: Close Notify)
   20   0.010458    127.0.0.1 → 127.0.0.1    TLSv1.3 92 Alert (Level: Warning, Description: Close Notify)

Аналогичным образом мы можем установить переменную окружения SSLKEYLOGFILE на стороне сервера.

Для этого необходимо наличие Apache httpd 2.4.49 или более поздней версии.

Мы перезапускаем контейнер сервера и передаем переменную окружения SSLKEYLOGFILE.

docker run -it --rm --net="host" --name simple-apache-httpd -e SSLKEYLOGFILE="/usr/local/apache2/logs/sslkeylogfile.log" simple-apache-httpd

Следующая запись журнала сигнализирует о том, что файл журнала ключей будет записан:

[Tue Dec 21 20:03:20.441733 2021] [ssl:notice] [pid 1:tid 139780428569920] AH10227: Init: Logging SSL private key material to /usr/local/apache2/logs/sslkeylogfile.log

Мы готовы повторить запрос:

$ curl -v -k https://localhost
*   Trying 127.0.0.1:443...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: CN=f31d50e8d088
*  start date: Dec  2 10:39:24 2021 GMT
*  expire date: Nov 30 10:39:24 2031 GMT
*  issuer: CN=f31d50e8d088
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.68.0
> Accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Thu, 02 Dec 2021 14:23:13 GMT
< Server: Apache/2.4.51 (Unix) OpenSSL/1.1.1k
< Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
< ETag: "2d-432a5e4a73a80"
< Accept-Ranges: bytes
< Content-Length: 45
< Content-Type: text/html
< 
<html><body><h1>It works!</h1></body></html>
* Connection #0 to host localhost left intact

После выполнения и захвата запроса нам нужно получить файл журнала из контейнера, чтобы использовать его с помощью tshark.

docker exec -it simple-apache-httpd cat /usr/local/apache2/logs/sslkeylogfile.log > sslkeylogfile.log

Теперь мы можем расшифровать трафик, как и раньше, снова передав файл журнала ключей в tshark:

$ tshark -o tls.keylog_file:sslkeylogfile.log -r dump.pcap -Y tls
    6   0.033156    127.0.0.1 → 127.0.0.1    TLSv1 585 Client Hello
    8   0.035385    127.0.0.1 → 127.0.0.1    TLSv1.3 1381 Server Hello, Change Cipher Spec, ...
   10   0.035890    127.0.0.1 → 127.0.0.1    TLSv1.3 148 Change Cipher Spec, Finished
   12   0.036026    127.0.0.1 → 127.0.0.1    HTTP 163 GET / HTTP/1.1 
   14   0.036078    127.0.0.1 → 127.0.0.1    TLSv1.3 355 New Session Ticket
   16   0.036194    127.0.0.1 → 127.0.0.1    TLSv1.3 355 New Session Ticket
   18   0.036511    127.0.0.1 → 127.0.0.1    HTTP 375 HTTP/1.1 200 OK  (text/html)
   20   0.036814    127.0.0.1 → 127.0.0.1    TLSv1.3 92 Alert (Level: Warning, Description: Close Notify)
   22   0.036932    127.0.0.1 → 127.0.0.1    TLSv1.3 92 Alert (Level: Warning, Description: Close Notify)

Этот подход с использованием переменной окружения SSLKEYLOGFILE работает и в некоторых браузерах.

Однако ее можно отключить с помощью переменной времени компиляции из-за риска, который она представляет.

Если злоумышленнику удастся установить эту переменную окружения для клиента или сервера и получить доступ к журналу ключей, он сможет легко взломать TLS-шифрование, как показано выше.

По этой причине хорошей идеей может быть мониторинг журналов на наличие записи, указывающей на использование переменной среды SSLKEYLOGFILE, как показано выше, или даже добавление отдельного журнала, в котором переменная SSLKEYLOGFILE будет регистрироваться, если она присутствует.

Это позволит вам определить постфактум, какие запросы были затронуты, если переменная окружения была установлена.

Кроме того, было бы неплохо просмотреть переменные окружения всех процессов, чтобы определить, установлена ли где-нибудь эта переменная.

Простым способом сделать это вручную является следующая команда.

Она показывает, что переменная окружения SSLKEYLOGFILE используется и куда записывается файл журнала ключей:

$ sudo cat /proc/*/environ | tr '\0' '\n' | grep SSLKEYLOGFILE
SSLKEYLOGFILE=/usr/local/apache2/logs/sslkeylogfile.log
SSLKEYLOGFILE=/usr/local/apache2/logs/sslkeylogfile.log
SSLKEYLOGFILE=/usr/local/apache2/logs/sslkeylogfile.log
SSLKEYLOGFILE=/usr/local/apache2/logs/sslkeylogfile.log

см. также:

 

Добавить комментарий