一个月前参加某互联网公司的校招笔试时被问到:该如何实现一个短链接服务?

当时随便写了点和服务器架构相关的东西上去,实际上我并不知道短链接是如何解析的,这两天在实习的时候想起了这个问题,便学习了一下。

目前比较通用的做法是建立一张 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分别访问这个短链接,都能直接弹出窗口。

浅谈短链接以及一种不同的实现方案-LMLPHP浅谈短链接以及一种不同的实现方案-LMLPHP

这只是很简单的一个例子,当然前提是网站存在漏洞,现在无论是微信、短信、朋友圈到处都是这样短链接,安全性可能不是很好。

但从好的方面来想,短链也隐藏了长链中的Get参数和一些路径信息,不过实际上最后也会跳转得到长链,所以也没什么用,可能对于爬虫而言有一定隐蔽性,原本某些直接解析Url就能得到的信息可能需要再经过一次请求才能拿到,一定程度上增加了时间成本。

三、一些个人对短链接改进的想法

最直接的办法就是在现有基础上对长链接建立一种有效的安全性校验,以上例子中的长链接就无法通过百度的短链接生成校验,如下图。

浅谈短链接以及一种不同的实现方案-LMLPHP

作为一个还没毕业的学生,没办法对安全校验的设计提出建议,但显然网络上部分短链接网站没有去考虑安全性的问题,这些网站从臭鱼烂虾便乘了真实臭鱼烂虾。

另外一个方法是,制定一个通用的短链生成协议,无论什么短链接都能用同一套方法解析出原始地址,对用户也更透明一些,这样也有另一个好处,服务器在执行解析的时候无需比对数据库就可以直接给出原始地址,一些数据统计放到异步处理,对用户而言也提升了那么一丢丢响应速度。

但这种协议从设计上来讲很难,因为要想对所有人透明,实际上是一个信息的压缩与解压过程,任意长度的Url都想压缩到6位左右基本不可能。

直接压缩Url并不可行,那么要保证信息公开透明,又要像现有的短链实现一样做到对长短链的一一对应,似乎区块链是可行的方案。

12-04 22:22