Security Advisory: EOTK and Onionspray upstream HTTPS certificate verification¶
About¶
Advisory references¶
- TROVE-ID:
TROVE-2024-002
. - CVE-ID: N/A.
- Severity: CRITICAL.
- The ticket for this issue is tpo/onion-services/onionspray#45.
- The main copy of this document be 002-proxy-ssl-verify.
Timeline¶
- 2024-02-07: Issue is found for Onionspray.
- 2024-02-07: Issue is confirmed to also affect EOTK.
- 2024-02-07: Patch is created and tested for Onionspray.
- 2024-02-07: Patch is ported and tested for EOTK.
- 2024-02-08: Release strategy and coordination begins (contacting vendors and known users in advance so they have time to upgrade).
- 2024-02-08: EOTK maintainer is contacted.
- 2024-02-09: EOTK decides to go ahead and release a fix.
- 2024-02-09: Known users are contacted.
- 2024-02-09: A fix for Onionspray is publicly released.
Document versions¶
- v2.0.0 - 09 February 2024 - First public version.
- v1.1.0 - 08 February 2024 - Fixes and adjustments.
- v1.0.0 - 07 February 2024 - Initial internal release.
Audience¶
All users and operators of .onion
websites working as rewriting proxies to
existing public accessible sites, especially when the connection between the
Onion Service and the upstream site happens through the Internet, and
especially all onionsites using EOTK or previous/unpatched Onionspray
revisions.
Impact¶
- All Onion Services running with current Onionspray and EOTK are affected, especially if they connect to the backend/upstream site through the Internet.
- The impacted Onion Service may be prone to machine-in-the-middle (MITM) attacks that can rewrite the website content and also listen to all traffic between the user and the affected onionsite.
Description¶
Onionspray works by setting up HTTPS rewriting proxies between existing sites and Tor users connecting through an Onion Service. Typically this happens through the Internet:
graph LR
C[Client] -- .onion address via Tor Network --> O[Onionspray CDN] -- HTTPS through the Internet --> U[Upstream site]
The proxy is mainly intended to replace regular domain names with their .onion counterparts, offering a seamless experience to users.
The safety of this proxy basically depends on the safety in the HTTPS connection between Onionspray and the destination remote/upstream site.
If the HTTPS certificates used in these connections aren't verified, there is no guarantee that there are no intermediaries listening or tampering with the connection.
The affected Onionspray and EOTK versions lack proper certificate verification on the upstream HTTPS connections.
The issue is fully discussed at tpo/onion-services/onionspray#45, where a fix is also provided.
Steps to reproduce¶
1. Install Onionspray¶
Proceed with the Install Onionspray guide. Or test with EOTK if you prefer.
2. Create a test service¶
Create and run a project with the following configuration (badssl.conf
):
set nginx_resolver 8.8.8.8 8.8.4.4 ipv6=off
set log_separate 1
set project badssl
hardmap %NEW_V3_ONION% badssl.com
Configure and start the badssl
project:
./onionspray config badssl.conf
./onionspray start badssl
This will create a Onion Service proxy to https://badssl.com, so you can test the backend HTTPS connection through different invalid certificates.
3. Test¶
Access both https://badssl.com flavours and the corresponding .onion domain
from the badssl
project.
Expected behavior¶
It's expected that the generated Onion Service would have a bad gateway when
accessing an upstream with problematic TLS certificate, eg.
https://expired.etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion
.
Actual behavior¶
No warnings or error, and the site is rendered as if the certificate was valid.
Available fixes¶
A fix is available and is publicly released in Onionspray 1.6.0 (2024-02-09).
Patches for both Onionspray and EOTK are also available below in this message.
The fix implements a setting to enforce upstream HTTPS certificate verification, but it's NOT enabled by default, since it depends in providing a trusted certificate file that varies depending the Certificate Authority used by the upstream site and the operating system where Onionspray is running.
In order to apply the fix, upgrade Onionspray and make sure to add a configuration like the following for all your projects:
set nginx_proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt
... where /etc/ssl/certs/ca-certificates.crt
points to the file where Root CA
files can be found that can validade the upstream certificate. You can even
use a file from /etc/ssl/certs from the Root CA that can validate the upstream
certificate, as a way to restrict the set of CAs.
After applying the fix, reconfigure and restart all projects.
Patch for Onionspray¶
The patch for Onionspray is already applied since commit 187a94d934b20a25d1a507b85c38804fa1b8b6f4
and is available on version 1.6.0.
Testing the patch:
$EDITOR badssl.conf # then add the proper nginx_proxy_ssl_trusted_certificate config
./onionspray config badssl.conf
./onionspray bounce -a
Patch for EOTK¶
A patch for EOTK is available in this pull request.
Testing the patch:
$EDITOR badssl.conf # then add the proper nginx_proxy_ssl_trusted_certificate config
./eotk config badssl.conf
./eotk bounce -a
Fix for NGINX setups¶
For other Onion Services proxies relying on NGINX, the basically involves adding the following configuration:
proxy_ssl_verify on;
proxy_ssl_trusted_certificate /path/to/some.crt;
File /etc/ssl/certs/ca-certificates.crt
will work in most cases, but it's not
widely available in all Operating systems.
References:
Fix for other setups¶
A fix for other Onion Service rewriting proxy implementations is currently out of this document scope, and we recommend that you refer to the corresponding vendor documentation and support channels.
Testing the fix¶
The effectiveness of the feature can be tested with the provided
examples/badssl.tconf
configuration for badssl.com. When
the fix is properly applied, and this configuration is used to reach a
badssl.com subdomain with a deffective configuration it
will lead to a "502 Bad Gateway" and the following NGINX errors will appear in
the logs:
user@onionspray:/path/to/onionspray$ cat projects/badssl/log/nginx-error.log
2024/02/07 17:14:51 [error] 1757#0: *32 upstream SSL certificate verify error: (10:certificate has expired) while SSL handshaking to upstream, client: unix:, server: etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion, request: "GET / HTTP/1.1", upstream: "https://104.154.89.105:443/", host: "expired.etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion"
2024/02/07 17:14:53 [error] 1757#0: *32 upstream SSL certificate verify error: (10:certificate has expired) while SSL handshaking to upstream, client: unix:, server: etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion, request: "GET /favicon.ico HTTP/1.1", upstream: "https://104.154.89.105:443/favicon.ico", host: "expired.etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion", referrer: "https://expired.etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion/"
2024/02/07 17:14:53 [error] 1757#0: *34 upstream SSL certificate verify error: (18:self-signed certificate) while SSL handshaking to upstream, client: unix:, server: etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion, request: "GET / HTTP/1.1", upstream: "https://104.154.89.105:443/", host: "self-signed.etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion"
2024/02/07 17:14:53 [error] 1757#0: *35 upstream SSL certificate verify error: (19:self-signed certificate in certificate chain) while SSL handshaking to upstream, client: unix:, server: etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion, request: "GET / HTTP/1.1", upstream: "https://104.154.89.105:443/", host: "untrusted-root.etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion"
2024/02/07 17:14:53 [error] 1757#0: *36 upstream SSL certificate verify error: (10:certificate has expired) while SSL handshaking to upstream, client: unix:, server: etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion, request: "GET / HTTP/1.1", upstream: "https://104.154.89.105:443/", host: "revoked.etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion"
2024/02/07 17:15:05 [error] 1757#0: *35 upstream SSL certificate verify error: (19:self-signed certificate in certificate chain) while SSL handshaking to upstream, client: unix:, server: etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion, request: "GET /favicon.ico HTTP/1.1", upstream: "https://104.154.89.105:443/favicon.ico", host: "untrusted-root.etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion", referrer: "https://untrusted-root.etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion/"
2024/02/07 17:15:05 [error] 1757#0: *34 upstream SSL certificate verify error: (18:self-signed certificate) while SSL handshaking to upstream, client: unix:, server: etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion, request: "GET /favicon.ico HTTP/1.1", upstream: "https://104.154.89.105:443/favicon.ico", host: "self-signed.etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion", referrer: "https://self-signed.etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion/"
2024/02/07 17:15:06 [error] 1757#0: *36 upstream SSL certificate verify error: (10:certificate has expired) while SSL handshaking to upstream, client: unix:, server: etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion, request: "GET /favicon.ico HTTP/1.1", upstream: "https://104.154.89.105:443/favicon.ico", host: "revoked.etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion", referrer: "https://revoked.etzuksalmgy62xvhv7tj427jkzow4o5j364mwfmsronu2we3ird3puad.onion/"
user@onionspray:/srv/shared$