解语阁
一个“高级”架构师的个人博客

2008年8月21日

HTML圆角输入框
Technorati 标签: CSS3,CSS,HTML,圆角

这段时间做项目,美工设计的界面输入框都是圆角的,确实很好看,研究了一下,实现起来真还有些麻烦

firefox,safri,chrome这些浏览器基本都一定程度支持新的CSS3标准,可以用CSS来搞定圆角:

  1: border-radius: 5px; /* css 3标准 */
  2: -moz-border-radius: 5px; /* mozilla */
  3: -webkit-border-radius: 5px; /* webkit */
可是M$的IE就麻烦了, 直道IE9 还没完整支持CSS3,就只能用背景图片法,前后补图法等等,来模拟圆角效果了哭泣的脸
posted @ 2011-09-27 10:15 赵宝刚 阅读(3119) | 评论 (0) | 编辑 收藏
 
Flex 文件上传
Technorati 标签: Flex,Coding,upload,AS3,program,代码
:

上网查了一些资料,摸索着用Flex写了一个 文件上传的工具。没做太多修饰,主要代码贴出来,免得以后忘了

   1:  <!-- filename :flashuploader.mxml -->
   2:  <?xml version="1.0" encoding="utf-8"?>
   3:  <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   4:                  xmlns:c="component.*"
   5:                  width="450" height="450" minWidth="460" minHeight="400" initialize="application1_initializeHandler(event)" layout="absolute">
   6:      <mx:Style source="css/main.css"/>
   7:      <mx:states>
   8:          <mx:State name="TEST">
   9:              <mx:AddChild position="lastChild" relativeTo="{filelist}">
  10:                  <c:uploadFile currentState="UploadError">
  11:                  </c:uploadFile>
  12:              </mx:AddChild>
  13:          </mx:State>
  14:      </mx:states>
  15:      <mx:LinkButton id="selectbutton" x="5" y="5" label="{selectlabel}" click="button1_clickHandler(event)"/>
  16:      <c:CountingVBox id="filelist" x="5" y="36" height="100%" maxCount="{max}"/>
  17:      <mx:Script>
  18:          <![CDATA[
  19:              import component.uploadFile;
  20:              import mx.events.FlexEvent;
  21:              private var filter:Array;
  22:              private var single:Boolean;
  23:              
  24:              private var fileRefs:FileReferenceList;
  25:              
  26:              private var fileRef:FileReference;
  27:              [Bindable]
  28:              private var max:int=10;
  29:              [Bindable]
  30:              private var selectlabel:String="文件上传";
  31:              
  32:              
  33:              
  34:              private function button1_clickHandler(event:MouseEvent):void
  35:              {
  36:                  if (single){
  37:                      fileRef = new FileReference();
  38:                      fileRef.addEventListener(Event.SELECT,singleSelectHandle);
  39:                      fileRef.browse(filter);
  40:                  }else{
  41:                      fileRefs = new FileReferenceList();
  42:                      fileRefs.addEventListener(Event.SELECT,multiSelectHandle);
  43:                      fileRefs.browse(filter);
  44:                  }
  45:              }
  46:              
  47:              private function singleSelectHandle(event:Event):void
  48:              {
  49:                  var file:uploadFile = new uploadFile();
  50:                  file.parentContainer=filelist;
  51:                  //                file.fileRef = FileReference(event.currentTarget);
  52:                  file.fileRef = fileRef;
  53:                  filelist.addChild(file);
  54:                  
  55:              }
  56:              
  57:              private function application1_initializeHandler(event:FlexEvent):void
  58:              {
  59:                  if( parameters.labelselect !=null) selectlabel = parameters.labelselect;
  60:                  if( parameters.ext != null)
  61:                      if ( parameters.type!=null)
  62:                          filter=[new FileFilter(parameters.type,parameters.ext)];
  63:                      else
  64:                          filter = [new FileFilter("Select Files"+parameters.ext, parameters.ext)];
  65:                  
  66:                  
  67:                  if (parameters.single!=null && "true" == parameters.single.toLowerCase()){
  68:                      single = true;
  69:                      max = 1;
  70:                  }else{
  71:                      if (parameters.max !=null )
  72:                          max = parameters.max ;
  73:                      if (isNaN(max)||max<=0 ) max=int.MAX_VALUE;
  74:                  }
  75:                  filelist.addEventListener("EMPTY",restoreSelectButton);
  76:                  filelist.addEventListener("FULL",disableSelectButton); 
  77:                  var prefix:String="http://localhost/fileupload";
  78:                  filelist.urlRequest = new URLRequest(prefix+"/upload.php");
  79:              }
  80:              
  81:              private function multiSelectHandle(event:Event):void
  82:              {    
  83:                  var fileList:Array=fileRefs.fileList;
  84:                  for(var i:int =0;i<fileList.length;i++){
  85:                      
  86:                      var file:uploadFile = new uploadFile();
  87:                      file.parentContainer=filelist;
  88:                      file.fileRef = fileList[i];
  89:                      filelist.addChild(file);
  90:                  }
  91:              }
  92:              
  93:              private function restoreSelectButton(event:Event):void
  94:              {
  95:                  selectbutton.visible=true;                
  96:              }
  97:              
  98:              private function disableSelectButton(event:Event):void
  99:              {
 100:                  selectbutton.visible=false;                
 101:                  
 102:              }
 103:              
 104:          ]]>
 105:      </mx:Script>    
 106:  </mx:Application>
   1:  <!-- filename: component/uploadFile.mxml -->
   2:  <?xml version="1.0" encoding="utf-8"?>
   3:  <mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
   4:             xmlns:c="component.*"
   5:             height="20" width="440" initialize="canvas1_initializeHandler(event)" >
   6:      <mx:states>
   7:          <mx:State name="UploadError" >
   8:              <mx:SetProperty name="label" target="{progressbar1}" value="{errorInfo}"/>
   9:              <mx:SetProperty name="styleName" value="error"/>
  10:          </mx:State>
  11:          <mx:State basedOn="UploadError" name="FileError">
  12:              <mx:SetProperty name="x" target="{image1}" value="317"/>
  13:              <mx:RemoveChild target="{progressbar1}"/>
  14:              <mx:SetStyle name="styleName" target="{label1}" value="error1"/>
  15:              <mx:SetProperty name="toolTip" target="{label1}" value="{errorInfo}"/>
  16:          </mx:State>
  17:      </mx:states>
  18:      <mx:Image x="5" width="16" height="16" source="{fileicon}" verticalCenter="-1" />
  19:      <c:FilenameLabel x="23"  width="160" text="{filename}" truncSize="10" verticalCenter="-1"/>
  20:      <mx:Label x="185" width="64" text="{extname}" verticalCenter="-1"/>
  21:      <mx:Label id="label1" x="251" width="64" text="{filesize}" textAlign="right" verticalCenter="-1"/>
  22:      <mx:ProgressBar id="progressbar1" x="317" width="100" height="16" label="%3%%" labelPlacement="center" maximum="100" source="{_fileRef}"
  23:                      verticalCenter="-1"/>
  24:      <mx:Image id="image1" x="419" width="16" height="16" click="cancle_clickHandler(event)" source="@Embed('icons/cancel.png')" verticalCenter="-1"/>
  25:      <mx:Script>
  26:          <![CDATA[
  27:              import flash.events.MouseEvent;
  28:              import flash.events.ProgressEvent;
  29:              
  30:              import mx.controls.Alert;
  31:              import mx.events.FlexEvent;
  32:              import mx.states.Transition;
  33:              
  34:              private static var MAX_FILE_SIZE:uint =int.MAX_VALUE;
  35:              
  36:              private var _parent:CountingVBox;
  37:              [Bindable]
  38:              private var _fileRef:FileReference ;
  39:              [Bindable]
  40:              private var errorInfo:String="";
  41:              [Bindable]
  42:              private var fileicon:Class;
  43:              [Bindable]
  44:              private var extname:String;
  45:              [Bindable]
  46:              private var filesize:String;
  47:              [Bindable]
  48:              private var filename:String;
  49:              
  50:              
  51:              
  52:              
  53:              public function set fileRef(value:FileReference):void
  54:              {
  55:                  _fileRef = value;
  56:                  filename=_fileRef.name.substring(0,_fileRef.name.indexOf(_fileRef.type));
  57:                  extname=_fileRef.type;
  58:                  var size:uint=_fileRef.size;
  59:                  var unit:String="B";
  60:                  if(size>10240){
  61:                      size/=1024;
  62:                      unit="KB";
  63:                  }
  64:                  if(size>10240){
  65:                      size/=1024;
  66:                      unit="MB";
  67:                  }
  68:                  if(size>10240){
  69:                      size/=1024;
  70:                      unit="GB";
  71:                  }
  72:                  
  73:                  filesize=size.toFixed(0)+unit;
  74:                  fileicon=getFileIconClass();
  75:                  if (checkFilesize()){
  76:                      _fileRef.upload(_parent.urlRequest);
  77:                      _fileRef.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA,upload_complete); 
  78:                }
  79:              }
  80:              
  81:              public function set parentContainer(p:CountingVBox):void
  82:              {
  83:                  _parent = p;
  84:              }
  85:              
  86:              
  87:              private function getFileIconClass():Class
  88:              {
  89:                  [Embed("icons/Unknown.png")] 
  90:                  var unknown:Class;
  91:                  
  92:                  [Embed("icons/doc.png")]
  93:                  var doc:Class;
  94:                                  
  95:                 //其他文件类型
  96:                  
  97:                  if (_fileRef.type == null){
  98:                      return unknown;
  99:                  }
 100:                  
 101:                  var type:String=_fileRef.type.toLowerCase();
 102:                  if (type == ".doc") return doc;
 103:                  if (type == ".docx") return doc;
 104:                  //其他文件类型
 105:                  
 106:                  return unknown;                
 107:              }
 108:              
 109:              private function cancle_clickHandler(event:MouseEvent):void
 110:              {
 111:                  _fileRef.cancel();
 112:                  _parent.removeUploadedFile(_fileRef);
 113:                  _parent.removeChild(this);
 114:                  if (_parent.count<1){
 115:                      _parent.dispatchEvent(new Event("EMPTY"));
 116:                  }
 117:              }  
 118:              
 119:              protected function upload_complete(event:DataEvent):void
 120:              {
 121:                  _parent.addUploadedFile(_fileRef); 
 122:              }
 123:              
 124:              protected function upload_IO_error(event:IOErrorEvent):void
 125:              {
 126:                  errorInfo="UploadError";
 127:                currentState = "UploadError";
 128:                   
 129:              }
 130:              
 131:              private function checkFilesize():Boolean
 132:              {
 133:                  if (_fileRef.size>MAX_FILE_SIZE){
 134:                      errorInfo = "File too Big";
 135:                      currentState = "FileError";
 136:                      return false;
 137:                  }
 138:                  return true;
 139:              }
 140:              
 141:          ]]>
 142:      </mx:Script>
 143:  </mx:Canvas>
 144:   
posted @ 2011-09-27 10:07 赵宝刚 阅读(287) | 评论 (0) | 编辑 收藏
 
千万要避免的五种程序注释方式

 

你是否有过复查程序时发现有些注释毫无用处?程序注释是为了提高代码的可读性,为了让原作者以外的其他开发人员更容易理解这段程序。

我把这些让人郁闷的注释方式归为了五类,同时把写出这些注释的程序员也归为了五类。我希望读了这篇文章后你感觉自己不属于其中的任何一种类型。如果你有兴趣的话可以读一下另外一篇文章 五种程序员(英文),和这篇讲到的五种程序员对比一下。

1. 高傲的程序员

public class Program
{
static void Main(string[] args)
{
string message = “Hello World!”; // 07/24/2010 Bob
Console.WriteLine(message); // 07/24/2010 Bob
message = “I am so proud of this code!”; // 07/24/2010 Bob
Console.WriteLine(message); // 07/24/2010 Bob
}
}

这种程序员是如此的欣赏自己的程序,以至于不得不在每行代码上都署上自己的大名。应该让版本控制系统来提供程序变更的信息,他这样做一眼看去并不能说明谁对这行代码负责。

2. 过时的程序员

public class Program
{
static void Main(string[] args)
{
/* 这段程序已经不再有用
* 因为我们发现千年虫问题只是一场虚惊
* 我们的系统不会恢复到1/1/1900
*/
//DateTime today = DateTime.Today;
//if (today == new DateTime(1900, 1, 1))
//{
// today = today.AddYears(100);
// string message = “The date has been fixed for Y2K.”;
// Console.WriteLine(message);
//}
}
}

如果一段程序不再有用(比如废弃了),那就删了它吧——不要被几行没用的注释搞的程序混乱不堪。即使你可能以后重用这段代码,你也可以使用版本控制系统,用它把你的程序恢复到以前的样子。

3. 天真的程序员

public class Program
{
static void Main(string[] args)
{
/* 这个程序是用来在屏幕上
* 循环打印1百万次”I Rule!”
* 每次输出一行。循环计数
* 从0开始,每次加1。
* 当计数器等于1百万时,
* 循环就会停止运行
*/
for (int i = 0; i < 1000000; i++)
{
Console.WriteLine(“I Rule
!”);
}
}
}

基本的编程语法规则我们大家都知道——我们不需要“编程入门”。你不需要浪费时间来解释一个显而易见的东西,我们更希望知道的是你的程序功能——那是浪费空间了。

4. 传奇的程序员

public class Program
{
static void Main(string[] args)
{
/* 有一天我在大街上的一家星巴克里
* 和销售部的Jim讨论问题,他告诉我
* 销售代表是依据以下的比例提取佣金的。
* 周五: 25%
* 周三: 15%
* 其它日期: 5%
* 我是否告诉你过我点了一个卡拉梅
* 铁咖啡和两份的Espresso?
*/
double price = 5.00;
double commissionRate;
double commission;
if (DateTime.Today.DayOfWeek == DayOfWeek.Friday)
{
commissionRate
= .25;
}
else if (DateTime.Today.DayOfWeek == DayOfWeek.Wednesday)
{
commissionRate
= .15;
}
else
{
commissionRate
= .05;
}
commission
= price * commissionRate;
}
}

如果你不得不在注释里写明需求,那也不要提到人名。销售员Jim很可能在公司里不再是销售。而且大多数读到这段注释的程序员未必都知道Jim是谁。你描述的是实际情况但跟我们的内容不相干,所以就省掉吧。

5. 未来程序员

public class Program
{
static void Main(string[] args)
{
//TODO: 将来我会修复这个问题 – 07/24/1995 Bob
/* 我知道这个问题很难解决而且
* 我现在依赖于这个Contains函数,但
* 我以后会用一种更有意义,更
* 优雅的方式打印这段代码。
* 我只是现在没时间。
*/
string message = “An error has occurred”;
if(message.Contains(“error”))
{
throw new Exception(message);
}
}
}

这种注释是一种集大成者,它包含了上面所说的注释的所有问题。TODO注释在一个项目最初的开发阶段是非常有用的,但这个注释看起来是在好几年前的产品程序里的——它证明了程序有问题。如果程序有问题需要解决,马上解决,不要拖到日后再解决。

如果你写过这样的注释,或者是你正在寻找一种最好的注释方案,我推荐你读一读Steve McConnell写的《Code Complete》这本书。这是我推荐给所有程序员必读的六本书中的一种。或者你可以学学如何停止注释你的程序(英文)。

你是否在你的程序里还见到过其它种没有意义的或讨厌的注释?欢迎共享。

英文原文:5 Types of Comments to Avoid Making in Your Code

 

posted @ 2010-08-13 22:32 赵宝刚 阅读(246) | 评论 (0) | 编辑 收藏
 
如何选择最合适的Web开发框架
  开发框架的选择,始终是个仁者见仁、智者见智的事情。尤其是Web层的开发框架,数量非常多,而且各有特色,如:Struts、WebWork、Spring MVC、Tapestry、JSF、WebPage3.0……等等。

  下面先来看看为什么要使用Web开发框架


  一:使用框架的必然性


  框架,即framework。其实就是某种应用的半成品,把不同应用程序中有共性的一些东西抽取出来,做成一个半成品程序,这样的半成品就是所谓的程序框架。


  软件系统发展到今天已经很复杂了,特别是服务器端软件,涉及到的知识,内容,问题太多。在某些方面使用别人成熟的框架,就相当于让别人帮你完成一些基础工作,你只需要集中精力完成系统的业务逻辑设计。这样每次开发就不用白手起家,而是可以在这个基础上开始搭建。


  使用框架的最大好处:减少重复开发工作量、缩短开发时间、降低开发成本。同时还有其它的好处,如:使程序设计更合理、程序运行更稳定等。基于这些原因,基本上现在在开发中,都会选用某些合适的开发框架,来帮助快速高效的开发应用系统。


  了解了使用框架的必然性,下面来看看如何选择,当然我们的话题集中在Web层的开发框架。在谈这个问题之前,先来看看我们在Web开发中究竟需要做些什么工作:


  二:Web层开发的工作


  在J2EE开发中,分层是基本的思想,3层架构或者多层架构早已深入人心,在这里我们就把目光集中到Web层,看看到底Web层开发做了那些工作:


  1:数据展示


  Web层需要从逻辑层获取需要展示的数据,然后以合理的方式在页面进行展示


  2:人机交互


  用户需要从界面上输入数据,在界面上进行按钮点击,进而触发事件,标准的事件驱动模型,然后跟后台进行数据交换,出现新的界面。


  3:收集数据,调用逻辑层接口


  Web层收到用户的事件请求,需要调用相应的逻辑层接口来进行处理,Web层是不会有任何逻辑处理的。调用逻辑层接口,需要传递参数,这时需要收集用户在界面上输入的数据,然后进行组织,组织成为逻辑层接口需要的数据封装形式(通常都是ValueObject)。


  4:根据逻辑层的数据来重新展示页面


  逻辑层处理完了,需要返回数据或信息到界面上。这个时候Web层需要根据返回的值选择合适的页面,然后展示这些数据或者信息。


  从上面可以看出,Web层开发的主要工作集中在展示上,也就是图形用户界面。这一部分是用户直观感受应用程序的窗口,也是用户要求最多的地方,其表现形式也是最丰富的。


  三:Web层开发的步骤


  下面再来总结一下Web层开发的大致步骤(也就是需要开发人员做的工作):


  注意:这里讨论的Web层开发,是不使用任何开发框架时候的开发。


  1:写页面Html,到底有哪些数据需要在界面上表现


  2:每个数据的具体表现形式,如:有的需要表现成为下拉列表,有的需要表现成为单选按钮等。


  3:界面表现形式的逻辑布局,所谓逻辑布局是指某些数据的表现形式应该放在前面,某些应该放在后面;某些放在上面,某些放在下面。如:某个请假
申请的业务,有请假开始时间和结束时间,很明显开始时间的表现就应该排在结束时间的前面。而美工是负责最后页面的美观,一般美工不能动界面的逻辑布局。

  4:完成前面3步,页面的表现形式的大致模样就有了,下面需要来做功能性的开发。第一个就是这些表现形式的值的来源,如:下拉列表显示的值从什么地方来。值的来源方式很多,有数据库中来、固定值、某断程序运行的中间结果、前面页面传递过来等等,当然典型的还是来自数据库。

  好了,确定了值的来源,开发人员就要写代码来获取这些值,然后把这些值赋值到对应的表现形式里面。


  5:还有一些比较特殊,也就是真实操作的是一类值,但是在界面上显示的是另一类值,比如:数据库中有用户编号,到了界面上就得显示用户姓名,但
是所有的操作都是要操作用户编号的。我们把这种情况分做:真实值和表现值,他们有一定的内在联系。这些都是要开发人员去转化和维护的。


  6:接下来就应该开发功能性的事件响应了。用户点击了某个按钮或者触发了某个事件,首先是客户端:数据检测、客户端事件处理;然后提交到服务端,服务端要获取到客户端提交的数据,然后调用相应的逻辑层接口来响应。当然如何写逻辑层的实现这里就不去谈论了。


  7:逻辑层执行完过后,返回数据和信息到Web层,开发人员还需要写代码去处理,选择哪个页面来显示,如何显示这些数据和信息等。


  8:在整个交互的过程中,还必须考虑到如何控制权限,如:某些数据不能显示,某些数据不能编辑等等;同样还需要考虑到消息的配置和国际化等等。这些功能起源于逻辑层,但是实际的控制要到Web层,这些都需要开发人员来控制。


  9:完成了上面的开发步骤,页面基本的功能开发就告一段落,接下来开发人员需要考虑页面美观的问题了。大家可能会说:“不是有美工吗,还需要开
发人员干什么?”。事实上美工多半只能出一个静态页面的美化模版,美工对于一推Java代码和Html的混杂物,多半是没有办法的,更不要说还有一些内容
是动态生成的,美工就更不可能搞定了。还是得开发人员上阵,按照美工给的模版,开始添加Css:class、id、style……


  10:完成上面的开发,基本页面的开发工作就完成了,最后的一个步骤就是把各个页面有机的组织起来,开发应用程序的整体应用导航框架,通常就是菜单,然后把各个功能页面跟菜单结合起来,形成一个完整的应用。


  在这里我们省略了开发期反复的调试过程,仅总结开发的步骤。


  四:选择Web开发框架的目的


  了解了如果没有框架,我们需要做的工作,这对选择框架有非常大的帮助。


  框架,直白点说,就是一个半成品,能够帮我们做一些事情的半成品。


  框架的选择,就是看哪个框架最合适,从而减少开发的工作量,提高开发的效率和质量,并有效减少维护的工作量,最终达到节约综合开发成本,获取更多的收益。


  五:选择Web开发框架的标准


  声明:这里所谈的选择Web开发框架的标准,只是我们的总结和一家之言,并不是放之四海而皆准的真理,请根据您的体会客观的看待我们的总结。


  另外:我们这里更多的讨论业务功能性应用程序的Web开发框架。


  1:选择能够对我们的开发过程提供更多、更好帮助的Web开发框架


  2:Web开发框架的学习一定要简单,上手一定要快,没有什么比使用能得到更深的体会。那些动不动就需要半个月或者一个月学习周期的框架,实在是有些恐怖。


  3:一定要能得到很好的技术支持,在应用的过程中,或多或少都会出现这样或者那样的问题,如果不能很快很好的解决,会对整个项目开发带来影响。一定要考虑综合成本,其实这是目前应用开源软件最大的问题,碰到问题除了死肯文档就是查阅源代码,或者是网上搜寻解决的办法,通常一个问题就会导致1-2天的开发停顿,严重的甚至需要一个星期或者更长,一个项目有上这么几次,项目整体的开发成本嗖嗖的就上去了。


  4:Web开发框架结合其他技术的能力一定要强,比如:在逻辑层要使用Spring或者Ejb3,那么Web开发框架一定要能很容易,很方便的与它们进行结合。


  5:Web开发框架的扩展能力一定要强。在好的框架都有力所不及的地方,这就要求能很容易的扩展Web开发框架的功能,以满足新的业务需要。同时要注意扩展的简单性,如果扩展框架的功能代价非常大,还不如不用呢。


  6:Web开发框架最好能提供可视化的开发和配置,可视化开发对开发效率的提高,已经得到业界公认。


  7:Web开发框架的设计结构一定要合理,应用程序会基于这个框架,框架设计的不合理会大大影响到整个应用的可扩展性。


  8:Web开发框架一定要是运行稳定的,运行效率高的。框架的稳定性和运行效率直接影响到整个系统的稳定性和效率。


  9:Web开发框架一定要能很好的结合目前公司的积累。在多年的开发中已有了很多积累,不能因为使用Web开发框架就不能再使用了,那未免有些得不偿失。


  10:选择开发框架另外要注意的一点就是:任何开发框架都不可能是十全十美的,也不可能是适应所有的应用场景的,也就是说任何开发框架都有它适用的范围。所以选择的时候要注意判断应用的场景和开发框架的适用性。



posted @ 2008-11-14 09:28 赵宝刚 阅读(221) | 评论 (0) | 编辑 收藏
 
XSS攻击防御技术白皮书
  XSS攻击,跨站脚本攻击是一种经常出现在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。XSS攻击将对用户的web安全构成巨大的威胁。
1、什么是XSS攻击

  XSS攻击:跨站脚本攻击(Cross Site Scripting),为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆。故将跨站脚本攻击缩写为XSS。XSS是一种经常出现在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。比如这些代码包括HTML代码和客户端脚本。攻击者利用XSS漏洞旁路掉访问控制——例如同源策略(same origin policy)。这种类型的漏洞由于被骇客用来编写危害性更大的phishing攻击而变得广为人知。对于跨站脚本攻击,黑客界共识是:跨站脚本攻击是新型的“缓冲区溢出攻击“,而JavaScript是新型的“ShellCode”。

  数据来源:2007 OWASP Top 10的MITRE数据

  2007 OWASP Top 10的MITRE数据

  注:OWASP是世界上最知名的Web安全与数据库安全研究组织

  从这张图中我们看到,在2007年OWASP所统计的所有安全威胁中,跨站脚本攻击占到了22%,高居所有Web威胁之首。

  XSS攻击的危害包括

  1、盗取各类用户帐号,如机器登录帐号、用户网银帐号、各类管理员帐号

  2、控制企业数据,包括读取、篡改、添加、删除企业敏感数据的能力

  3、盗窃企业重要的具有商业价值的资料

  4、非法转账

  5、强制发送电子邮件

  6、网站挂马

  7、控制受害者机器向其它网站发起攻击

  XSS漏洞的分类

  XSS漏洞按照攻击利用手法的不同,有以下三种类型:

  类型A,本地利用漏洞,这种漏洞存在于页面中客户端脚本自身。其攻击过程如下所示:

  Alice给Bob发送一个恶意构造了Web的URL。

  Bob点击并查看了这个URL。

  恶意页面中的JavaScript打开一个具有漏洞的HTML页面并将其安装在Bob电脑上。

  具有漏洞的HTML页面包含了在Bob电脑本地域执行的JavaScript。

  Alice的恶意脚本可以在Bob的电脑上执行Bob所持有的权限下的命令。

  类型B,反射式漏洞,这种漏洞和类型A有些类似,不同的是Web客户端使用Server端脚本生成页面为用户提供数据时,如果未经验证的用户数据被包含在页面中而未经HTML实体编码,客户端代码便能够注入到动态页面中。其攻击过程如下:

  Alice经常浏览某个网站,此网站为Bob所拥有。Bob的站点运行Alice使用用户名/密码进行登录,并存储敏感信息(比如银行帐户信息)。

  Charly发现Bob的站点包含反射性的XSS漏洞。

  Charly编写一个利用漏洞的URL,并将其冒充为来自Bob的邮件发送给Alice。

  Alice在登录到Bob的站点后,浏览Charly提供的URL。

  嵌入到URL中的恶意脚本在Alice的浏览器中执行,就像它直接来自Bob的服务器一样。此脚本盗窃敏感信息(授权、信用卡、帐号信息等)然后在Alice完全不知情的情况下将这些信息发送到Charly的Web站点。

  类型C,存储式漏洞,该类型是应用最为广泛而且有可能影响到Web服务器自身安全的漏洞,骇客将攻击脚本上传到Web服务器上,使得所有访问该页面的用户都面临信息泄漏的可能,其中也包括了Web服务器的管理员。其攻击过程如下:

  Bob拥有一个Web站点,该站点允许用户发布信息/浏览已发布的信息。

  Charly注意到Bob的站点具有类型C的XXS漏洞。

  Charly发布一个热点信息,吸引其它用户纷纷阅读。

  Bob或者是任何的其他人如Alice浏览该信息,其会话cookies或者其它信息将被Charly盗走。

  类型A直接威胁用户个体,而类型B和类型C所威胁的对象都是企业级Web应用,目前天清入侵防御产品所能防范的XSS攻击包括类型B和类型C。

 2、XSS攻击防御

  基于特征的防御

  XSS漏洞和著名的SQL注入漏洞一样,都是利用了Web页面的编写不完善,所以每一个漏洞所利用和针对的弱点都不尽相同。这就给XSS漏洞防御带来了困难:不可能以单一特征来概括所有XSS攻击。

  传统XSS防御多采用特征匹配方式,在所有提交的信息中都进行匹配检查。如, 对于这种类型的XSS攻击,采用的模式匹配方法一般会需要对“javascript”这个关键字进行检索,一旦发现提交信息中包含 “javascript”,就认定为XSS攻击。这种检测方法的缺陷显而易见:骇客可以通过插入字符或完全编码的方式躲避检测:

  躲避方法1)在javascript中加入多个tab键,得到    

<IMG SRC="jav ascript:alert('XSS');">

  躲避方法2) 在javascript中加入&#x09编码字符,得到 

<IMG SRC="jav&#x09;ascript:alert('XSS');">

  躲避方法3) 在javascript中加入字符,得到    

<IMG SRC="jav&#x0A;ascript:alert('XSS');">

  躲避方法4)在javascript中的每个字符间加入回车换行符,得到

<IMG SRC="j\r\na\r\nv\r\n\r\na\r\ns\r\nc\r\nr\r\ni\r\np\r\nt\r\n:alert('XSS');">   

   躲避方法5)对"javascript:alert('XSS')"采用完全编码,得到

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

  上述方法都可以很容易的躲避基于特征的检测。而除了会有大量的漏报外,基于特征的还存在大量的误报可能:在上面的例子中,对"http://www.xxx.com/javascript/kkk.asp?id=2345"这样一个URL,由于包含了关键字“javascript”,也将会触发报警。

  基于代码修改的防御

  和SQL注入防御一样,XSS攻击也是利用了Web页面的编写疏忽,所以还有一种方法就是从Web应用开发的角度来避免:

  步骤1、对所有用户提交内容进行可靠的输入验证,包括对URL、查询关键字、HTTP头、POST数据等,仅接受指定长度范围内、采用适当格式、采用所预期的字符的内容提交,对其他的一律过滤。

  步骤2、实现Session标记(session tokens)、CAPTCHA系统或者HTTP引用头检查,以防功能被第三方网站所执行。

  步骤3、确认接收的的内容被妥善的规范化,仅包含最小的、安全的Tag(没有javascript),去掉任何对远程内容的引用(尤其是样式表和javascript),使用HTTP only的cookie。

  当然,如上操作将会降低Web业务系统的可用性,用户仅能输入少量的制定字符,人与系统间的交互被降到极致,仅适用于信息发布型站点。并且考虑到很少有Web编码人员受过正规的安全培训,很难做到完全避免页面中的XSS漏洞。

  正是由于传统检测方法存在诸多缺陷,国内厂商(如启明星辰天清入侵防御系统)并未采用这一方法,而是采用了基于攻击手法的行为检测方法。  

  首先对各种场景下的XSS攻击样本库进行整理和分类,并建立起XSS攻击行为特征库,在实时攻击检测阶段,对所有可能实现XSS攻击的数据来 源,如HTTP-Refere、URL、COOKIE、表单数据等,进行数据收集和初步分析,存在注入脚本的用户提交信息才进入下一步的XSS攻击判断。

  这种分析方法有以下几点优势:

  A:采用行为特征库而非数据特征库方式,可以避免由于检测固定特征导致的误报可能。

  B:内置数据预处理过程,可以对所有可能包含XSS攻击的数据进行预处理,放行大部分正常HTTP请求,仅对少量疑似事件进行深入分析,提升分析速度,降低资源开销。

  C:XSS攻击行为特征库维护由启明星辰公司AD-LAB(积极防御实验室)和博士后工作站负责,AD-LAB拥有大批漏洞发掘和分析人 员,2007年发现并获得CVE编号的漏洞数量多达26个,是国内独立发掘CVE漏洞数量最多的团队。启明星辰博士后工作站是业内第一家驻企业的信息安全 博士后工作站,为产品算法实现、研究技术转化提供有力保障。

  3、综论

  XSS攻击作为Web业务的最大威胁之一,不仅危害Web业务本身,对访问Web业务的用户也会带来直接的影响,如何防范和阻止XSS攻击,保障Web站点的业务安全,是定位于业务威胁防御的入侵防御产品的本职工作。只有结合对XSS攻击的分析,才能能准确的发现和防御各类XSS攻击行为,保障Web业务的正常运营。

Blogged with the Flock Browser

Tags: XSS, Web, Web安全, 攻击, 网页挂马, 防御

posted @ 2008-08-21 09:01 赵宝刚 阅读(311) | 评论 (0) | 编辑 收藏
 
 
<2008年8月>
日一二三四五六
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456

 导航

  • 首页
  • 发新随笔
  • 发新文章
  • 联系
  • 聚合
  • 管理

 统计

  • 随笔: 44
  • 文章: 5
  • 评论: 0
  • 引用: 0

常用链接

  • 我的随笔
  • 我的文章
  • 我的评论
  • 我的参与

留言簿(5)

  • 给我留言
  • 查看公开留言
  • 查看私人留言

随笔分类(26)

  • 技术趋势(21) (rss)
  • 汶川地震(1) (rss)
  • 管理心得(4) (rss)

随笔档案(49)

  • 2011年9月 (2)
  • 2010年8月 (1)
  • 2008年11月 (1)
  • 2008年8月 (6)
  • 2008年7月 (5)
  • 2008年6月 (6)
  • 2008年5月 (15)
  • 2006年7月 (2)
  • 2006年6月 (11)

友情链接

  • 我的另一个Blog地址 (rss)
  • 我的斗牛士(mydonews) (rss)
  • 老婆的QQZone (rss)

好玩的

  • 好玩的

最新随笔

  • 1. HTML圆角输入框
  • 2. Flex 文件上传
  • 3. 千万要避免的五种程序注释方式
  • 4. 如何选择最合适的Web开发框架
  • 5. XSS攻击防御技术白皮书
  • 6. 产品经理们,遇到Bug请别十万火急
  • 7. 在ERP项目中建立针对个人激励制度
  • 8. MySQL 5.1正式版即将公开发布
  • 9. 电子商务几大问题阻碍中小企业发展
  • 10. 企业信息化:体系比软件更重要
  • 11. 用户所不需要的也是应该被关注的
  • 12. 五大趋势推动云计算发展
  • 13. 如何控制虚拟机蔓延产生的成本增加?
  • 14. 不应忽视小型项目开发的管理问题
  • 15. 腾讯本月将首推Linux QQ
  • 16. 好消息——Mysql放弃闭源
  • 17. ITIL:指导企业IT外包应用最佳实践方法
  • 18. 从模式到优势 SaaS技术详细介绍
  • 19. 中小企业Email营销的用户体验设计
  • 20. 美国警告中国:小心被“技术隔离”
  • 21. 《仓鼠革命》四大方法简介
  • 22. [转贴]了解 Eclipse 插件如何使用 OSGi
  • 23. 阐述中小企业选择ERP标准及注意事项
  • 24. 云计算成软件厂商必争之地
  • 25. [震区求助]急需 260 万顶帐篷
  • 26. 企业如何在电子新闻邮件中展示广告
  • 27. 解析SOA未能获得成功的原因
  • 28. 坏消息——Sun开始关闭MySQL部分功能的源代码
  • 29. 内聚对SOA是否重要?
  • 30. SCA同OSGI的比较
  • 31. ebXML:一种商业协作发展方向
  • 32. 电子商务全球化标准:ebXML
  • 33. [转贴]关于员工离职引发的思考
  • 34. [转贴]云计算下的商业雨
  • 35. [转贴]福布斯:云计算已成未来经济的必然选择
  • 36. [转贴]Gartner:IT主管应该尽早为云计算做准备
  • 37. 从选择 Java 框架谈谈技术人员的“舒适区”
  • 38. [导入]为什么 Java 开发者应该写 Blog
  • 39. [导入]Eclipse使用技巧之插件管理
  • 40. [导入]Eclipse插件之FindBugs

最新评论

阅读排行榜

  • 1. HTML圆角输入框(3119)
  • 2. PMD Squashes Code Bugs(1158)
  • 3. [导入]Eclipse使用技巧之插件管理(924)
  • 4. [转贴]了解 Eclipse 插件如何使用 OSGi(442)
  • 5. [导入]Eclipse插件之FindBugs(374)

Powered by: 博客园
模板提供:沪江博客
Copyright ©2025 赵宝刚