谈谈JS中的函数劫持

8

说到劫持,第一反应可能是什么不好的东西。函数劫持并不邪恶,关键是看使用的人。虽然这个概念在前端领域使用较少,但是在安全领域、自定义业务等场景下还是有一定的使用价值的。所以,这一篇文章将会和大家一起去了解一下JS中的函数劫持是什么,有什么用。

基本概念

函数劫持,顾名思义,即在一个函数运行之前把它劫持下来,添加我们想要的功能。当这个函数实际运行的时候,它已经不是原本的函数了,而是带上了被我们添加上去的功能。这也是我们常见的钩子函数的原理之一。

乍一看上去,这很像是函数的改写。函数的改写也可以理解为是函数劫持的一种,但是这种方式太恶心了。作为一个劫持者,在绑票获得好处以后也应该遵守职业道德,把人原封不动地还回去,所以我们得在合适的地方把函数原本的功能给重新调用回来。

推而广之,其实“劫持”这一概念我们经常会遇到,比方说某网站被运营商劫持了,在浏览该网站的时候会弹出运营商的广告。

举例分析

现在我们来举个简单的例子,劫持一下alert()函数,为它增添一点小小的功能:

let warn = alert
window.alert = (t) => {
    if (confirm('How are you?')) warn(t)
}

alert('Help me...!!!')

可以打开开发者工具尝试一下这个例子,你会发现只有你在confirm里面点击了OK,才会弹出Help me...!!!

接下来我们把这部分的内容封装一下,成为一个通用的函数:

const hijack = (obj, method, fun) => {
  let orig = obj[method]
  obj[method] = fun(orig)
}

首先我们定义了一个hijack函数,它会先把原函数给保存下来,然后执行自定义函数,而原函数将会在自定义函数内部进行调用。

然后我们来劫持confirm()函数:

hijack(window, 'confirm', (orig) => {
  return (text) => {
    alert('HELP ME PLZ!!!')
    if (orig.call(this, text)) {
      alert('YOU SEEMS FINE AND I AM LEAVING, GOOD BYE!')
    } else {
      alert('HOLD ON! I AM COMING!!')
    }
  }
})

这段函数的功能很简单就不详细说明了,直接调用confirm()你就知道了:
codepen例子

反劫持

新建一个页面,打开你的开发者工具控制台,输入alert,你会看到这样的输出:

function alert() { [native code] }

然后使用本文开头的那段代码,把alert()劫持一下,再重新在控制台输入alert,你会看到这样的输出:

function (t) => {
    if (confirm('How are you?')) warn(t)
}

通过上述的例子可以知道,要看一个函数是否被劫持了,只需要直接把它打印出来即可。针对系统原生的函数,[native code]即代表它是纯净无污染的。

函数劫持的作用

除了为函数增加功能以外,还能够利用函数劫持去追踪恶意用户的信息。一般的XSS攻击会先利用alert()等能够输出信息的方法进行测试,这时候我们可以先对原生alert()进行劫持,向其输入追踪信息的代码,最后才把原函数释放出去。当恶意用户在测试alert()的时候就会立即被我们追踪,而他本人却无从察觉。

后记

关于JS的函数劫持,也不是什么新鲜的东西,只是在最近的工作中遇到了这个知识点感觉比较陌生,所以花了一些时间进行了研究,并把结果记录下来。如果发现有什么错漏的地方欢迎指正!

感谢你的阅读,欢迎关注我的专栏,我将不定期分享自己的学习体验,开发心得,搬运墙外的干货。下次见啦!


参考资料:
javascript 函数劫持 | 神奇辉
JavaScript函数劫持- 谢灿勇
Need to hook into a javascript function call, any way to do this?


如果觉得我的文章对你有用,请随意赞赏

你可能感兴趣的

11 条评论
mario0515 · 2016年09月22日

"函数劫持的作用"这部分很感兴趣,不过看的不是很懂,能不能展开详细说明一下这个过程?

回复

喝茶的螃蟹 · 2016年09月22日

其实就是函数重写,window.alert = ()=>{ console.log('劫持'); alert.apply(window, arguments); } 先执行自己的操作conso.log。 再执行原函数alert

回复

jrainlau 作者 · 2016年09月22日

@喝茶的螃蟹 说得对,其实就是函数的改写,我在文章中也说明了

乍一看上去,这很像是函数的改写。函数的改写也可以理解为是函数劫持的一种

所以你可以在改写当中加入你想要的功能,在最后把原本的功能重新还回去即可。

回复

ecmadao · 2016年09月22日

因锤斯艇,涨姿势了

回复

_CRY · 2016年09月22日

曾经 Google 还是非死不可劫持了 Chrome 的 console 功能 (就是敲控制台以执行代码) 用以防止 self-XSS… 其他浏览器的控制台实现是私有的所以逃过一劫。

回复

mengdu · 2016年09月25日

这个在封装jsonp功能时用过,那时候并不知道这个概念

回复

agentuv · 2016年09月26日

没有用啊,如果这样的话
f.toString = function(){return '{ [native code] }'}

回复

Simga · 2016年09月29日

hijack 和 hook 有啥区别?

回复

ishida · 2016年12月12日

感觉就是monkey patch啊 劫持后的反劫持可以使用原生代码再次劫持一回么?

回复

vea · 2017年02月10日

概念不是新概念了,在js上实现还是让人耳目一新……
话说,有指针就会有劫持,无论是什么语言……

回复

jrainlau 作者 · 2017年02月10日

嗯嗯

回复

载入中...