在瀏覽網頁時,我們時常透過 subdomain 來區分服務的內容,例如:
- music.youtube.com/ → 到 YouTube Music
- youtube.com → https://www.youtube.com/ → 到 YouTube
很顯然地,因為 domain name 是 youtube.com,我們可以很快得知這兩個網域都是由 YouTube 所擁有,也因此我們可以信任裡頭的內容,安心瀏覽。那麼我們應該怎麼判斷兩個網域是否屬於同一個擁有者呢?判斷 URL 是否包含 youtube.com 字串嗎?
很顯然地,這並不是一個有效的區別方法,舉例來說:
- youtube.kalan.dev
- youtube.com.kalan.dev
這兩個子網域雖然都包含了 youtube 字串,但我們很快就可以得知它並不是 YouTube 所擁有的網域。
因此子網域的判別方式應該由右至左開始找起,而非從左至右。判別子網域對於軟體工程師來說輕而易舉,但對於不懂 domain 運作機制的人來說,透過子網域釣魚容易讓人掉入陷阱。
第二問題來了,從右至左要找幾個部分?以 blog.kalan.dev
來說,domain name 為 kalan.dev
,程式碼可以這樣寫:
const host = 'blog.kalan.dev'.split('.').reverse().slice(0, 2).reverse().join('.')
然而這並不是一個相當正確的寫法,舉例來說:
- ebay:www.ebay.co.uk
- google:www.google.co.uk
如果以剛剛的寫法來看,那麼 co.uk 會是 domain name,www.ebay 跟 www.google 則是 subdomain,所以兩個網站都屬於 .co.uk?很顯然這樣區別是錯誤的,ebay 是 ebay;google 是 google,兩個 domain 屬於完全不同的公司所有。原因在於國家代碼一級網域搭配二級網域也會被當作獨立的 domain name 使用。因此在這邊正確的解析方式是將 google.co.uk
與 ebay.co.uk
視為兩個獨立的 host,擁有者也完全不同。
TLD(Top Level Domain)
是時候來談談頂級域名了。像是 .io
、.dev
1、.org
等後綴,這些域名都是由 ICANN 管理的,每個人都可以申請自己的網域,像是我的 kalan.dev
就是以 .dev
為後綴組合而成的網域。
ccTLD(Country Code top-level Domain)
根據地區也有對應頂級域名可以使用,像是 .tw
或是 .jp
。要注意的是有些 country code 與其他二級域名搭配時,也會單獨形成一個網域,像是:
在這兩個網站當中,momoshop.com.tw 與 books.com.tw 為網域名稱,而 www.momoshop.com.tw 與 www.books.com.tw 則是其子網域。
eTLD(effective top-level domains)
從以上幾個例子可以發現,有些頂級網域可以跟二級網域搭配變成一個網域名稱(例如 kalan.dev
),而有些則是兩個域名集合起來變成一個頂級網域(.com.tw
),瀏覽器要怎麼知道如何解析呢?這背後的概念是透過維護一個巨大的 Public Suffix List(PSL)列表,在裡頭列出的網域名稱就被稱作 effective top-level domains(eTLD),列表可以在這裡取得。
另外一個常見的名詞則是 eTLD+1,代表有效頂級域名+一個二級域名會形成一個網域,在本範例當中 .com.tw
為有效頂級域名,而 momoshop 則是二級域名。
SameSite 對前端應用的意義
網域的運作機制對於前端最大的意義在於 SameSite2 的判斷,我們想要知道兩個網站是否為 SameSite,因為在 SameSite 的情況下網站的 Cookie 是共享的(在沒有特別設定 header 的情況下)。
因此給定兩個網站 URL,kalan.hacker.com
跟 jack.hacker.com
,請問這兩個 URL 是否為 SameSite?乍看之下兩個 URL 很像 hacker.com
的 subdomain,但看完剛剛的例子與說明,我們應該先看看 hacker.com
有沒有在 public suffix list 裡才能做判斷。
如果對 cookie 與 Samesite 的討論有興趣的話,也可以參考我之前寫的文章關於 Cookie 與 CORS 的再思考
以 GitHub 舉例
在 GitHub 當中,可以透過 Repository 的設定免費生成 xxx.github.io
的網域 ,像是我的舊部落格:kjj6198.github.io/blog
。在這種情況下,我們可不希望每個 xxx.github.io
的 cookie 都可以互相存取。對於這類型的應用來說,我們希望的是每個 xxx.github.io
都是一個獨立的網域,而不是 .github.io
的子網域,透過 eTLD 可以有效解決這個問題,查看 public suffix list 也確實可以找到 .github.io
的存在。
誰可以申請 Public Suffix List?
從 publicsuffix 的官方文件看起來,只要按照官方的規定發個 PR 就可以了,只是整個流程看起來需要花些時間,而且從過往的 PR 看起來都是人工審核。
談談瀏覽器的地址欄
我的 blog.kalan.dev
在 Firefox 跟 Edge 的地址欄上面的顯示如上圖,上面是 Firefox 的顯示,下面是 Edge 的顯示。
有觀察出來差異了嗎?blog
文字在 Edge 當中顏色和 kalan.dev
是一樣的,但是在 Firefox 當中 blog
的文字比較淡一點。Firefox 的地址欄只會將網域名稱的顏色強調出來,而 Edge 以及 Chrome 則是將網域部分(包含子網域)也一起強調出來。在這個例子當中,透過 Firefox 的地址列我可以很快知道 blog 是 kalan.dev 的一個子網域。
這個差異雖然很小,但是當網域含有 eTLD 時 Firefox 的地址欄功能就相當有用,例如 kjj6198.github.io
,由於 .github.io
為 eTLD,所以整個 kjj6198.github.io
是一個網域。
下次如果有人問你兩個網域是不是 Samesite 的話,最好的方法就是打開 Firefox 輸入網址,看看兩個 URL 強調的部分是不是一樣,如果是的話我們可以很有信心地說他們是 Samesite 了!