Use Wildcard Certificates to Reduce the Attack Probability by Hiding Cloud Instances from TLS Certificate Transparency Logs

tl;dr: Use <secret-id>.<public-id>.ui.nabu.casa combined with wildcard certificates for *.<public-id>.ui.nabu.casa to hide HA-instances from TLS transparency logs and protect users against themselves (weak credentials) and agains 0-day attacks.

Current State

Every user of Home Assistant Cloud gets a public URL with the following structure:
<RANDOM-IDENTIFIER>.ui.nabu.casa.
Using Let’s Encrypt a certificate is locally generated and then used to provide an end-to-end encrypted connection to the instance.

Connections to these URLs lead to AWS servers controlled by Nabu Casa where they are routed to the correct Home Assistant instance without breaking the encryption by using Server Name Indication (SNI) as described here.

The Problem

The random identifier might suggest to make finding the instance during scans hard, but due to TLS Certificate Transparency logs all these identifiers are public.
Using open source tooling I was able to quickly gather a list of over 25000 Home Assistant instances.
See e.g. https://crt.sh/?q=ui.nabu.casa.

Password Spraying with common credentials can easily be done and the probability of successful logins is very high.
From there it is possible to get full access to the user’s network (e.g. using the addon ‘Terminal & SSH’)

Further, Home Assistant is not immune to vulnerabilities that could grant even an unauthenticated attacker access to all those instances.

Proposed Solution

I propose to change the URL structure to
<SECRET-IDENTIFIER>.<PUBLIC-IDENTIFIER>.ui.nabu.casa
and use TLS wildcard certificates for
*.<PUBLIC-IDENTIFIER>.ui.nabu.casa.

The public identifier would still be visible in the certificate transparency logs.
The secret identifier would act as a password that needs to be present in the SNI for traffic to even be forwarded to the local Home Assistant instance.

This would hide cloud customer’s instances pretty well and prevent easy enumeration and consequently exploitation.

The solution is not perfect, as the secret identifier would e.g. be visible in plain text to all systems on the route to the local instance and would also be known to external cloud providers like Amazon (for Alexa integration) or Google (for Google Assistant integration).

Benefits (Summary)

  • Protection of less security-conscious users (Users that use admin:admin or other weak credentials for their internet exposed instance)
  • Protection in case of 0-day vulnerabilities (Malicious traffic wouldn’t even hit the Home Assistant instance but be stopped at Nabu Casa’s SniTun)

What prevents someone from simply enumerating the ‘secret’ identifier?

There are two options that already exist to make this attack method next to impossible:

Enable IP ban and set a reasonable login attempt threshold (e.g. 5). IMO this should be enabled by default.

Enable MFA: Multi-factor authentication - Home Assistant

1 Like

@tom_l:
Both of these are valuable features but don’t solve the problems I mentioned.

IP ban
This only helps agains password brute force attacks. During Password Spraying an attacker on tries very few (possibly only one) login on each instance. Therefore no IP ban is triggered.
Still, you’ll certainly find many instances using common credentials like admin:admin, admin:password, admin:123456, etc.
See this OWASP Cheat Sheet for more information.

MFA
Again: Very valuable feature.
But someone using admin:admin as their login won’t enable MFA. My feature request would offer protection to the less security-conscious users.

Additionally, MFA does not protect against vulnerability exploitation. My suggestion would prevent malicious traffic from ever hitting the Home Assistant instance which reduces the attack surface.

@langestefan:
That would be an online brute force attack. Choosing sufficiently long and random secrets would reduce the chances of finding even a single instance to almost zero. Additionally such attacks could (with limitations) be detected and blocked by Nabu Casa.

Meanwhile the current state allows me to find >25000 instances using a single command which works fully passively (without touching Nabu Casa servers).