David Fifield
The following is an evaluation of the TLS fingerprint of meek, adapted to use ESNI in place of domain fronting. It compares three TLS fingerprints:
The fingerprints produced by (2) and (3) are the same.
They differ from (1) in the lack of a server_name
(plaintext SNI) extension,
the possible omission of a padding extension,
and the addition of an encrypted_server_name
(encrypted SNI) extension
when the server is identified by a name rather than an IP address.
When Firefox is configured to use ESNI, with name resolution provided by a DNS-over-HTTPS server identified by IP address, it actually produces two distinct TLS fingerprints: one for contacting the DNS-over-HTTPS server (identified by IP address), and one for contacting the web server (identified by hostname).
All tests use an instance of meek-server running behind Cloudflare at the domain name meek.rinsed-tinsel.site.
The tests use
Firefox Developer Edition
67.0b6 linux-x86_64/en-US
(download link)
and Tor 0.2.9.16.
The browser is set up with two profiles: "plain" and "esni"
(run firefox --ProfileManager
to create profiles).
Both profiles have the following preferences set in a user.js file:
user_pref("app.normandy.enabled", false); user_pref("app.update.auto", false); user_pref("app.update.checkInstallTime", false); user_pref("app.update.interval", 999999999); user_pref("browser.laterrun.enabled", false); user_pref("browser.newtabpage.activity-stream.disableSnippets", true); user_pref("browser.newtabpage.activity-stream.discoverystream.endpoints", ""); user_pref("browser.newtabpage.activity-stream.enabled", false); user_pref("browser.newtabpage.activity-stream.feeds.section.highlights", false); user_pref("browser.newtabpage.activity-stream.feeds.section.topstories", false); user_pref("browser.newtabpage.activity-stream.feeds.snippets", false); user_pref("browser.newtabpage.activity-stream.feeds.topsites", false); user_pref("browser.newtabpage.enabled", false); user_pref("browser.safebrowsing.blockedURIs.enabled", false); user_pref("browser.safebrowsing.downloads.enabled", false); user_pref("browser.safebrowsing.malware.enabled", false); user_pref("browser.safebrowsing.passwords.enabled", false); user_pref("browser.safebrowsing.phishing.enabled", false); user_pref("browser.safebrowsing.provider.mozilla.gethashURL", ""); user_pref("browser.safebrowsing.provider.mozilla.updateURL", ""); user_pref("browser.search.geoip.url", ""); user_pref("browser.search.geoSpecificDefaults", false); user_pref("browser.search.suggest.enabled", false); user_pref("browser.shell.checkDefaultBrowser", false); user_pref("browser.startup.firstrunSkipsHomepage", false); user_pref("browser.startup.homepage", "about:blank"); user_pref("datareporting.healthreport.uploadEnabled", false); user_pref("datareporting.policy.dataSubmissionEnabled", false); user_pref("dom.push.enabled", false); user_pref("extensions.pocket.enabled", false); user_pref("geo.enabled", false); user_pref("geo.wifi.url", ""); user_pref("network.captive-portal-service.enabled", false); user_pref("privacy.trackingprotection.enabled", false); user_pref("privacy.trackingprotection.pbmode.enabled", false); user_pref("startup.homepage_override_url", ""); user_pref("startup.homepage_welcome_url", ""); user_pref("toolkit.telemetry.enabled", false);
The esni profile additionally has the following preferences set in user.js:
user_pref("browser.dom.window.dump.enabled", true); user_pref("network.trr.mode", 3); user_pref("network.trr.uri", "https://1.1.1.1/dns-query"); user_pref("network.security.esni.enabled", true); user_pref("security.OCSP.enabled", 0); user_pref("xpinstall.signatures.required", false);
The esni profile then has the meek-http-helper extension installed according to these instructions. The version of meek is commit 5b96265e01cf5e82b9e82f9e9e05441ac5311245.
Packet captures are run in a separate Linux network namespace, in order to isolate the test's traffic from other traffic on the host. The network namespace is set up as follows:
# mkdir -p /etc/netns/net0 # sh -c 'echo nameserver 8.8.8.8 > /etc/netns/net0/resolv.conf' # ip netns add net0 # ip link add veth-a type veth peer name veth-b # ip link set veth-a netns net0 # ip netns exec net0 ip address add 127.0.0.1/8 dev lo # ip netns exec net0 ip link set lo up # ip netns exec net0 ip address add 192.168.100.2/24 dev veth-a # ip netns exec net0 ip link set veth-a up # ip address add 192.168.100.1/24 dev veth-b # ip link set veth-b up # ip netns exec net0 ip route add default via 192.168.100.1 dev veth-a # sh -c 'echo 1 > /proc/sys/net/ipv4/ip_forward' # iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o $INTERFACE -j SNAT --to-source $ADDRESS
$INTERFACE
stands for the name of the default
extenal network interface (e.g. eth0
) and
$ADDRESS
stands for the interface's address
(e.g. 192.168.0.2
).
tor is configured with a torrc.esni file that refers to the meek-http-helper extension's listening address. The port number changes on each run of Firefox and has to be manually edited.
DataDirectory datadir SOCKSPort auto UseBridges 1 Bridge meek 0.0.2.0:3 url=https://meek.rinsed-tinsel.site/ ClientTransportPlugin meek exec ./meek-client --helper 127.0.0.1:$PORT
$PORT
must be edited
as it changes on every run of Firefox.
Firefox and tor are run as follows, where $USER
stands for the username of an ordinary user on the host:
# ip netns exec net0 tcpdump -U -w OUTPUT.PCAP
# ip netns exec net0 su $USER -c './firefox -P plain'
# ip netns exec net0 su $USER -c './firefox -P esni'
# ip netns exec net0 su $USER -c 'tor -f torrc.esni'
tor was run twice, as the first run would always fail due to an apparent Firefox bug.
Browsing directly to https://meek.rinsed-tinself.site/ results in TLS fingerprint 6bfedc5d5c740d58 (archive), which at the time of writing is ranked #11 all time and #7 in the past week.
The name is resolved with plaintext DNS and the server name appears in plaintext SNI.
Browsing directly to https://meek.rinsed-tinself.site/ results in two TLS fingerprints.
The first fingerprint is
8300bf0e26f2a109 (archive)
which ranks #3758 all time and #3643 in the past week.
This fingerprint appears in the requests to 1.1.1.1,
which is the DNS-over-HTTPS server configured.
It differs (archive)
from 6bfedc5d5c740d58 only in the lack of a server_name
extension,
which is expected because the server is identified by IP address.
The second fingerprint is
2dcbeba533890640 (archive)
which ranks #6219 all time and #3681 in the past week.
This fingerprint appears in the requests to
meek.rinsed-tinsel.site.
It differs (archive)
from 6bfedc5d5c740d58 in that it lacks
server_name
and padding
extensions,
and gains a encrypted_server_name
(0xffce) extension.
Bootstrapping tor with meek-client through the ESNI-enabled firefox results in the same two TLS fingerprints as in the Firefox with ESNI case.
OCSP must be disabled with using ESNI, because OCSP requests may leak the server name. That is why the esni browser profile has the `security.OCSP.enabled` pref set. Because the plain browser profile does not have this pref set, I expected to see OCSP requests regarding meek.rinsed-tinself.site in plain.pcap, but did not, for unknown reasons.