$cache[$key] = empty($arr) ? NULL : $arr; return $cache[$key]; } // 门户 获取需要在频道显示的栏目主题数据 function portal_channel_thread($fid) { global $forumlist; if (empty($fid)) return NULL; $orderby = array('tid' => 1); $page = 1; // 遍历所有在频道显示内容的栏目 $category_forumlist = channel_category($fid); $arrlist = array(); $forum_tids = array(); $tidlist = array(); if ($category_forumlist) { foreach ($category_forumlist as &$_forum) { // 频道显示数据 $arrlist['list'][$_forum['fid']] = array( 'fid' => $_forum['fid'], 'name' => $_forum['name'], 'rank' => $_forum['rank'], 'type' => $_forum['type'], 'url' => $_forum['url'], 'channel_new' => $_forum['channel_new'], ); $forum_thread = thread_tid__find(array('fid' => $_forum['fid']), $orderby, $page, $_forum['channel_new'], 'tid', array('tid')); // 最新信息按栏目分组 foreach ($forum_thread as $key => $_thread) { $forum_tids[$key] = $_thread; } unset($forum_thread); } $tidlist += $forum_tids; } unset($category_forumlist); // 获取属性对应的tid集合 list($flaglist, $flagtids) = flag_thread_by_fid($fid); empty($flagtids) || $tidlist += $flagtids; unset($flagtids); // 频道置顶 $stickylist = sticky_list_thread($fid); empty($stickylist) || $tidlist += $stickylist; // 在这之前合并所有二维数组 tid值为键/array('tid值' => tid值) $tidarr = arrlist_values($tidlist, 'tid'); // 在这之前使用$tidarr = array_merge($tidarr, $arr)前合并所有一维数组 tid/array(1,2,3) if (empty($tidarr)) { $arrlist['list'] = isset($arrlist['list']) ? array_multisort_key($arrlist['list'], 'rank', FALSE, 'fid') : array(); return $arrlist; } $tidarr = array_unique($tidarr); $pagesize = count($tidarr); // 遍历获取的所有tid主题 $threadlist = well_thread_find_asc($tidarr, $pagesize); // 遍历时为升序,翻转为降序 $threadlist = array_reverse($threadlist); foreach ($threadlist as &$_thread) { // 各栏目最新内容 isset($forum_tids[$_thread['tid']]) AND $arrlist['list'][$_thread['fid']]['news'][$_thread['tid']] = $_thread; // 全站置顶内容 isset($stickylist[$_thread['tid']]) AND $arrlist['sticky'][$_thread['tid']] = $_thread; // 首页属性主题 if (!empty($flaglist)) { foreach ($flaglist as $key => $val) { if (isset($val['tids']) && in_array($_thread['tid'], $val['tids'])) { $arrlist['flaglist'][$key][array_search($_thread['tid'], $val['tids'])] = $_thread; ksort($arrlist['flaglist'][$key]); $arrlist['flag'][$_thread['tid']] = $_thread; } } } } unset($threadlist); if (isset($arrlist['sticky'])) { $i = 0; foreach ($arrlist['sticky'] as &$val) { ++$i; $val['i'] = $i; } } if (isset($arrlist['flag'])) { $i = 0; foreach ($arrlist['flag'] as &$val) { ++$i; $val['i'] = $i; } } if (isset($arrlist['flaglist'])) { foreach ($arrlist['flaglist'] as &$val) { $i = 0; foreach ($val as &$v) { ++$i; $v['i'] = $i; } } } isset($arrlist['list']) AND $arrlist['list'] = array_multisort_key($arrlist['list'], 'rank', FALSE, 'fid'); return $arrlist; } ?>Is there a way to check if a native Javascript function was monkey patched? - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Is there a way to check if a native Javascript function was monkey patched? - Stack Overflow

programmeradmin0浏览0评论

For example I loaded a script on some website, and I would like to know if JSON.parse/stringify wasn't monkey patched.

I noticed that if I use toString on the function in Chrome/FF, JSON.stringify.toString, then I get back:

function stringify() {
    [native code]
}

My question is do you think this is a good way to verify if a function was monkey patched? Also would love to hear of any other approaches to this problem.

For example I loaded a script on some website, and I would like to know if JSON.parse/stringify wasn't monkey patched.

I noticed that if I use toString on the function in Chrome/FF, JSON.stringify.toString, then I get back:

function stringify() {
    [native code]
}

My question is do you think this is a good way to verify if a function was monkey patched? Also would love to hear of any other approaches to this problem.

Share Improve this question asked Jul 25, 2016 at 8:15 itayaditayad 2892 silver badges10 bronze badges 2
  • 2 Maybe you can run your own script in a WebWorker and compare the function from within the worker to the function from the main page. – Buzzy Commented Jul 25, 2016 at 11:37
  • @Buzzy how can you do this? If I try to do myWorker.postMessage(Function.prototype.toString); it throws an error. – teg_brightly Commented Dec 21, 2021 at 9:42
Add a comment  | 

5 Answers 5

Reset to default 6

One could easily fake JSON.stringify.toString

JSON.stringify = function() {}
JSON.stringify.toString = function() {return 'ha-ha'}

console.log(JSON.stringify); //ha-ha

A little more robust way would be to use Function.prototype.toString

Function.prototype.toString.call(JSON.stringify)

But really bad monkeypatcher could patch Function.prototype.toString as well :)

Yes, this is the only practical way to check whether or not a native function had been overridden or not.

const isNative = fn => !!fn.toString().match(/\[native code\]/)

console.log(isNative(JSON.stringify));

A more robust solution could use Function.prototype.toString() instead of direct call of fn.toString(), but both are monkeypatchable as well. The joys of JavaScript :)

The spec ( http://www.ecma-international.org/ecma-262/7.0/index.html#sec-function.prototype.tostring ) does not specify the exact string returned for a builtin function :

19.2.3.5 Function.prototype.toString

When the toString method is called on an object func, the following steps are taken:

If func is a Bound Function exotic object, then Return an implementation-dependent String source code representation of func. The representation must conform to the rules below. It is implementation dependent whether the representation includes bound function information or information about the target function. If Type(func) is Object and is either a built-in function object or has an [[ECMAScriptCode]] internal slot, then Return an implementation-dependent String source code representation of func. The representation must conform to the rules below. Throw a TypeError exception. toString Representation Requirements:

The string representation must have the syntax of a FunctionDeclaration, FunctionExpression, GeneratorDeclaration, GeneratorExpression, ClassDeclaration, ClassExpression, ArrowFunction, MethodDefinition, or GeneratorMethod depending upon the actual characteristics of the object. The use and placement of white space, line terminators, and semicolons within the representation String is implementation-dependent. If the object was defined using ECMAScript code and the returned string representation is not in the form of a MethodDefinition or GeneratorMethod then the representation must be such that if the string is evaluated, using eval in a lexical context that is equivalent to the lexical context used to create the original object, it will result in a new functionally equivalent object. In that case the returned source code must not mention freely any variables that were not mentioned freely by the original function's source code, even if these “extra” names were originally in scope. If the implementation cannot produce a source code string that meets these criteria then it must return a string for which eval will throw a SyntaxError exception.

So checking for [Native Code] may or may not work depending on the interpreter. Furthermore, an implementation could well implement builtin functions as normal javascript code.

So in answer to your question, you cannot determine, is a Javascript specified way whether a builtin function has been monkey-patched.

That said it appears that Chrome and Firefox both return the [Native Code] string subject to verification on other implementations that may be a pragmatic solution.

I just wanted to add that, after ES6, all solutions that involve checking "[native code]" are even less reliable because of ES6 proxy traps.

// Example monkey-patching the Fetch API using an ES6 proxy trap
window.fetch = new Proxy(window.fetch, {
    apply(fetch, that, args) {
        const result = fetch.apply(that, args);
        result.then((response) => {
            console.log("Intercepted!", args, response);
        });
        return result;
    }
});

// True
console.log(window.fetch.toString().includes("[native code]"));

// True 
console.log(Function.prototype.toString.call(window.fetch).includes("[native code]"));

For more info, check this answer.

I tried to develop some of the ideas from other replies into a working script - here it is:

https://gist.github.com/mindplay-dk/767a5313b0052d6daf2b135fdecd775f

Paste it into the Chrome (or Edge) console and press ENTER - it'll print out a list of any constructors and class-methods not matching their native counterparts. (It does this by comparing against the native APIs in an iframe - which it creates via document.createElement, so, technically, it's possible to fool it by overriding that method, if you were intending to do so deliberately; this isn't a security tool.)

Note that this currently gives false positives for window.location, window.fetch and window.length - this appears to be because these properties aren't correctly reflected by their native browser implementations? If you know how to fix it, please post a comment.

Here is example output from a site that was incorrectly loading some IE11 polyfills into Chrome:

发布评论

评论列表(0)

  1. 暂无评论