guest@6admin.io:~$

Internal vs external domain separation

Using one domain name for both the public site and the internal estate feels tidy and it quietly hands an attacker several advantages at once. The argument for splitting them is not aesthetic, it is that a handful of concrete attacks stop working the moment internal services live under a name that never appears in a public certificate or a public DNS answer.

Why a shared domain leaks

A wildcard certificate is the first problem. A *.company.com issued for the public web is, by construction, valid for every internal host under that name too, so the day a single public server is compromised, its certificate impersonates any internal service without a browser blinking. One stolen key and the man in the middle is trusted everywhere.

Certificate Transparency is the second and it is the one people forget. Every publicly trusted certificate is logged, publicly, forever and crt.sh turns that log into a free map of your estate:

jenkins.company.com   → you run CI/CD, here
gitlab.company.com    → source lives there
backup.company.com    → the backups are there
ad.company.com        → Active Directory, this way
vpn.company.com       → remote access, knock here

None of that reconnaissance costs the attacker a single packet against you. You published it yourself, the moment you asked a public CA for the certificate. Internal names under an internal domain, signed by an internal CA, never enter a CT log and the map goes dark.

The third is DNS. Sharing a zone between the inside and the outside forces split-horizon, which is fiddly and fails in the direction of disclosure and it ties internal resolution to the fate of your external DNS: hijack or poison the public side and the internal side moves with it.

Typosquatting and homographs

The lookalike domain is the social-engineering half of the problem and it gets sharper when internal services carry a public-looking name, because users trust what looks internal and skip the scrutiny they would give an external link.

Plain typos are the cheap version: compeny.com, intranet.company.co with the m gone, intranet-company.com folding a subdomain into a domain. The dangerous version is the IDN homograph, a name that is visually identical and byte-for-byte different:

Legitimate: company.com
Lookalike:  сompany.com   (Cyrillic 'с', U+0441)
Punycode:   xn--ompany-hrf.com

The Latin-to-Cyrillic substitutions (a→а, c→с, e→е, i→і, o→о, p→р) render pixel-identical in most fonts, so the only reliable tell is the Punycode, which is exactly what a hurried user never checks. The payoff is the usual trio: a fake login page that harvests credentials, a “software update” that ships malware, an invoice page that reroutes a payment.

The architecture that closes it

Two domains, one public and one internal, with no overlap:

company.com            (public only)      company.internal   (internal only)
├── www.company.com                       ├── intranet.company.internal
├── mail.company.com                      ├── ad.company.internal
├── api.company.com                       ├── gitlab.company.internal
└── blog.company.com                      └── *.dev.company.internal

As of 2024 .internal is formally reserved by ICANN for private use, which is the first time this advice rests on something firmer than convention: the name can never be delegated on the public internet, so it can never collide with a real registration and never needs a publicly trusted certificate. .corp and .home sit on the same never-delegate list and work too, though .internal is now the one with an explicit blessing.

The public side takes individual certificates per service, never a wildcard, so a single compromise does not spread and CT logs reveal only what is already meant to be public. The internal side runs its own PKI, where a wildcard is fine precisely because nothing about it is published:

Root CA (offline, air-gapped)
├── Intermediate - servers
├── Intermediate - users and devices
├── Intermediate - development (short-lived)
└── Intermediate - code signing

What is worth doing on top

Defensive registration buys down the lookalike risk for the names that would hurt most, both the plain typos and the obvious Cyrillic homographs of the brand, plus monitoring for new ones rather than trying to pre-register an infinite space.

On the technical side, the levers that actually move the needle: internal resolvers authoritative for the .internal zone, browsers set to force Punycode display for mixed-script names so a homograph stops hiding, HSTS with includeSubDomains and certificate pinning for the handful of applications that justify the operational cost.

For monitoring, CT itself becomes a defensive tool once you watch it for your own name and the usual domain-permutation scanners cover the squatting space:

# watch CT for anything claiming your name
curl -s "https://crt.sh/?q=%25company.com&output=json" \
  | jq '.[] | select(.name_value | contains("company"))'

# enumerate registered look-alikes, homographs included
dnstwist --registered --format idna company.com

The user-facing rule that survives all the tooling is boring and effective: internal services live under .internal, they are reached from a bookmark and never from an email link and anything asking for credentials under a public-looking name gets a second look at the address bar before a password.

Where the claim stops

Separation does not make phishing impossible and anyone selling it as “absolute protection” is overselling. What it does is remove whole attack classes from the board: the wildcard that impersonates the inside, the CT log that maps it, the public lookalike that borrows an internal-looking name. Those are worth removing on their own and a clean split between the public domain and an internal one reserved for the purpose is the cheapest way to remove them.