如何使用未知ID清除setInterval定时器?

29

假设有人(坏人)使用 setInterval 设定了一个定时器,但是我们不知道它的ID(我们没有对该定时器返回的对象引用,也不知道其值)

(function(){
  setInterval(function(){console.log('pwned')},
              10000)
})();
有没有什么方法可以清除它?是否有可能以其他方式访问计时器?或者至少在特定的浏览器/ JavaScript 引擎中?
David Flanagan 在他的大型 JSTDG 中也涉及了类似的主题。其中,setInterval() 方法在恶意代码中的使用是索引点之一。
“…一些浏览器检测到重复的对话框和长时间运行的脚本,并给用户选项停止它们。但是,恶意代码可以使用 setInterval() 这样的方法来加载 CPU,并通过分配大量内存攻击您的系统。Web 浏览器没有一般性的方法可以防止这种粗鲁的攻击。在实践中,这不是 Web 上的常见问题,因为没有人会返回到从事这种脚本滥用的站点!”

2
相关 - https://dev59.com/kHA75IYBdhLWcg3wuLnD - Shadow The Spring Wizard
嗯...另一个想法-他们是否给这个函数起了名字? - Shadow The Spring Wizard
Shadow Wizard,在这种情况下,它不幸地被设置在闭包中(有时被认为是用于安全目的的好功能)...我知道,这个问题有点理论化,因为我们可能可以在大多数情况下在某些浏览器中找到并编辑恶意代码。 - mykhal
Shadow Wizard..嗯,也许它不完全是闭包。但它是一个匿名函数,被执行了。拥有对该函数的引用会在某种程度上帮助我们吗? - mykhal
是的,你可以(至少在理论上)覆盖函数并放置自己的函数和代码。使用相同名称声明的最后一个函数将在运行时执行。 - Shadow The Spring Wizard
5个回答

53

从快速测试结果来看,所有主要浏览器(最新版的Chrome,Firefox和IE)都会为ID生成相对较小的数字,因此仅盲目循环所有可能的数字就可以正常工作:

根据测试结果,在所有主流浏览器(包括最新版的Chrome、Firefox和IE)中生成的ID数字都比较小,因此只需要简单地循环所有可能的数字即可:

function ClearAllIntervals() {
    for (var i = 1; i < 99999; i++)
        window.clearInterval(i);
}

完整的示例:

window.onload = function() {
    window.setInterval(function() {
        document.getElementById("Tick").innerHTML += "tick<br />";
    }, 1000);
    window.setInterval(function() {
        document.getElementById("Tack").innerHTML += "tack<br />";
    }, 1000);
};

function ClearAllIntervals() {
    for (var i = 1; i < 99999; i++)
        window.clearInterval(i);
}
#Placeholder div { width: 80px; float: left; }
<button type="button" onclick="ClearAllIntervals();">Clear All</button>
<div id="Placeholder">
    <div id="Tick"></div>
    <div id="Tack"></div>
</div>

这将停止所有间隔,当然,如果不知道它的ID,就无法停止特定的间隔。

正如您可以自行测试的那样,它应该在上述所有主要浏览器上运行。


请查看我在Hans B PUFAL的回答下面的评论 :) - mykhal
我的方法即使在代码的不同点激活了许多间隔,也能够正常工作 - 然而,显然汉斯的方法更加优雅和高效。 - Shadow The Spring Wizard
2
有点晚了 - 需要注意的是,setIntervalsetTimeout使用相同的ID池,因此这也会取消任何setTimeout - kristiyan.mitev

13

实际上在Chrome中的试验表明setInterval返回一个数字,每次调用都会增加。因此,如果你确定你的setInterval是最后一个设置的,以下代码将起作用:

function clearLastInterval () {
  var i = setInterval (function () {}, 10000);
  clearInterval (i-1);
  clearInterval (i);
}

不过我不确定我会推荐这样做。


1
这是一种可能的方式 :) 像 pauseInterval 这样的东西对于手动查找适当的计时器会很有帮助,因为我们不想杀死无辜的计时器。 - mykhal

8

我尝试了#Shadow Wizard提出的方法,它可以清除间隔。然而,这种方法在之后会有副作用。在我的特定情况下,我清除了所有间隔后无法使用jquery.fadeTo()。

我采用的方法是更清晰的解决方案,即重新定义setInterval方法并在重新定义的方法中保存间隔ID。如下所示,我将ID放入数组中,然后清除所有ID。通过对存储数组的结构进行更多的细化,您可以对其进行标记并进行有选择地清除。

var intervalTracking = new Array();
var intervalCount=0;

window.oldSetInterval = window.setInterval;
window.setInterval = ( function(func, interval) {
    var interval = oldSetInterval(func, interval);
    intervalTracking[++intervalCount]=interval;
    return interval;
});

function clearAllIntervals() {
    for (var i = 0 ; i <= intervalCount ; i++) {
    window.clearInterval( intervalTracking[i] );
    }
}

这似乎有效!


0

var last;
function clearAll() { while(last >= 0) window.clearInterval(last--); }
last = setTimeout(clearAll,1);

这与Shadow的答案有相同的注意事项。我认为它更有效率,可以防止超过第100,000个的超时和间隔。


-1

我通过使用本地存储来解决这个问题,将setInterval的id保存在那里,然后稍后再获取它以清除该间隔。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接