从拼夕夕砍一刀链接漫谈微信落地页防封

3,100 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情

写在前面

最近v2ex上一个话题火了,大概内容是有一个 好奇 摸鱼的程序员,在分析了拼夕夕发出的砍一刀短链接后,惊呼不可能。

image.png 是什么让一个见多识广的程序员如此惊讶呢?问题就出在拼夕夕发出的短链接上,经过测试发现,在微信内打开的短链,会出现二维码的页面,而在pc端浏览器打开时,则出现的另外一套界面。是什么导致了这样的情况呢?

微信落地页防封

谈到拼多多的短链分享,就不得不提一个很关键的名词微信落地页防封 ,说到微信落地页防封,那就需要知道,在什么情况下,会触发微信的域名拦截机制,一般来说,触发域名拦截有以下几个原因

  • 域名是新购入的老域名,在微信内之前有过违规记录,上过黑名单。

  • 网站流量太大,微信内同一域名被大量分享,比如分享赚类的平台某拼。

  • 诱导分享传播,即便是合法营销活动,也会触发拦截。

  • 网站内容违规,这个不必多说。

  • 被同行恶意举报。

为了让域名活的久一些,微信落地页防封这样的技术就应运而生,主要通过以下几点,来逃避微信的域名拦截机制

  • 大站域名【美团、京东...】
  • 不同主体各自备案域名【鸡蛋不放在一个篮子内】
  • 多级跳转+前置防火墙【通过前置防火墙中转页识别是否是机器扫描】
  • 随机Ip【cdn分发】
  • 图床 + 短链
  • 短链 + 自定义跳转 【稍后详细分析一下这种方式】

拼夕夕的防封技术猜测

经过测试,拼夕夕的防封应该采用的是图床+短链+自定义跳转的方式,接下来就听我一一道来

  • 图床 图床是oss对象存储的昵称,通常是用来存放图片的,如果是用在防封里,那他其实是将一个html页面上传进了图床内,至于是怎么上传进去的。很简单啊,你只需要有一个阿里云,京东云,腾讯云的账号,购买了oss对象存储服务,设置公共读私有写,就可以访问了,这些不重要,你只需要知道图床所存储的是html就可以了。

我通过chrome的控制台抓取了通过短链转换而来地址,然后抓到了如下请求

  • 短链重定向

image.png 注意看第一个请求,第一个请求就是短链的自定义跳转,短链自定义跳转我们下一节详细去说,通过301重定向,将我们重定向到了图床的地址

  • 图床ua、地域、等判断 图床内的html包含了对ua、地域、设备类型等的判断,不同的环境所打开的内容是不同的,通过对环境的判断,展示不同的内容去屏蔽微信的扫描,拼夕夕就是通过这样的方式来实现落地页防封的 下面是我从落地页中拿到的一个函数,虽然我们很难完全还原这个函数,但是通过里面没被混淆的常量比如ke.HUAWEIke.OPPO等不难看出来,这是一个判断当前手机品牌的函数,针对不同的品牌下的浏览器,会做一些特殊的处理。
 const t = e(u().mark(function t (e) {
  let r, n, o, i, c, s
  return u().wrap(function (t) {
    for (; ;) {
      switch (t.prev = t.next) {
        case 0:
          if (r = e.brand,
          n = e.payload,
          o = a()(n, 'data', {}),
          i = a()(n, 'isThirdBrowser'),
          c = a()(n, 'data.fastAppDomains', ''),
          s = Te(o),
          Pe(o),
          !i) {
            t.next = 8
            break
          }
          return t.abrupt('return')
        case 8:
          if (r !== ke.HUAWEI) {
            t.next = 11
            break
          }
          return t.next = 11,
          R(c, {
            cTime: s,
            data: o
          }).catch(fn)
        case 11:
          if (r !== ke.OPPO) {
            t.next = 27
            break
          }
          if (!j(A.OppoLeftScreen, o)) {
            t.next = 17
            break
          }
          return t.next = 15,
          R(c, {
            cTime: s,
            data: o
          }).catch(fn)
        case 15:
        case 20:
          t.next = 27
          break
        case 17:
          return t.prev = 17,
          t.next = 20,
          sn(c, {
            cTime: s,
            data: o
          })
        case 22:
          if (t.prev = 22,
          t.t0 = t.catch(17),
          !j(A.banBrowserV2, o) && !j(A.oppoQAppPriority, o)) {
            t.next = 27
            break
          }
          return t.next = 27,
          R(c, {
            cTime: s,
            data: o
          }).catch(fn)
        case 27:
          if (r !== ke.VIVO) {
            t.next = 30
            break
          }
          return t.next = 30,
          sn(c, {
            cTime: s,
            data: o
          }).catch(fn)
        case 30:
        case 'end':
          return t.stop()
      }
    }
  }
  , t, null, [[17, 22]])
}
))

再注意看接下来的一段代码片段,很明显针对上面获取到的手机品牌,会生成不同的图片,注意看下面混淆过的c函数,x.brandType, brand有品牌的意思,也就是上面函数获取到的手机品牌

o = new Promise((function(t) {
var r, o = document.createElement("img"), i = k(n), c = (f(r = {}, x.brandType, 1),
f(r, E.funcParams, i),
r), u = a()(e.split(","), "0");
o.onload = function(e) {
    var r = a()(e, "path[0]") || a()(e, "target")
      , n = gn(r);
    t({
        brand: n,
        img: r
    })
}
,
o.onerror = function() {
    t({
        brand: ke.OTHERS
    })
}
;
var s = S(u).href;
o.src = m(c, s)
}
)),

得益于落地页开发者优秀的代码命名习惯,通过下面的片段,isWeChatPlatform,isIOSWeChatPlatform这两个字符串让我们知道落地页里面还有针对微信的一些判断,会判断是安卓还是ios微信

n = a()(r, "data", {}),
i = a()(r, "isWeChatPlatform"),
c = a()(r, "isIOSWeChatPlatform"),
f = a()(r, "data.mqCodeKey", ""),
l = a()(r, "data.websiteDomain", "").replace(/\/$/, ""),
p = a()(r, "data.fastAppDomains", ""),
d = v("image_url"),
h = v(f) || location.href,
!d) {
    t.next = 15;
    break
}

还有落地页内针对UA的判断的实现

((w = t.document),
  (x = w ? w.title : ''),
  (_ = navigator.userAgent.toLowerCase()),
  (S = navigator.platform.toLowerCase()),
  (O = !(!S.match('mac') && !S.match('win'))),
  (A = _.indexOf('wxdebugger') != -1),
  (E = _.indexOf('micromessenger') != -1),
  (I = _.indexOf('android') != -1),
  (T = _.indexOf('iphone') != -1 || _.indexOf('ipad') != -1),
  (P = function () {
    const t = _.match(/micromessenger\/(\d+\.\d+\.\d+)/) || _.match(/micromessenger\/(\d+\.\d+)/)
    return t ? t[1] : ''

通过上面的代码片段,我们得以窥见拼夕夕落地页的逻辑设计,落地页内,至少实现了下面的能力

  • 针对手机品牌的处理
  • 针对安卓与ios系统的处理
  • 针对是否微信的处理

这些代码进一步的验证了我们的猜想,拼夕夕的确是通过oss内的html动态创建元素来规避微信拦截的!下面是短链智能跳转的一个例子,可以帮助大家更好的理解短链推广的内在逻辑

短链与智能跳转

我们以某平台的功能为例,演示如何通过短链实现自定义的跳转

  • 创建短链接

image.png

  • 配置智能跳转

image.png

  • 智能跳转的规则

可以看到,本身规则就支持按平台,按访问环境,按地域去进行智能跳转了,这也是为什么谷歌会想要将UA的信息进行加密或减少所提供的的信息。

image.png

  • 按地域的实现 服务器可以看到当前访问的ip,通过ip去反向推断地域
  • 操作系统、访问环境 是通过判断UA来实现
console.log(navigator.userAgent)
// ua内会包含设备的关键信息,如果是微信浏览器内打开的,会携带微信浏览器特有的ua信息
'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'

结语

技术本身都是为了解决现实存在的问题,技术没有好坏黑白,但是作为一个技术人,我们能做的就是做任何事情的时候,要坚守心中的底线。君子不立危墙之下,尽量少游走在黑白间的灰色地带。