Skip to content

Security Advisory: EOTK and Onionspray upstream HTTPS certificate verification

About

Advisory references

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$