两年前,我写过一段代码,防止网页被嵌入框架(Frame)。
<script type="text/javascript">
if (window!=top) // 判断当前的window对象是否是top对象
top.location.href = window.location.href; // 如果不是,将top对象的网址自动导向被嵌入网页的网址
</script>
这段代码是有效的。但是,有一个问题:使用后,任何人都无法再把你的网页嵌入框架了,包括你自己在内。
于是,我今天就在考虑,有没有一种方法,使得我的网页只能被嵌入我自己的框架,而不是别人的框架?
表面上看,这个问题很简单。只要做一个判断:当前框架和顶层框架的域名是否相同,如果答案是否,就做了一个URL重定向。
if (top.location.hostname != window.location.hostname) {
top.location.href = window.location.href;
}
但是,出乎意料的是,这样写是错误的,根本无法运行。你能看出,错在哪里吗?
假定 top.location.hostname 是 www.111.com,而 window.location.hostname 是 www.222.com。也就是说,111.com把222.com嵌入了它的网页中。这时,比较 top.location.hostname != window.location.hostname 会有什么结果?
浏览器会提示代码出错!
因为它们跨域(cross-domain)了,浏览器的安全政策不允许222.com的网页操作111.com的网页,反之亦然。IE把这种错误叫做"没有权限"。进一步说,浏览器甚至不允许你查看top.location.hostname,跨域情况下,一看到这个对象,就直接报错。
那么,代码应该如何修改?
事实上,这提示我们,只要查看top.location.hostname是否报错就可以了。如果报错了,表明存在跨域,就对top对象进行URL重导向;如果不报错,表明不存在跨域(或者未使用框架),就不采取操作。
try{
top.location.hostname;
}
catch(e){
top.location.href = window.location.href;
}
这样写已经正确了,在IE和Firefox中可以正确运行。但是,Chrome浏览器会出现错误,不知为何,在跨域情况下,Chrome对top.location.hostname不报错!
没办法,只能为了Chrome,再加一段补充代码。
try{
top.location.hostname;
if (top.location.hostname != window.location.hostname) {
top.location.href =window.location.href;
}
}
catch(e){
top.location.href = window.location.href;
}
好了,升级版代码完成。除了本地域名以外,其他域名一律无法将你的网页嵌入框架。我的Blog现在就使用这段代码。
==============================
P.S.
除了代码以后,我还有一件事要说。
今年6月5日,在《创业途径:手工杂志》一文的最后,我说:
"喜欢手工的女同学们,建议你们试试。只要你的作品有趣,我帮你在我的Blog上推广。"
结果,真的有女同学找我。Daisy来信说,她和女友做了一本电子杂志《上班族》,希望我帮忙推广。
虽然我对上班这件事一点兴趣也没有,也不觉得这种主题值得做,但是我不想食言,而且我一向觉得,追求梦想的人值得鼓励。所以,欢迎大家阅读。
最后,为了增加点击率,Daisy同学自愿提供了一张生活照。
(完)
colin 说:
杂志做的不错,值得鼓励。
有梦想就有可能!
2010年8月15日 21:40 | # | 引用
ddd 说:
我不能理解不能嵌入别人的框架对你有什么好处?
2010年8月15日 21:48 | # | 引用
ok 说:
这个都不能理解?省流量,省麻烦啊
2010年8月15日 22:38 | # | 引用
Alvan 说:
window.onbeforeunload = function() {
return "请问是否关闭本页面";
}
iframe页面加入该代码后,如果被嵌入页面执行跳转,浏览器就会跳出对话框询问用户是否要关闭页面——如果用户点“否”,那么你的这些努力就都白费了。
防止网页被嵌入框架的代码叫frame killer,上面的这段代码就叫做frame-killer killer
2010年8月15日 22:54 | # | 引用
sophiasmth 说:
你这个想要破解也是很简单的,只能应付一些初级的程序员,无用功
2010年8月15日 23:38 | # | 引用
LuciferByron 说:
电子杂志业不是已经全军覆没了吗
2010年8月16日 11:07 | # | 引用
Daisy 说:
难道是北邮的Daisy学姐!?
2010年8月16日 11:58 | # | 引用
hipboi 说:
本来还想看看,结果放了照片。。。就不想看了 :)
2010年8月16日 13:34 | # | 引用
OceanBan 说:
2010年8月17日 08:49 | # | 引用
Daisy 说:
没关系,我经得起打击。其实准确地说,也不能算是我主动提供照片,是您说为了提高点击量,可能有照片更好。我本来就是对这些小事情都很无所谓的人。无论如何,谢谢一峰帮忙宣传。非常感谢。
我的电子杂志没准有一天也会死掉,但至少我试过了。至少目前身在职场看过的人,很多人还是觉得有可看之处的。
也希望大家用宽容和好奇的心态来看看罗。
2010年8月19日 00:01 | # | 引用
auchan 说:
看看!很不错哦!!
2010年8月19日 14:39 | # | 引用
小扁豆 说:
加油~Daisy :)
2010年8月19日 16:54 | # | 引用
依云 说:
我觉得那个用来看杂志的Flash用户体验非常不好,翻页和阅读都很不方便,也没找到能用的目录。
2010年8月19日 18:30 | # | 引用
yurii 说:
阮兄你好,最近在读《软件随想录》,部分文字我有不同看法,特来与您商榷,比如《大构想的陷阱》(94页)开头:
眼睛的工作方式同页错误(page-fault)机制有类似之处。它运作起来如此完美,以致于你都不会察觉到它是怎么运作的。
译本给“页错误”加了注释:页错误指的是应用程序读取物理内存的某段地址时,其中没有包含数据,导致出错。
我读这句话非常迷惑,结合下文想了很久才明白这里的“页错误”是什么意思:据我估计,此处的page-fault指的是操作系统采用的虚拟页式内存管理机制(而且应用程序并不能直接读取物理内存某段地址,只能通过操作系统读取逻辑地址),用户以为数据都在物理内存中,其实数据是由操作系统根据需要从硬盘调换到内存中的。这样理解,下文说眼睛其实也只能保持对一个小区域的清晰成像,而人却以为自己能清楚看到“整个视野”,就顺理成章了。
所以我建议翻译为:
眼睛的工作方式类似电脑的虚拟页式内存管理机制(注释:虚拟页式内存管理机制是指操作系统并不会把所有数据都保存在物理内存中,而是保存在外存中,程序需要时再调入内存,用户感觉不到这个过程,以为数据是全都在内存中的)。它运作起来异常完美,你都察觉不到真正的细节。
2010年8月20日 14:14 | # | 引用
Ruan YiFeng 说:
其实,我不懂什么叫“页错误”,当时看了网上的解释,也没搞明白。我也觉得应该就是指硬盘虚拟内存,但是不确定,只好按照字面译。如果能够确定,那你的翻译就是对的。
2010年8月21日 06:29 | # | 引用
larz 说:
这段文字的问题看似只有一个点,实则影响了译者翻译全书的方式,也就是译者假定本书的读者层级 - 科班?非科班?
想来Joel这段文字假定读者具有基本的OS概念(大多为科班),因此也就不作解释。而一峰兄非科班出身,这些译注想来是写给非科班的读者看,可惜背景所限,译注的内容反有误导之嫌
要解释页错误,无法靠译注的一两句话就能达成。它是虚拟内存管理机制中重要的一环,不可能只解释一个点,就让读者能理解整个面,结果读者最后还是一知半解。
我觉得与其强迫自己去解释不熟悉的东西,还不如保留原文术语而不多作处理,科班读者一眼即知在说什么(他们更熟悉原文术语,也更有突出性),而非科班的读者可以此查询wiki获得更完整的解释
--
页错误是一个系统信号用来管理虚拟内存。当应用程序读取虚拟内存(物理内存+分页档)的某个页面(某段地址),若此页面不在物理内存中,就产生一个页错误,告诉OS要去分页档取出需求的页面,置入实体内存中。所有流程都由OS在背景处理,用户无须关心。
2010年8月30日 13:56 | # | 引用
Jake 说:
Dr. Ruan,
Greetings! I am sorry for bothering you a bit.
May I know if you have any knowledge if Google will penalize the sites that apply this of your anti-framing code. When checking out on some English tech blogs, they just speculate Google may down-rank the concerned websites but offer no proof that the search engine giant will sure to do so.
Looking forward to your answer and many thanks in advance!
All the best
Yours faithfully,
2010年11月26日 02:32 | # | 引用
lj 说:
《上班族》挂了?就看了个封面
2011年2月18日 14:15 | # | 引用
笨小孩 说:
很好,谢谢,但这种情况下不适用,123.abc.com中框架456.abc.com中的一个页面,也会出错,但是都是自己的二级域名,有什么好办法吗?
2011年3月12日 06:58 | # | 引用
Ruan YiFeng 说:
那只有比较top.location.hostname 和 window.location.hostname的主域名了。
2011年3月12日 22:31 | # | 引用
初桂鑫 说:
你好,为什么访问top.location.hostname存在跨域问题,而访问top.location.href就没有跨域问题呢?
2013年1月23日 16:23 | # | 引用
phplaber 说:
为什么在w3school这个网站上找不到关于top对象的信息?难道这个对象被干掉了么?
2013年7月 6日 23:50 | # | 引用
无与伦比 说:
这段代码好像在狐火和谷歌浏览器下无效啊?
2013年9月25日 11:34 | # | 引用
Chris 说:
1、按照本文最后的结论,top.location.hostname;这一句代码也可以不用了,因为作判断的时候也会执行这一句。
2、至于说Chrome,在执行这句话的时候是有错误信息的,但貌似并没有抛出错误中断执行,更奇怪的是在执行
if (top.location.hostname != window.location.hostname) {
top.location.href = window.location.href;
}
的时候居然继续执行了括号内的跳转操作,怪哉。
3、Alvan说的frame-killer killer其实意义也不大,试想如果用户每次打开盗嵌别人网页的网站时都要点击一个弹出框,那用户还会继续访问该网站吗?也就是说这段代码的作用还是可以达到的。
2013年9月25日 16:26 | # | 引用
Biwood 说:
这个不是吗http://www.w3school.com.cn/htmldom/prop_win_top.asp
2013年12月 8日 20:46 | # | 引用
睡虫子 说:
使用Meta标签来防止被嵌入就好了。
2013年12月25日 11:12 | # | 引用
睡虫子 说:
好吧,我错了,这种方法曾经可以,http-equiv值设定为Window-target现在是用不了的,知识陈旧了。
2013年12月25日 13:28 | # | 引用
马克后生 说:
2014年7月25日 14:59 | # | 引用
skip 说:
不太清楚为什么 top.location.hostname 不能读取,而可以赋值
2014年9月 7日 19:07 | # | 引用
昂帝梵德·纳尔 说:
如果top!=window,直接清空页面就行了。不用跳转,让对方看不到内容。
2015年3月11日 17:15 | # | 引用
simon.xi 说:
2016年1月26日 13:11 | # | 引用
病人 说:
如何能直接联系到你啊,,, 我的网站被嵌入了。。
上面的代码都测试了,,没效果。
而且我把所有的方法都测试了,什么封IP。。。 等等。。
快急死了。。。。
2016年11月20日 19:36 | # | 引用
dreamart 说:
JS代码,服务器端调设置HTTP安全头,阻止域名和IP等等都试了,还是没能阻止嵌套。难道真的就没有办法解决了吗?请大侠进一步指点。
2017年4月29日 08:54 | # | 引用
largegod 说:
2018年3月11日 16:33 | # | 引用
xyuan 说:
时隔十年,很高兴能以这样的方式和你对话,我是一个应届毕业生,受公司技术大牛的影响,来到您的个人网站,看了你的博客,有一种说不出的感觉,具体是什么感觉,不知道。但是鸡汤却很浓,谢谢您
2018年8月18日 19:03 | # | 引用
WQ 说:
我觉得这个主意不错,只有当前页面被嵌入的情况下就满足了top!=window;只是这样也不能被自己域名下的网站嵌入,也要做一些判断
2018年9月13日 09:55 | # | 引用
ghppph 说:
noframe 标签 可以可以呢?
2018年12月 4日 17:01 | # | 引用
ghppph 说:
打错字了,是:可不可以呢?
2018年12月 4日 17:01 | # | 引用
Jerry 说:
我怎么觉得为了点击率,不应该提供那照片呢 ~ haha
2021年4月23日 17:13 | # | 引用
xihu88 说:
十多年前的照片了,跟现在的网红比不了。另外杂志好像也已经停了
2021年6月16日 16:54 | # | 引用