美文网首页让前端飞React Native实践
超简单思路防运营商劫持

超简单思路防运营商劫持

作者: mytac | 来源:发表于2018-11-21 10:43 被阅读2次

有的图片上传不成功点击github原文

不知道大家有没有这样的体验,当你专心浏览网站内容的时候,会从右下角弹出小广告,当你点击关闭的时候,又会跳转到另外的链接,你以为是网站搞的鬼,但你尝试去联系管理员时,人家表示不背这个锅。其实这背后是你的网络运营商在借刀杀人~

市面上常见的运营商劫持主要是http劫持,https劫持和dns劫持。我们经常看到的右下角弹小广告的一般是http劫持,如果将http转为https可以减少被运营商劫持的机率,但也可能会被伪造证书,仍然会被劫持。所以我们需要在自己的程序中设置一个监听器来监控dom中劫持插入的脚本。

思路

需要在运营商插入非法代码之前监听dom变动,以下的例子只检查<script>标签。

step1.挂载dom监听器

主要使用html5的一个特性MutationObserver来观察dom变动,注意兼容性,如果你不打算兼容ie浏览器,MutationObserver是最好的选择。

[图片上传失败...(image-8acba2-1542768178446)]

const observer = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
const isSupportObserver = !!observer
if (isSupportObserver) {
    console.info('The preventor is running...')
    new observer((records) => {
        // ....这里处理dom变动
    }).observe(watchNode, { childList: true, attributes: true })
} else {
    console.error('Your platform is not supported with "window.MutationObserver",please update.')
}

step2.处理dom变动,进行白名单筛选

经过上面的步骤,我们得到了网页中所有的<script>,之后筛选得到运营商注入的脚本信息,进行下一步操作。(你可以设置白名单,根据白名单进行过滤,设置白名单的过程这里不具体展开了,详见文章后面的完整代码。)

records.forEach(record => {
    const addedNodes = Array.from(record.addedNodes)
    addedNodes.forEach((node) => {
    if (node.tagName && ~filterTagList.indexOf(node.tagName.toLowerCase())) {
        const isInWhiteList = whiteRegList.some((reg) => reg.test(node.src))
        if (!isInWhiteList) {
            badInjections.push({ badNode: node, badSource: node.src })
        }
        }
    })
})

step3.处理运营商非法注入

我们在上一步得到的运营商注入的非法脚本,需要进行拦截和处理,最后发给运营商或举报到工信部。(注意这里,在head头部同步插入的脚本无法被监听到)。

badInjections.forEach(({ badNode, badSource }) => {
            badNode.remove(); // 移除非法注入节点
            console.warn(`The source "${badSource}" is invalid,removed it already.`)
})

完整代码

class HijackPreventor {
    constructor(watchNode = Array.from(document.getElementsByTagName('body'))[0],report=()=>{}) {
        this.whiteList = []
        this.whiteRegList = []
        this.filterTagList = ['script']
        this.report = report
        this.setObserver(watchNode)
    }

    /**
     * 设置域名白名单
     * @param {Array|String} list 
     */
    setWhilteList(item) {
        if (item instanceof Array) {
            this.whiteList = item
        } else if (typeof item === 'string') {
            this.whiteList.push(item)
        } else {
            console.error('[HijackPreventor]: Please set an Array or String type parameter to "setWhilteList" ')
            return;
        }
        this.whiteRegList = this.whiteList.map(wl =>
            new RegExp('/.+?\/\/' + wl + '|\/\/' + wl + '|.+?\.' + wl + '|^' + wl)
        )
    }

    /**
     * 挂载dom监听器
     * @param {Node} node 
     */
    setObserver(watchNode) {
        const observer = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
        const isSupportObserver = !!observer
        if (isSupportObserver) {
            console.info('[HijackPreventor]: The preventor is running...')
            new observer((records) => {
                this.filterSafeScript(records)
            }).observe(watchNode, { childList: true, attributes: true })
        } else {
            console.error('[HijackPreventor]: Your platform is not supported with "window.MutationObserver",please update.')
        }
    }

    /**
     * 获取非法注入
     * @param {Node} records 
     */
    filterSafeScript(records) {
        const { filterTagList, whiteRegList } = this
        let badInjections = []
        records.forEach(record => {
            const addedNodes = Array.from(record.addedNodes)
            addedNodes.forEach((node) => {
                if (node.tagName && ~filterTagList.indexOf(node.tagName.toLowerCase())) {
                    const isInWhiteList = whiteRegList.some((reg) => reg.test(node.src))
                    if (!isInWhiteList) {
                        badInjections.push({ badNode: node, badSource: node.src })
                    }
                }
            })
        })
        this.handleBadInjections(badInjections)
    }

    /**
     * 处理非法注入
     * @param {Array} badInjections 
     */
    handleBadInjections(badInjections) {
        badInjections.forEach(({ badNode, badSource }) => {
            badNode.remove(); // 移除非法注入节点
            console.warn(`[HijackPreventor]: The source "${badSource}" is invalid,removed it already.`)
        })
        this.report(badInjections)
    }

    /**
     * 模拟插入script,用来测试
     * @param {Node} appendNode 
     */
    mockHijack(appendNode = document.getElementsByTagName('body')[0]) {
        const node = document.createElement("script");
        node.src = 'https://cdn.bootcss.com/zepto/1.0rc1/zepto.min.js'
        appendNode.appendChild(node)
    }
}

举报方法

按下图方法投诉到工信部,一步到位!

投诉到工信部

参考链接

  1. 干货!防运营商劫持
  2. 【HTTP劫持和DNS劫持】实际JS对抗
  3. MutationObserver

最后请大家关注我的订阅号获得更加及时的推送~

那屋水泡

相关文章

  • 超简单思路防运营商劫持

    有的图片上传不成功点击github原文 不知道大家有没有这样的体验,当你专心浏览网站内容的时候,会从右下角弹出小广...

  • 防止运营商劫持,前端解决办法

    防止运营商劫持,前端解决办法 [toc] 常见的劫持方式: 按照劫持的方法不同,我将劫持分为下面两类: 跳转型劫持...

  • OS X MD5 SHA256 SHA1 文件校验

    在目前的网络状况下,运营商劫持、DNS劫持、CDN劫持都可能发生。劫持就导致了下载foo文件,得到的却是包着foo...

  • 运营商劫持

    大家想必一定遇到过这种小助(guang )手( gao ): 这些广告都是中途被别人暗地里加的,这个别人就是中国特...

  • dns劫持案例1

    【网络可用性上最头痛的问题是DNS劫持,前文讲到了DNS劫持方面除了恶意劫持以外,主要是运营商以节省跨省流量结算费...

  • 运营商劫持原罪

    面对运营商劫持的问题,七牛云也只能让客户去工信部投诉。 所有联网的设备数据流量都要经过运营商,这么大数据量下的金子...

  • 网页广告

    有一些网页会出现代码里没有的广告,无法去除。 原因:1.运营商劫持。 让客户自己打运营商电话投诉。 ...

  • http网络劫持与DNS劫持

    DNS 劫持原理 一般而言,用户上网的DNS服务器都是运营商分配的,所以在这个节点上,运营商可以为所欲为。例如,访...

  • 运营商劫持的问题

    网站有时候会莫名其妙的出现广告 (如下图) 这是被运营商劫持了 一般都是引用的百度统计js或微信的jssdk文件被...

  • 运营商广告劫持追查

    最近发现,手机上网经常弹出广告, 如下图所示 于是开始对其进行追踪. 追踪过程如下: 最终的广告页在是这个 可以看...

网友评论

    本文标题:超简单思路防运营商劫持

    本文链接:https://www.haomeiwen.com/subject/yvuqqqtx.html