1.介紹
InternetDomainName
是用於解析和操作域名的有用工具。它可以用作驗證器、組件提取器以及用作以類型安全的方式傳遞域名的值類型。
然而,InternetDomainName
行爲的某些方面可能令人吃驚,並且可能導致調用代碼中的錯誤。本文檔解決了這些問題。
2.細節
2.1公共後綴和私有域名
根據相關的RFC規範,可以保證InternetDomainName
對象在語法上是有效的,但不能保證它與Internet上的實際可尋址域相對應。如果不對域進行網絡查找並嘗試與它聯繫,就不可能做到這一點,對於大多數常見情況而言,這是不可接受的開銷。
儘管如此,確定給定域名是否可以代表Internet上的實際域名通常非常有用。爲此,我們使用來自公共後綴列表(Public Suffix List (PSL))的數據,該列表由Mozilla Foundation維護。InternetDomainName
上有一些方法可以確定給定域名與PSL的關係。用最基本的術語來說,如果domain.hasPublicSuffix()
返回true,則該域可能對應於一個真實的Internet地址;否則,幾乎可以肯定不會。
在這一點上,我們需要備份並定義一些術語。有四個興趣條款:
- 頂級域名(Top-Level Domain (TLD)):沒有子域的單標籤域,例如
com
或au
。 - 註冊表後綴:由域名註冊機構(例如Verisign for
com
)控制的域名(例如com
或co.uk
),人們可以在該域名下通過域名註冊機構(例如Namecheap)註冊子域名。此類域名註冊受互聯網監管機構(如ICANN)的法律保護。 - 公共後綴:此類別是註冊表後綴的超集,另外還包括不受註冊表控制但允許公衆註冊子域的後綴(例如
blogspot.com
)。在幾種常見情況下,更適合按公共後綴而不是註冊表後綴對域進行分類。例如,永遠不要在公共後綴上設置cookie。 - 有效的頂級域:“公共後綴”的已棄用同義詞。
在繼續之前值得仔細閱讀鏈接中的文章。
造成混淆的一個主要原因是人們說“ TLD”是指“註冊後綴”還是“公共後綴”。所有這三個都是獨立的概念。例如:
com
是這三個部分:一個TLD,一個註冊後綴和一個公共後綴au
是TLD,但不是註冊表後綴或公共後綴com.au
是註冊表後綴和公共後綴,但不是TLDblogspot.com
是公共後綴,但既不是註冊表後綴也不是TLDsquerf
不是這三個中的任何一個
這種混淆尤其危險,因爲TLD和註冊後綴具有明確的正式定義,而公共後綴則沒有。最後,一個可靠的消息來源要求PSL維護者將公共後綴添加到列表中。可信來源包括ICANN和國家/地區域管理者,但還包括提供服務的私營公司,這些服務具有(模糊地)定義了公共後綴的特徵——獨立的子域和超級cookie抑制。例如,PSL中包含許多Google擁有的域(例如blogspot.com
)。
回到InternetDomainName
,只要我們限制使用hasPublicSuffix()
來驗證該域是一個合理的Internet域,一切都很好。這種危險來自識別或提取“頂級私有域”的方法。從技術角度來看,頂級私有域只是公共後綴之前最右邊的超級域。因此,例如,www.foo.co.uk
的後綴爲co.uk
,頂級私人域爲foo.co.uk
。
正如有關isUnderPublicSuffix()
、isTopPrivateDomain()
和topPrivateDomain()
的文檔所述,這些方法(大多數)唯一可靠的是確定可以在哪裏設置Cookie。但是,許多人實際上想做的是從子域中找到“真實”域或“所有者”域。例如,他們希望在mail.google.com
中將google.com
標識爲所有者域。所以他們寫
InternetDomainName owner =
InternetDomainName.from("mail.google.com").topPrivateDomain();
…當然,所有者最終以google.com
域爲域名。事實上,這種習語(以及類似的習語)在很多時候都起作用。它看起來很直觀,“公共後綴下的域”在語義上應等效於“所有者域”。
但這不是問題所在。考慮出現在PSL中的blogspot.com
。儘管它具有公共後綴的特徵——人們可以在其下注冊域名(用於其博客),並且不應該在它上面設置cookie(以防止跨博客cookie惡作劇),它本身是Internet上的一個可尋址域(在撰寫本文時,該域恰好重定向到blogger.com
,但這很容易更改)。
因此,如果在foo.blogspot.com
上使用上述習語,所有者將是相同的域foo.blogspot.com
。對於許多常見應用程序來說,這是cookie設置的正確答案,但是對於許多人來說,這顯然是令人驚訝的。
對於那些實際上旨在確定從註冊表購買的域名的稀有應用程序,正確的抽象不是公共後綴,而是註冊表後綴。如果我們更改上面的代碼以對註冊表後綴使用並行方法:
InternetDomainName owner =
InternetDomainName.from("foo.blogspot.com").topDomainUnderRegistrySuffix();
…然後我們最終將所有者設置爲blogspot.com
。
這張表格方便的總結了各種後綴類型之間的區別:
InternetDomainName |
publicSuffix() |
topPrivateDomain() |
registrySuffix() |
topDomainUnderRegistrySuffix() |
---|---|---|---|---|
google.com |
com |
google.com |
com |
google.com |
co.uk |
co.uk |
N/A | co.uk |
N/A |
www.google.co.uk |
co.uk |
google.co.uk |
co.uk |
google.co.uk |
foo.blogspot.com |
blogspot.com |
foo.blogspot.com |
com |
blogspot.com |
google.invalid |
N/A | N/A | N/A | N/A |
這裏的主要經驗是:
- TLD、註冊表後綴和公共後綴不是一回事。
- 公共後綴是由人類定義的,用於嚴格限制的目的(主要是域驗證和超級cookie預防),並且變化是不可預測的。
- 給定域與公共後綴的關係,該域對Web請求的響應能力以及該域的“所有權”之間沒有定義映射。
- 從ICANN風格的域名註冊的角度來看,註冊後綴可以幫助你確定域名的“所有權”;但是對於大多數應用程序,此信息不如公共後綴適用。
- 你可以使用
InternetDomainName
來確定給定的字符串是否代表Internet上的合理可尋址域,並確定域的哪一部分可能允許設置cookie。 - 你不能使用
InternetDomainName
來確定在Internet上是否存在作爲可尋址主機的域。
請記住,如果你不聽從這個建議,你的代碼似乎可以在各種各樣的輸入上工作…但是失敗案例都是等待發生的所有錯誤,隨着PSL更新被合併到InternetDomainName
基礎代碼中,失敗案例的集合將發生變化。