Origens: um bug de navegador que não tinha solução limpa

A Public Suffix List nasceu de um problema de segurança que ninguém conseguia resolver direito. O navegador precisa decidir se um site pode gravar um cookie que outro site vai conseguir ler e, para responder isso com honestidade, é preciso saber onde começa o controle de uma organização sobre um nome.

Essa fronteira não está no DNS. Não existe tipo de registro que diga "abaixo deste ponto, donos diferentes". O com vende nomes para qualquer um, o co.uk também, o github.io dá um subdomínio para qualquer usuário que tenha conta e, para o protocolo, os três são rótulos (labels, os trechos do nome separados por pontos) como quaisquer outros. Por isso, as regras de cookie baseadas em contar rótulos erravam para os dois lados: eram permissivas demais no co.uk, onde um site conseguia gravar um cookie para todas as empresas britânicas de uma vez, e restritivas demais em outros casos.

A Mozilla começou a manter uma lista em meados dos anos 2000 para corrigir o comportamento dos cookies, e a lista passou a servir para outras coisas quase de imediato. Hoje o mesmo arquivo define a política de emissão de certificados, as verificações de same-site, o escopo de permissões e o jeito como as ferramentas de analytics agrupam o tráfego. É muita responsabilidade para um arquivo de texto mantido por voluntários, e essa fragilidade faz parte do assunto; não é um detalhe à parte.

O que ela é, na prática

É uma lista de sufixos sob os quais qualquer pessoa pode registrar um nome. Assim, o rótulo logo à esquerda de um sufixo da lista é a menor unidade que uma organização controla. Essa unidade é o domínio registrável, ou eTLD+1.

Duas características costumam surpreender. A lista não é uma relação de domínios de topo: tem milhares de entradas, e a maioria delas tem mais de um rótulo. E não é uma especificação com um documento numerado por trás; é um arquivo mantido por curadoria, com um processo para pedir inclusão. Ou seja, a fronteira que o navegador aplica é algo que alguém mantém, e não um fato que se deduz.

O problema dos "dois últimos rótulos"

É tentador supor que a parte registrada de um hostname são só os dois últimos rótulos. Com www.example.com isso funciona: o domínio registrado é example.com. Mas com www.example.co.uk dá errado. Aqui, .co.uk é um sufixo público, então o domínio registrado é example.co.uk, com três rótulos. Nada na string indica isso. O único jeito de saber que .co.uk se comporta como um domínio de topo e .example.com não é consultar uma lista dos sufixos que são públicos. Essa lista é a Public Suffix List (PSL), e a ferramenta de domínio registrado analisa os nomes com base nela.

Duas definições

Um sufixo público, também chamado de effective top-level domain (domínio de topo efetivo) ou eTLD, é um sufixo sob o qual qualquer pessoa pode registrar nomes diretamente. com, co.uk, github.io e s3.amazonaws.com são todos sufixos públicos. Um domínio registrado, ou eTLD+1, é um sufixo público mais exatamente um rótulo à esquerda dele: o nome mais curto que alguém pode de fato ter. example.com e example.co.uk são domínios registrados; co.uk não é, porque ninguém registra o próprio co.uk.

O algoritmo

Analisar um nome com base na lista segue um procedimento curto e exato. Você procura as regras que batem com o host: os rótulos da regra precisam ser iguais aos do host, comparando da direita para a esquerda, e um rótulo * na regra vale por qualquer rótulo, desde que seja um só. Entre as regras que batem, uma regra de exceção (escrita com um ! na frente) sempre vence; se não houver exceção, vence a regra com mais rótulos. Se a vencedora for uma regra de exceção, descarta-se o rótulo mais à esquerda dela. O sufixo público é o trecho que a regra vencedora cobre, e o domínio registrado é esse sufixo mais um rótulo. Se nenhuma regra bater, só o rótulo mais à direita é tratado como sufixo.

Dois tipos de regra fazem a diferença em relação a uma comparação ingênua. Um wildcard como *.ck quer dizer que todo algo.ck é um sufixo público; então foo.bar.ck é registrável, mas bar.ck não é. Uma exceção como !www.ck tira um único nome de dentro do wildcard; então www.ck é registrável, mesmo que o wildcard, sozinho, o tivesse engolido.

ICANN e PRIVATE

A lista tem duas seções, e a divisão não é só de fachada. A seção (Internet Corporation for Assigned Names and Numbers) reúne os sufixos operados pelos registros de domínio (os registries): é essa a fronteira que os navegadores aplicam nas decisões de segurança. A seção PRIVATE reúne sufixos que empresas incluíram porque distribuem subdomínios para terceiros, como github.io, *.compute.amazonaws.com ou várias plataformas de hospedagem de aplicações. As duas podem dar respostas diferentes. Com a lista completa, alice.github.io é um domínio registrado por si só, e é exatamente isso que o GitHub quer: o site do Pages de um usuário não deve ser same-site com o de outro. Só com as regras da seção ICANN, o domínio registrado é github.io. Qual das duas leituras está certa depende da pergunta que você está fazendo; por isso, a ferramenta mostra as duas sempre que quem decidiu o resultado foi uma regra da seção PRIVATE.

Por que a seção PRIVATE existe e o que ela muda

O arquivo tem duas partes. A seção ICANN cobre os sufixos dos registries, ou seja, a hierarquia normal de domínios. A seção PRIVATE é onde as organizações incluem os próprios nomes, e a inclusão é feita a pedido.

O motivo é a hospedagem em subdomínios. Se uma plataforma dá a cada cliente um cliente.plataforma-exemplo.com, então, sem uma entrada na lista, todos esses clientes dividem a mesma origem de cookies e a mesma cota de rate limit para certificados. Um tenant (cada cliente da plataforma) consegue gravar cookies que outro tenant lê, e isso é uma falha real de isolamento entre pessoas que nem se conhecem. Incluir o sufixo na seção PRIVATE transforma cada tenant num domínio registrável próprio, e é isso que resolve o problema.

Isso também traz consequências que quem pediu a inclusão talvez não queira. Ser um sufixo público significa que a plataforma não consegue mais gravar um cookie que valha para todos os seus tenants, e muda o jeito como as autoridades certificadoras tratam pedidos de certificado wildcard e os rate limits. A entrada tem um custo, e é por isso que a lista tem um processo de revisão, e não um botão de upload.

O que dá errado

Lista desatualizada. O que vale não é a lista em si, e sim a cópia compilada dentro de um navegador, de uma biblioteca ou de um appliance. Um sufixo novo só passa a valer onde o arquivo foi atualizado, então o comportamento muda de uma versão de cliente para outra, e um equipamento que quase nunca é atualizado pode estar usando uma fronteira com anos de atraso.

Tratar a lista como autoridade sobre quem é dono de cada nome. Ela diz onde o registro está aberto, não quem é dono de quê. Dois nomes sob o mesmo domínio registrável costumam ser da mesma organização; mas "costumam" não é "sempre", e as decisões de segurança baseadas nessa suposição herdam essa brecha.

Copiar o arquivo para dentro do projeto e esquecer dele. A falha é silenciosa: os cookies ficam com o escopo um pouco errado, um pedido de certificado é recusado por um motivo que ninguém consegue reproduzir, e nenhum log avisa que "sua lista de sufixos públicos está velha".

Supor que existe uma especificação. O comportamento varia de uma implementação para outra, principalmente com wildcards e regras de exceção, e não existe teste de conformidade a que recorrer.

Onde a fronteira aparece, por categoria

  • Navegadores: escopo de cookies, aplicação do same-site, agrupamento de permissões e o trecho da barra de endereços que alguns navegadores destacam.
  • Autoridades certificadoras: rate limits e política de emissão costumam ser contados por domínio registrável, e é por isso que os tenants de uma plataforma dividem a mesma cota até o sufixo entrar na lista.
  • Ferramentas de segurança: agrupamento de consultas DNS, heurísticas de phishing que comparam um domínio registrável com um nome parecido, e qualquer controle que precise dizer "mesma organização".
  • Analytics e publicidade, que precisam da mesma fronteira pelo mesmo motivo que os navegadores; é por isso que a lista tem, sem alarde, uma importância comercial grande.

O que fica é que uma fronteira com tanto impacto não tem nenhum protocolo por trás. É um arquivo mantido por pessoas, e a precisão dele depende de quem envia as entradas e de cada sistema que usa a lista manter a própria cópia atualizada.

Onde a fronteira é usada

Três sistemas dependem do domínio registrado, e errar nesse ponto causa bugs reais e difíceis de entender. Rate limits de certificados: a Let's Encrypt conta os certificados novos por domínio registrado, então todos os subdomínios de um site dividem uma única cota semanal (veja Let's Encrypt). Equipes que emitem um certificado separado para cada subdomínio muitas vezes se surpreendem ao bater no limite. Cookies: um site não pode gravar um cookie para um sufixo público como co.uk, porque isso deixaria um site ler os cookies de outro em todo o sufixo; o que o navegador verifica é justamente a fronteira do domínio registrado. Same-site e : saber se duas URLs contam como same-site, o que define o envio de cookies e algumas proteções cross-origin, é uma decisão tomada na fronteira do domínio registrado, com base na PSL. Nos três casos a regra é a mesma, e a ferramenta de domínio registrado mostra exatamente onde fica essa linha para qualquer nome.