淺談短連結以及一種不同的實現方案
一個月前參加某網際網路公司的校招筆試時被問到:該如何實現一個短連結服務?
當時隨便寫了點和伺服器架構相關的東西上去,實際上我並不知道短連結是如何解析的,這兩天在實習的時候想起了這個問題,便學習了一下。
目前比較通用的做法是建立一張 id , url 的表,id通過自增保證不重複,通過進位制轉換將 id轉換為短鏈,一般有[0-9a-z]的36位或者[0-9a-zA-Z]的62位轉換,一個id對應一個原始Url,例如轉換http://www.A.com/path?q=param 為短連結,首先查詢資料庫中是否有該 url 的記錄 ,若有,直接拿到 id 構成短鏈 ,若沒有,則將進行一次轉換入庫,假設 id 自增到 100001 ,得到36位轉換結果為255t,那麼短鏈結果就為a.com/255t,其中a.com為你自己的伺服器域名,下次有人訪問a.com/255t時,先將255t還原為100001的id ,再通過 id 查表拿到原始 url ,執行一次重定向。
也就是說,並不是隨便一個短鏈 url 傳到伺服器都能被解析的,只有經過轉換得到的短鏈才能被解析成功。
以下為我個人對短鏈的一些看法:
一、效能的角度
基於以上述實現,短連結服務有一個非常明顯的缺點,在簡化 url 的同時,將一次http請求拆分成了兩次。
從效能上講,若解析伺服器出現效能問題,原本可以通過原始長連結快速訪問到的url會因為解析伺服器的問題導致訪問緩慢,甚至超時。另外,不在快取中的短鏈還會經歷一次查表操作,像Mysql這樣的資料庫,百萬資料執行一次簡單的查詢大概也就0.05s左右,加上資料庫連線的一些網路耗時,雖然不大但多少會有一定影響。
二、安全性問題
就拿XSS漏洞來說,在URL裡構造一個指令碼隱蔽性不要太高。
本地Tomcat+test.html
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Short Url Simple Xss</title> <style> .margin_top{ text-align: center; } </style> </head> <body> <div class="margin_top"> <h4 id="echo"></h4> </div> <script src="/resources/js/jquery-3.3.1.min.js"></script> <script> $(function(){ $("#echo").html(GetQueryString("query")); }); function GetQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)","i"); var r = window.location.search.substr(1).match(reg); if (r!=null) return unescape(r[2]); return null; } </script> </body> </html>
通過query=</h4><script>alert("XSS");</script><h4>,閉合前後的<h4>標籤構造js指令碼。
在某短連結生成網站上對URL進行轉換
http://127.0.0.1:8080/test.html?query=%3C/h4%3E%3Cscript%3Ealert(%22xss%22);%3C/script%3E%3Ch4%3E
生成短連結為:
http://suo.im/4G8yTU
現在用Chrome和Edge分別訪問這個短連結,都能直接彈出視窗。
這只是很簡單的一個例子,當然前提是網站存在漏洞,現在無論是微信、簡訊、朋友圈到處都是這樣短連結,安全性可能不是很好。
三、一些個人對短連結改進的想法
最直接的辦法就是在現有基礎上對長連結建立一種有效的安全性校驗,以上例子中的長連結就無法通過百度的短連結生成校驗,如下圖。
作為一個還沒畢業的學生,沒辦法對安全校驗的設計提出建議,但顯然網路上部分短連結網站沒有去考慮安全性的問題,這些網站從臭魚爛蝦便乘了真實臭魚爛蝦。
另外一個方法是,制定一個通用的短鏈生成協議,無論什麼短連結都能用同一套方法解析出原始地址,對使用者也更透明一些,這樣也有另一個好處,伺服器在執行解析的時候無需比對資料庫就可以直接給出原始地址,一些資料統計放到非同步處理,對使用者而言也提升了那麼一丟丟響應速度。