B站无法外链HTML5播放器原因研究

2018年12月31日 0条评论 246次阅读 100分 前端技术

一、研究背景

在本博客打算引用如今热火朝天的各种视频解析接口的时候,站长我发现一个问题。这些解析接口的格式大都是“xxx/?url=yyy”的形式,而对于Blibili视频而言同一个AV号经常对应多个分P,这些分P是通过CID和AID来区分的,而AV号是一模一样的,这样就不能使用常见的视频解析接口了。

后来,我尝试过直接使用B站的外链功能,发现不能切换清晰度,其和其他国内视频站一个德行,一旦点击就会把你引入源站。后来,在偶然访问萌娘百科时,发现其中的页面不仅能正确加载B站的分P还能切换清晰度弹幕功能都是全的能够根据cookie用已登录用户身份发射弹幕。

在萌百看到这么好的东西,我马上就开始了F12查看之旅。后来发现了类似如下的链接:

于是我把这个URL复制到地址栏,激动的心情充斥着我。这个地址没有任何referrer检测,直接访问就能播放。一开始我还以为是缓存或者我浏览器有B站登录的cookie所以被授权观看。我又试了试清空缓存的IE,居然也能播放。兴奋之余,我赶紧把它放进iframe嵌入我的论坛,然而一盆冷水就此泼向我的热情——页面空白。

二、被阻拦的原因


一开始我以为是https导致的跨域或者被block等原因,但无论我怎么尝试都未果,一次次我打算放弃,可是看到直接输地址如此完美的播放有点不舍得。后来我开始忙别的事这件事就一直搁置,直到前一段时间,我重拾这个残局,某度和谷歌搜索均大多只能找到几年前别人说能够正常引用的教学贴,有少数近几年声称失效的疑问但都没有人提供技术引导。遂只好潜下心来F12单步,终于发现了蛛丝马迹。非常可惜的是为了尽快发表我的发现,我还没有针对下述发现找到合适的解决方法,但希望此处的揭露能够给大家一些启发。

话不多说,直接上截图干货:

html5player.html中的js代码

B站万恶的WhiteList

上面第一张图,解释了为什么直接访问能够播放而嵌入iframe就会空白。从代码46行看出,全局变量allow控制着59行的if语句是否新建一个播放器。而47~55行中就是对各种值的判断从而对allow赋值。

首先,程序检测当前窗口的父窗体是否为自己,如果不是且REFERRER_LIST非空则进一步判断。怪不得大窗能播放嵌入不能播放。接下来,如果嵌入了iframe那么就判断这个小窗的referrer,是不是在REFERRER_LIST列表中,如果不在则不允许播放,如果检测不到referrer就进一步检查useragent。想必经常用安卓手机浏览器的人应该对useragent很熟悉吧,经常用其切换手机版和电脑板网页用。这里,B站对手机用户网开一面,我发现安卓和苹果手机的用户代理也能播放但引用的移动播放器,在网页上全屏和单击交互很不自然。

说到这儿,有人会问那么REFERRER_LIST是哪里来的呢?如第二张图,其包含在一个whitelist.js文件中,被html5player.html静态包含,加载时被包含。从图中可以看出,有不少知名公司被写在这个白名单中。究竟是B站名声做大了,这些大公司向B站申请的呢,还是B站为了推广主动跪舔大公司的屁眼这里无从得知,但很明显的事实是这份白名单并未包含本站“*.dahexie365.com”(笑)。

当然,B站的外链限制可能远不及我提到的这些,但是基于其在浏览器地址栏直接输入URL能够正常观看视频并发送弹幕,我有理由相信底层尤其是播放器的js文件没有做进一步的限制,当然这有待进一步的实践。

三、可能的应对方法


首先这里要申明,以下方法我都没有实践过。由于时间仓促,我没有找到真正的破解方法,这一节仅仅给出我的一些猜想,权当是个人笔记仅供启发,以后我空下来也会积极尝试,如果成功也会第一时间发布研究结果。

1.服务器代理法


利用服务端的curl伪造referrer,服务端请求数据然后转发到前端,填入iframe。这个方法不多说,感觉成功率肯定很高,就算有机制检测是否是浏览器发来的,也有办法模拟浏览器请求。但是缺点也是显而易见的,无端多占用了服务器资源,尤其是对于我服务器在海外的来讲访问国内的B站延迟一定不会低,用户多了我入口带宽都可能不够,另外B站也可能对同一IP的短时间多次请求有检测,前端用户多了必然带来后端同一IP多次访问B站从而引发限制。

2.Iframe伪造referrer


这种方法理论上是不可能的,stackoverflow上有人提过类似问题,都被告知不能实现。但是我仍在国外的某网站找到有人成功伪造了paypal的referrer,但是其貌似是通过一个iframe修改父窗体的referrer,利用的是代码注入iframe,在目标网站里注入<a>标签,然后跳转从而实现referrer的。附上连接:https://www.brokenbrowser.com/referer-spoofing-patch-bypass/

3.全局变量监听修改


从第二节的分析中可知,控制B站播放器载入的是一个allow全局变量以及被引入的REFERRER_LIST全局数组。那么作为父页,是否能够通过循环不停地对iframe内js的值的读取,一旦发现allow变化或者REFERRER_LIST非空就清除REFERRER_LIST或者置allow为true,或者干脆修改这些变量的内存指向或值。这种方法非常耗费客户端的资源,但是不会对服务端产生任何影响,而且现在大家电脑配置都不差了,在页面加载初期就算卡也不会太影响用户体验。

4.注入iframe代码法


顾名思义,当iframe加载页面时,注入或者修改其请求到的html代码。但是这会面临一个挑战,即iframe的onload加载事件或者什么其他检测iframe加载的方法是否会先于其内部执行ready的事件。如果iframe加载事件被我检测到前里面的js代码就已经开始跑了,那就错过了修改或注入的时机了。无论是注入代码阻止allow被改写还是阻止判断语句,甚至是在allow赋值时引发错误,比如一开始的“var allow=true”改为”var allow = 1″,一旦赋值前出错了就会跳转到catch语句,从而直接执行下面的语句。(详情参考图1 46~58行的try catch语句块)但是如果这个方法可行,这会是最优解,因为这不仅节省性能而且还能够动态的自定义播放器的样式和行为,因为我可以任意注入代码。并且这些代码都是复用的,即便B站将来修改了其他限制或者接口,只需修改我的注入代码就可以级联让全站视频复活。

5.自己创建一份B站的前端代码


理论上讲,不考虑B站将来的更新(假定更新频率是很慢的,我有足够时间来跟进)把html5player.html的内容一点一点本地化到我的服务器上,反正视频和播放器都是ajax的或者依赖js的静态引用,只要能解决跨域问题就能把代码本土化。这样是最粗暴的方法,以略微增加服务器压力为代价,但本土化后还能改改样式什么也还不错。就是当B站更新接口时,站长维护工作量相对较大。

6.干脆超链接播放


这是最简单粗暴的方法,因为直接访问h5播放器接口能够浏览器满屏播放,实在没办法干脆直接创建一个超链接,点击后浏览器新窗口播放。这么做成功率最高,除非B站以后干脆关闭接口不给大家用了,但缺点是用户体验差,而且可维护性差。

有人说为什么不干脆点击进入B站得了,我想说只要能看不到B站脑残的相关视频和日趋社会主义化的版头,这种区别足够对得起我的努力了。

7.其他方法


这些方法可能不一定管用,但是姑且值得试试,比如:

ajax动态加载法:先用ajax引入B站html5player.html到字符串,然后修改后动态添加到dom里。
视频源解析法:既然html5player.html里面包含了视频真实地址的ajax方法,理论上经过不屑的探索一定能读懂并把对应js引入到我的网站然后找到视频源用自己的ckplayer等播放器播放。
寻找新的视频解析接口:找找有没有针对B站的或者能解决B站分P的解析网站,或者分析一些B站下载插件的前端代码看它们是怎么实现的。

四、结论与展望


通过上述研究,笔者分析了为什么B站H5播放器能够在浏览器URL栏播放而无法嵌入自己的页面。同时针对其已知的限制手段,提出了若干种可能的对抗手段,虽然这些手段都未被检验,但笔者会在将来有空的时候尝试,并且如果成功破解也会第一时间分享研究成果。


弦外之音

纵观B站发展多年,笔者见证了其从小众乐土到人生巅峰再到如今破败不堪、吃相难看的过程。H5播放器外链在过去几年都是没有限制的,而2018年起播放器的种种限制也伴随B站的日趋衰败而增加。那么,B站究竟是如何一步步走向和其他国内视频网站一样的同质化、平庸化、世俗化的道路的呢?是我们变了还是B站变了,详情请期待将来站长我在将来可能会起笔撰写的相关文章,敬请期待!(不知猴年马月会动笔2333)

Please wait...
 

发表评论