淘宝商城(天猫)高级技术专家.3年研发+3年性能测试调优/系统测试+4年团队管理与测试架构、研发系统实践. 新舞台新气象, 深化测试基础架构及研发架构,希望能在某个技术领域成为真正的技术大牛。欢迎荐才http://bbs.51testing.com/viewthread.php?tid=120496&extra=&page=1 .邮件: jianzhao.liangjz@alibaba-inc.com,MSN:liangjianzhao@163.com.微博:http://t.sina.com.cn/1674816524

发布新日志

  • [论坛] 微软软件测试质量体系最佳实践课程

    2008-06-06 21:54:03

    MSUP的课程。看了很是心动:)

    陆宏杰的课程偶旁听过,给你展现很多MS的东东。有兴趣的朋友请

    祥见:www.msup.com.cn



    陆宏杰 曾任微软亚洲工程院部门经理
    微软资深专家顾问,曾任职于微软亚洲工程院,十余年的软件开发、软件测试和团队管理经验,曾主管过多个大型复杂项目的开发和测试工作,尤其在自动化测试技术和测试管理方面积累了大量的实际项目经验。对于各种测试方法的重点、难点和实施技巧有深入的研究,其主持开发和测试的项目多次获得微软全球最高技术奖项和工程奖项,并获得msup 2007年度top one金牌分享大师、msup 2007年度软件企业内训最佳好评讲师。

    课题
    简述
    Topic 1
    对软件测试的理解
    (1)软件测试的最高境界是什么
    (2)测试驱动开发模式
    (3)测试是需要额外增加项目时间
    还是加速开发进度?
    (4)通过测试提高开发有效代码率
    (5)软件测试的存在阶段
    (6)怎样实施不间断测试
    (7)缺陷分类对开发管理支撑作用
    (8)软件风险的概念
    (9)测试的充分性准则
    要做好测试,首先要有深刻的理解,对实践中最重要、最容易混淆或最容易出问题的地方结合实例阐述,讲解将测试融入开发进程的实战策略以及自动化测试的部署策略。

    Topic 2
    测试计划
    (1)测试计划的制定策略
    (2)测试计划和需求分析之间的联系
    与配合
    (3)如何科学评定工作量、所需人数
    和各方面设备
    (6)测试范围的界定
    (7)测试目标的界定和考评
    (8)项目风险评估
    (9)测试过程中的假定和局限
    (11)被测对象特性描述
    (12)具备可操作性的发布标准
    (13)对验证粒度的管理和要求
    (14)通用方法/工具的建立
    (15)所需拓扑逻辑的定义
    (16)各种测试工具的比较和选择标准
    (17)怎样提高测试效率
    (18)如何组织和管理需求文档、设计文档和测试文档
    分析文档的核心价值和在软件项目中的作用,为什么要写文档?不写行不行?要写哪些文档?准备文档对项目整体进度的影响是什么?

    这部分内容将分别从测试执行者和测试管理者的角度分别出发,讲解如何制定能覆盖到细节的测试计划,文档对项目的实用价值,对文档质量的评审流程,以及准备资源的依据,并最终评定每一个测试人员的测试执行情况。

    Topic 3
    测试用例
    设计
    (1)黑盒测试
    (2)白盒测试
    (3)等价类划分法
    (4)边界值分析法
    (5)因果图法如何提高测试技术复用程度
    在众多测试用例中,验证的深度和白盒测试是测试活动中比较突出的难点,大部分理论中的描述不具有可操作性。这部分内容会着重讲解如何进行深度验证和解决白盒测试的难点,使得白盒测试可以真正得以实施,同时,介绍提高测试效率及效果的技术复用策略。

    Topic 4
    测试度量体系建立
    (1)缺陷库的建立
    (2)用例库的建立
    (3)测试结果库的建立
    (4)自动化测试体系
    (5)高效的工作流程
    (6)数据统计和数据挖掘
    (7)缺陷追踪体系 科学的测试管理
    通过对测试度量体系的构建,深入理解如何工程化实施大规模深度测试。

    Topic 5
    自动化测试
    方法及技巧
    (1)对功能测试的控制
    (2)黑盒/白盒测试的部署技巧
    (3)安全性测试的难点和特点
    (4)Help、手册和文档的测试分工
    (5)全球化和本地化测试
    (6)可用性测试定义
    (7)可扩展性测试
    (8)Geo/Political/Legal的测试方法
    (9)Logging/ Message format Tracing/Counters( Diagnos ability)
    (10)Testability的评估
    (11)Test Hooks高级测试方法
    (12)基于场景的测试
    (13)可靠性/耐久性测试
    (14)集成测试
    (15)交互性测试
    (16)兼容性测试
    (17)UE测试
    (18)性能测试的方法和要点
    (19)Benchmark
    (20)压力测试
    (21)性能测试和压力测试的区别
    (22)压力测试的难点和技巧
    (23)对系统的压力测试
    (24)对界面的压力测试
    (25)使用工具进行性能测试和压力测试
    这一章是自动化测试的重要实战部分,将对每一种测试方法的重点、难点和实施技巧进行讲解,用一个真实的企业级软件项目作为案例,讲解如何在一个真实项目中逐一实施这些测试方法,其中绝大部分的测试方法都以自动化测试的技术和实现方法来讲解。当所有的测试方法都部署完成,讲解何如把这些独立的测试方法和测试活动整合成自动化测试体系。从而实现缺陷预防的持续改进。

    Topic 6
    自动化测试体系
    (1)自动化测试对Bug的控制力度
    (2)多种自动化测试工具的分析
    (3)自动化测试的运行部署策略
    (4)数据驱动的测试
    (5)核心功能的自动化测试标准
    (6)Pass Rate:测试活动的重要标准
    (7)代码覆盖率检查,对测试质量的审查
    (8)自动化测试的缺陷跟踪
    (9)GUI测试自动化的难点和解决方法
    (10)自动化测试的自动化
    (11)如何将多种自动化测试工具和技术部署为一个复杂完备的大型质量保证体系
    这部分内容是核心中的核心,它是建立在前面用例设计、测试计划和各种测试方法的基础上的,可以说前面的内容都是在为这一块打基础,对于自动化测试来说,光有技术和工具还不够,需要工程化的综合使用,使之成为一个体系,甚至需要实现自动化测试的自动化。

    Topic 7
    测试管理
    (1)如何着手组建和优化测试团队?
    (2)一个测试团队必须的3种人才
    (3)产品Bug和测试Bug
    (4)如何从每一个细节控制测试进度和项目进度
    (5)如何协调测试团队和其他团队的配合
    (6)周期性测试的活动安排
    (7)测试人员的考评标准
    (8)测试纪律的制定策略
    (9)质量文化
    (10)对工作项的时间限定
    (11)数据统计和数据挖掘
    (12)如何制定项目计划,包括开发计划和测试计划
    (13)合理的里程碑及里程碑之间的工作计划
    (14)长期计划、中期计划、短期计划
    (15)Guideline和CheckList
    (16)在项目进度要求很紧的情况下如何保证测试的质量和完备性
    (17)作为一个管理者必须控制的3件大事
    (18)保持项目的持续成长
    没有科学的测试管理就不可能建立完备的质量保证体系,这部分内容分享在测试管理中的有效经验,通过流程控制与过程改进优化测试效率,保证测试质量,加强测试对于需求分析和开发过程以及技术应用的配合,从而完整实现测试驱动软件开

    [ 本帖最后由 liangjz 于 2008-6-6 21:55 编辑 ]
  • 遴选合适岗位人才要领

    2008-05-27 01:06:08

     

    一 分析现有岗位人员技能特点,最好增加互补型人才

      假如现有的人才都属于通才型,那需要找到一个很有专长的人才,作为互补最合适。
    还有如果团队都是年轻人,加入一个经验丰富稳重一些的更好

    二 考察专业能力
     
      工程师考察专业能力相对容易一些,可以将自己经历过的项目提炼出一些有梯度的问题,判断应聘者

    属于需要人带 、独立做事情、带团队做事情、某个领域的专家中哪种类型

      专业能力最好能涵盖基础知识以及项目实践,把握好深度、广度。基础好的人,发展潜力、爆发力比

    较好

    三 考察学习能力

     了解碰到疑难问题的解决模式,以及对这个问题是否有提问的智慧。

    另外,可以将业余爱好与学习能力结合起来。还有询问经常去的一些网站,记得哪些比较深刻的技术细

    节。
     
      一般情况下,如果对某个比较难的技术问题把握得很到位,也可以侧面了解到学习能力高下。
      学习意愿可以从他最擅长的知识入手考察,一般意愿强的人,喜欢寻根究底,深刻理解背后的原理。
    反面而言,就是一根筋:)

    四 考察适应环境能力
     
     可以从几个方面看
    1 承受压力能力:互联网公司项目多\紧急,一般面临多项工作并行开展,同时节凑快。
    2  软技能:测试工作繁复琐碎,需要耐心、细致的特质;由于需要频繁和外部联系,良好的沟通技巧,

    有利于顺利开展工作。开放、共享的心态有助自我提升。
     
      还需要判断其缺点是否影响其业绩

    3  团队的融入性: 做事风格不能相差太多。认可结果为导向、客户第一等多项价值观

    五 职业素质
     
    1 比如跳槽是否过于频繁,能否有稳定性
    2 对自己是否有一个清晰的定位以及职业发展规划

     实际上,在挑选高级人才时碰到最大的问题有几个
    A) 比较接近的候选人偏少
    B)  把握不准到底适合这个岗位、流入市场的候选人到底有多少?这里有类似非常复杂的猴子捡玉米问


    C)  在软技能和潜力把握方面难度比较大

    欢迎大家探讨

  • web软件测试碰到的难题

    2008-05-25 15:36:21

    最近在整理测试难题,以及打算在跨子公司讨论、分享的话题。呵呵,大致列举一些

    1 如何清晰度量产品的测试质量?

       按测试覆盖率?按BUG遗漏数?按已经发现BUG的曲线图?哪些标准度量最合适

    2 如何为复杂产品/大型测试项目选取测试策略? 如
     
    镜像站点测试
    异地数据同步测试
    重构项目测试

    3 支持多浏览器(IE6/ie7/firefox...)/多OS软件如何测试?

    降低成本的测试方法有哪些?

    正交表测试方法满足我们的需求么?

    4 支持国际化语言版本的软件如何测试?如国际站网站支持英文,繁体版,马来西亚语言。
    降低成本的测试方法有哪些?

    5 如何在时间、进度压力下,最优选取测试集合?
    回归测试的面积多大算合理?

    6 如何提高估计测试时间的准确度?

    7 跨部门、跨公司的接口测试如何开展,以提高协调效率?

    如中文站和阿里软件贸易通状态接口,国际站和后台CRM 接口,

    8 如何有效度量测试工程师的绩效?

    9 生产环境依赖于外部昂贵的设备,在测试环境开展性能测试如何模拟?

    比如专用邮件服务器,图片服务器?

    10 生产环境的数据量巨大,如何剪裁合适的数据集作为性能测试基准数据?

    11 如何更快找到合适的测试人才?

    12 如何提高开发、测试双方的满意度?

    13 如何在没有单元测试代码情况下,度量代码测试覆盖率

    14 现有的软件测试平台更适合传统的大型软件测试,能否、如何定制更适合快速上线的WEB系统?

    如QC 的报表、需求管理2部分功能一直没有采用。

    15 项目管理、需求管理、缺陷管理多个系统入口, 并没有统一关联。另外代码与需求之间映射关系随着业务变更也难以一一映射

    ...待续

  • 实际项目中C++如何调用java应用

    2008-05-18 01:14:39

     

    http://bbs.51testing.com/viewthread.php?tid=115018&extra=page%3D1&frombbs=1

    问题的关键在 jni.h的函数实现,如 jint res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);

  • javascript 显示flash

    2008-05-05 20:58:58

    <html >
      <head>
          <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
         <scrīpt type="text/javascrīpt" language="javascrīpt">   
         function swf(url) {
                document.getElementById("flash_span").innerHTML='<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0"><param name="movie" value="' + url + '" /><embed width=0 height=0 src="' + url + '" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" /></object>'
            }       
        </scrīpt>     
       
     </head>
      <body>
       <span id="flash_span" style=""></span>
        <button name="click"  ōnclick="swf('http://10.0.6.91/uploadfiles/flashes/d55bcef8682a8f87fee992e08771be5c8d784e77.swf')">
    </body>

    </html>

     

     

  • 体验ajax 程序

    2008-05-02 13:12:28

     

    经过测试在IE6 以及firefox2.0 都可以正常运行的ajax程序

     

    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
    <title>ajax demo</title>

    <scrīpt type="text/javascrīpt" language="javascrīpt">
     var httpRequest =false;
        function makeRequest(url) {       
     document.getElementById("result").innerHTML="";
            if (window.XMLHttpRequest) { // Mozilla, Safari, ...
                httpRequest = new XMLHttpRequest();
                if (httpRequest.overrideMimeType) {
                    httpRequest.overrideMimeType('text/xml');
                    // See note below about this line
                }
            }
            else if (window.ActiveXObject) { // IE
      var versions = ['Microsoft.XMLHTTP', 'MSXML2.XMLHTTP','MSXML.XMLHTTP', 'Msxml2.XMLHTTP.7.0',

    'Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.5.0', 'Msxml2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', ];
       for(var i=0; i<versions.length; i++) {
            try {
           httpRequest = new ActiveXObject(versions[i]);     
        } catch(e) {}
       }
             }
            if (!httpRequest) {
                alert('Cannot create an XMLHTTP instance');
                return false;
            }
     
            httpRequest.onreadystatechange = alertContents;   //function() { alertContents(httpRequest); };
            httpRequest.open('GET', url, true);
     httpRequest.setRequestHeader('Cache-Control','no-cache');
            httpRequest.send('');
        }

        function alertContents(){
            if (httpRequest.readyState == 4) {
                if (httpRequest.status == 200) {
                    //alert(httpRequest.responseText);
      document.getElementById("result").innerHTML =httpRequest.responseText;
                } else {
                   document.getElementById("result").innerHTML='There was a problem with the request.';
                }
            }
        }
    </scrīpt>
    </head>
    <body>
    <span
        style="cursor: pointer; text-decoration: underline"
        ōnclick="makeRequest('http://127.0.0.1:3000/my_test/')">
            Make a request
    </span>
    <br>
    <span id="result" style="" >
    </body>
    </html>

     

    在本地启动mongrel服务器侦听3000端口

  • web前端性能分析工具

    2008-05-02 01:36:20

      以前关注服务器端性能测试,现在投了一些精力在了解web前端性能测试。有几个很趁手的工具

    1)ibm page detailer。注册IBM 帐号后,下载了basic版本的。第一个感觉就是惊艳,能把网页duration(切分服务器时间、下载时间等,与loadrunner page break down类似),item等等.基本上满足我们目前需求.

      在启动page detailer后,再启动IE后的HTTP 请求都被截获。

    2) firefox插件firebug。呵呵,这个工具开源的,功能也很强大,而且javascrīpt调试能力好。呵呵,目前 ALIBABA的部分应用支持firefox不如ie好啊。

    3)yahoo yslow。也是firefox插件。偶还没有试用过:)

       前2个工具切实给页面调优带来较大的想象空间:) 

       看来好工具还是很多的,关键是要有发现的眼光:)

     

     

  • 前端技术-- ajax框架

    2008-05-02 00:00:04

        以前性能测试关注重心在服务器端,最近有几个应用提出客户端性能度量问题。呵呵,正在了解前端技术领域。

         前端技术包括Javascrīpt、Actionscrīpt、CSS、xHTML等传统技术与Adobe AIR、Google Gears等新技术。 淘宝网大规模应用ajax框架 。

       Ajax框架主要有如下几种 :

    Prototype http://prototypejs.org, http://scrīpt.aculo.us
    JQuery    http://jquery.com      
    Ext JS2.0-  javascrīpt library    http://www.extjs.com
    scrīpt.aculo.us
    Mootools
    YUI              http://developer.yahoo.com/yui,淘宝网采用YUI,现在自主研发Tbra(不是100%确信)
    JSON
    Dojo             http://dojotoolkit.org
    BackBase

      另外找到一个firefox上调试js的好插件:firebug

     

  • rails应用性能测试技巧以及工具

    2008-04-27 11:18:04

    其他web应用也可以参考 。

    相当多概念思路可以遵循

    http://bbs.51testing.com/viewthread.php?tid=113200&page=1&extra=page%3D1

     

  • 解决 perl xml getNodeValue 为空值的过程

    2008-04-19 22:37:48

    记录一下,不熟悉Perl xml 处理过程,吃了大亏:)

     

    http://www.51testing.com/?170805/action_viewspace_itemid_80386.html

     

  • Acunetix web vulnerality scanner安全测试

    2008-04-19 12:50:53

  • 利用 gprof2dot 和graphviz 图形化定位linux c/c++系统性能瓶颈

    2008-04-15 21:46:04

    这个技巧从开发那里学来的。

    这帮GG寻找好东西的能力一流 :)

     

     

    1 下载

     

    http://code.google.com/p/jrfonseca/wiki/Gprof2Dot

    http://jrfonseca.googlecode.com/svn/trunk/gprof2dot/gprof2dot.py   下载gprof2dot.py

     http://www.graphviz.org/Download_source.php 下载源代码graphviz-2.18.tar.gz

     

    2  环境

    [admin@b2bsearch80 bin]$ python  -V

    Python 2.3.4

    [admin@b2bsearch80 bin]$ gcc -v

    Reading specs from /usr/lib/gcc/i386-redhat-linux/3.4.6/specs

    Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-java-awt=gtk --host=i386-redhat-linux

    Thread model: posix

    gcc version 3.4.6 20060404 (Red Hat 3.4.6-3)

    [admin@b2bsearch80 bin]$ uname -a

    Linux b2bsearch80 2.6.9-42.ELsmp #1 SMP Wed Jul 12 23:27:17 EDT 2006 i686 i686 i386 GNU/Linux

     

    3  安装

     

    Chmod  744 gprof2dot.py

    Tar  -zxvf  graphviz-2.18.tar.gz

       ./configure

      make

       su   -

     make install

     

    4   编译代码

    gcc -pg  -g  -o  uniqueCoreDump  uniqueCoreDump.c

     

    5  执行代码生成gmon.out

     

      执行命令产生gmon.out 文件

      ./uniqueCoreDump

    ll gmon.out

     

    如果gprof  ./uniqueCoreDump 有:

    gmon.out file is missing call-graph data

     

    则表示没有正确的编译选项或者只有一个main函数

     

     

     

    6  生成图片

      gprof  ./uniqueCoreDump   | ./gprof2dot.py -n0 -e0 | dot -Tpng -o output.png

     

      sz  output.png 

     

     

  • inet_ntoa(remote_addr.sin_addr) 在64位linux下core dump

    2008-04-15 21:31:16

    在编写一个网络应用程序,在32位Linux下已经运行了相当长时间,无core dump,移植到64

    我都是单进程执行的。

     

     

    Program terminated with signal 11, Segmentation fault.

    #0  0x0000003a53c75350 in strlen () from /lib64/libc.so.6

    (gdb) bt

    #0  0x0000003a53c75350 in strlen () from /lib64/libc.so.6

    #1  0x0000003a53c45b88 in vfprintf () from /lib64/libc.so.6

    #2  0x0000003a53c60e09 in vsprintf () from /lib64/libc.so.6

    #3  0x0000003a53c4b958 in sprintf () from /lib64/libc.so.6

    #4  0x000000000040156b in socket_server () at getlinuxstat.c:183

    #5  0x0000000000401c90 in main (argc=1, argv=0x7fff4b872328) at getlinuxstat.c:349

    (gdb) f 4

    #4  0x000000000040156b in socket_server () at getlinuxstat.c:183

    183                                                                                                             sprintf(buf_log,"received a connection from %s\n", inet_ntoa(remote_addr.sin_addr));

     

      咨询开发用线程安全的inet_ntop函数,但是这样的话,就会用到两个额外的数组。总要有些牺牲的。
    使用inet_ntoa的话,就不能够在同一个函数的几个参数里面出席那两次inet_ntoa,或者是第一个inet_ntoa未使用结束之前,不要使用第二个。

    更改实现为:

     if ( NULL== (char*) (inet_ntop(AF_INET,&remote_addr.sin_addr.s_addr,str,31)) )

     

    详细的代码如下:

    int socket_server()

    {

        int sockfd,client_fd; /*sock_fd:监听socketclient_fd:数据传输socket */

        struct sockaddr_in my_addr; /* 本机地址信息 */

        struct sockaddr_in remote_addr; /* 客户端地址信息 */

        int sin_size;

        char  recv_buf[MAX_BUF_SIZE]={0};

        int   recv_size=0;

        char  send_buf[MAX_BUF_SIZE]={0};

        int    send_size=0;

        int  pid;

        int  status;

        struct timeval tv;

        struct in_addr clientaddr ;

        char  str[32]={0};

        char  buf_log[MAX_BUF_SIZE]={0};

     

        enum  stat_action  action;

        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

            sprintf(buf_log,"socke errno=%d,desc=%s\r\n",errno,strerror(errno));

            buf_log[strlen(buf_log)]=0;

            writelog(g_logfile,buf_log);

            return 1;

        }

     

       my_addr.sin_family=AF_INET;

       my_addr.sin_port=htons(SERVPORT);

       my_addr.sin_addr.s_addr = INADDR_ANY;

       bzero(&(my_addr.sin_zero),8);

       if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))  == -1) {

          sprintf(buf_log,"bind errno=%d,desc=%s\r\n",errno,strerror(errno));

          buf_log[strlen(buf_log)]=0;

          writelog(g_logfile,buf_log);

          return 1;

       }

       if (listen(sockfd, BACKLOG) == -1) {

         sprintf(buf_log,"bind errno=%d,desc=%s\r\n",errno,strerror(errno));

            buf_log[strlen(buf_log)]=0;

            writelog(g_logfile,buf_log);

         return 1;

        }

        tv.tv_sec= SOCKET_TIMEOUT_SECOND;

        tv.tv_usec=0;

     

        while(1) {

             memset(&remote_addr, 0, sizeof(struct sockaddr));

            sin_size = sizeof(remote_addr);

            if ((client_fd = accept(sockfd, (struct sockaddr *)(&remote_addr), &sin_size)) == -1) {

               sprintf(buf_log,"accept errno=%d,desc=%s\r\n",errno,strerror(errno));

               buf_log[strlen(buf_log)]=0;

               writelog(g_logfile,buf_log);

               continue;

              }

     

            //sprintf(buf_log,"received a connection from %s\n", inet_ntoa(remote_addr.sin_addr));

     

            if ( NULL== (char*) (inet_ntop(AF_INET,&remote_addr.sin_addr.s_addr,str,31)) )

            {

               printf("inet_ntop error,errno=%d,desc=%s\r\n",errno,strerror(errno) );

            }

            sprintf(buf_log,"received a connection from %s\n", str);

     

            buf_log[strlen(buf_log)]=0;

            writelog(g_logfile,buf_log);

     

           if (setsockopt(client_fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)) == -1)

           {

              sprintf(buf_log,"warning!setsockopt  errno=%d,desc=%s\r\n",errno,strerror(errno));

             buf_log[strlen(buf_log)]=0;

             writelog(g_logfile,buf_log);

           }

     

           if ( (pid=fork()) == 0) { /* 子进程代码段 */

               while(1)

               {

                 memset(recv_buf,0,MAX_BUF_SIZE);

                 recv_size=recv(client_fd,recv_buf,MAX_BUF_SIZE -1 ,0);

                 if(recv_size ==-1)

                 {

                    sprintf(buf_log,"recv errno=%d,desc=%s\r\n",errno,strerror(errno));

                     buf_log[strlen(buf_log)]=0;

                    writelog(g_logfile,buf_log);

                    close(client_fd);

                    exit(1);

                 }

                 else if( 0== recv_size)

                {

                   sprintf(buf_log,"connection reset by peer!\r\n");

                    buf_log[strlen(buf_log)]=0;

                    writelog(g_logfile,buf_log);

                   exit(1);

                }

                 else     //if (1 == recv_size)

                 {

     

                   action=atoi(recv_buf);

                   sprintf(buf_log,"recv_buf=%s,recv_size=%d,action=%d\r\n",recv_buf,recv_size,action);

                   buf_log[strlen(buf_log)]=0;

                   writelog(g_logfile,buf_log);

                   memset(send_buf,0,MAX_BUF_SIZE);

     

                   if (exec_command(2,action,send_buf) ==-1 )

                    {

                         continue;

                    }

     

                   send_buf[ strlen(send_buf)] = 0;

                   sprintf(buf_log,"begin send...,send_buf=%s\r\n",send_buf);

                   buf_log[strlen(buf_log)]=0;

                   writelog(g_logfile,buf_log);

                   if (send(client_fd, send_buf,strlen(send_buf), 0) == -1) {

                      sprintf(buf_log,"send errno=%d,desc=%s\r\n",errno,strerror(errno));

                       buf_log[strlen(buf_log)]=0;

                       writelog(g_logfile,buf_log);

                      close(client_fd);

                      exit(1);

                   }

     

                 }

              }

          }

          else if(pid <0)

          {

            sprintf(buf_log,"socket_server fork errno=%s\n",strerror(errno));

            buf_log[strlen(buf_log)]=0;

            writelog(g_logfile,buf_log);

          }

          else

          {

            //parent;

            close(client_fd);

            waitpid(pid,&status,0);

     

           }

     

       }

      return 0;

    }

  • 免费跨站攻击扫描工具paros与appscan 对比

    2008-04-11 23:36:56

     

    2者对比发现paros的结果有很多的不足

     

    1)      SQL 注入扫描貌似有问题

    2)      跨站脚本有遗漏

    3)      Lotus dimino 有安全问题误报

    4)      报表、修复建议没有appscan强大

    5)      Appscan集成强大的安全规范

    6)     

    更多见http://bbs.51testing.com/viewthread.php?tid=110473&extra=page%3D1&frombbs=1

  • 修改HTTP Post/get数据利器TamperIE

    2008-04-11 23:35:11


    偶在此登记,避免遗漏:)

     

    近期关注安全测试,将陆续介绍接触到的一些很好的工具。

    安全工具是一把双刃剑,用好了给测试工作带来很大的便利。

    本期介绍修改HTTP Post/get数据利器TamperIE。

    http://bbs.51testing.com/thread-110474-1-1.html

  • 借助jclasslib与javassist修改java class字节码

    2008-04-05 19:53:40

    http://bbs.51testing.com/thread-110784-1-1.html

        有时候,我们在没有java源程序的情况下,想改变.CLASS文件的部分内容输出或者改变跳转流,怎么办呢?
      介绍2个java hacker的工具javassist 以及jclasslib。

     

  • 技术管理初体验

    2008-03-22 10:41:35

     

     

    在技术管理方面,偶是绝对的新手。

    不过就像很多事情一样 ,都有人无师自通的 J ,可惜偶不算这种。

    以下都是偶的一些浅显见解。

     

    技术管理和纯技术工作还是有很大的不同

    1)      技术管理需要经常REVIEW 成员的成果,REVIEW的工作量取决于REVIEW的粒度,太细会把握不住重点且工作量大,太粗无法看出门道。由于要REVIEW 组员成果,需要对组员的工作领域有比较深刻的把握,故技术管理需要杂家 纯技术则一门心思把自己的事情做好,并偶尔帮忙请教的同事解决问题,在自己的领域专注得比较深

    2)      技术管理的重点在于把握人,要鼓励组员积极发挥主观能动性,及时发现组员的思想情绪变化,也需要授权给与组员充分的信任但还是需要REVIEW成果;纯技术则重点在于管事,把颗粒很细的事情解决掉,当然也有培养接口人的任务。

    3)      技术管理的绩效考核从团队业绩出发,一华为跳槽过来的哥们说的: 团队PKI 比个人PKI 更难出彩; 纯技术工作更多把自己的活做好,并影响周围人积极向前

    4)      技术管理的工作经常被打断,思路也随之被打断,故在时间管理上提出更高要求;纯技术则干扰少一些 ,技术管理者需要帮纯技术的同事创造一个尽少被干扰的环境

    5)      在技能要求方面,作为一个上通下达的角色,技术管理在领悟能力、沟通、协调等 软技能方面提出很高的要求,另外在某些时刻需要根据直觉决断 ;纯技术则需要在技术细节方面把握很到位

     

    技术管理方面碰到的一些容易困惑的问题

    1)      技术管理碰到最大的问题是资源短缺,如何平衡各方的需求成为一个最棘手的问题

    2)      绩效考核,技术工作很难单纯用数字量化,如何甄别组员的优秀,需要有伯乐的眼光

    3)      一直保持良好的团队激情、氛围。基层的技术管理者手上有的 赏的权利很小,手段多为肯定、赞扬组员的工作,呵呵,有时候这些手段是不够 J

    4)      技术管理如何协调团队内外的关系。外部期望值一般都很高 ,作为技术管理者在满足外部需求时,需要权衡团队的承担能力

    5)      怎样的领导风格最适合团队? 太严格,容易压抑;太宽松,容易散漫;太武断,容易听不见他人意见,太犹豫容易错失时机

    6)      技术管理,自身还需要承担很多技术工作,比如确定技术研究方向、解决技术问题,技术和管理分配的时间比率为多少最合适?

    7)      …..

    说到底,面对诸多问题,有一个度量把握的问题,这个很需要艺术。 也是偶的努力方向。

       

  • APPSCAN 修复SQL注入安全缺陷建议[zt]

    2008-03-20 22:29:29

     最近在了解IBM 的安全测试工具APPSCAN.

     通过使用demo.testfire.com。感觉功能确实NB。

     找个临时license尝试下扫描自己的测试环境,看看是否也这么好的命中率?

     另外,还有疑问它工作原理是否通过网络截取包,并解析特征字?

      对于hibernate、ibatis 这种封装SQL的代码是否也能判断到?

     

    Blind SQL Injection
    Fix Recommendation

    --------------------------------------------------------------------------------
    General
    There are several issues whose remediation lies in sanitizing user input.
    By verifying that user input does not contain hazardous characters, it is possible to prevent malicious users from causing your application to execute unintended operations, such as launch arbitrary SQL queries, embed Javascrīpt code to be executed on the client side, run various operating system commands etc.

    It is advised to filter out all the following characters:

    [1] | (pipe sign)
    [2] & (ampersand sign)
    [3] ; (semicolon sign)
    [4] $ (dollar sign)
    [5] % (percent sign)
    [6] @ (at sign)
    [7] ' (single apostrophe)
    [8] " (quotation mark)
    [9] \' (backslash-escaped apostrophe)
    [10] \" (backslash-escaped quotation mark)
    [11] <> (triangular parenthesis)
    [12] () (parenthesis)
    [13] + (plus sign)
    [14] CR (Carriage return, ASCII 0x0d)
    [15] LF (Line feed, ASCII 0x0a)
    [16] , (comma sign)
    [17] \ (backslash)


    The following sections describe the various issues, their fix recommendations and the hazardous characters that might trigger these issues:


    SQL injection and blind SQL injection:
    A. Make sure the value and type (such as Integer, Date, etc.) of the user input is valid and expected by the application.
    B. Use stored procedures to abstract data access so that users do not directly access tables or views. When using stored procedures, use the ADO command object to implement them, so that variables are strongly typed.
    C. Sanitize input to exclude context-changing symbols such as:

    [1] ' (single apostrophe)
    [2] " (quotation mark)
    [3] \' (backslash-escaped apostrophe)
    [4] \" (backslash-escaped quotation mark)
    [5] ) (closing parenthesis)
    [6] ; (semicolon)


    Cross site scrīpting:
    A. Sanitize user input and filter out Javascrīpt code. We suggest that you filter the following characters:

    [1] <> (triangular parenthesis)
    [2] " (quotation mark)
    [3] ' (single apostrophe)
    [4] % (percent sign)
    [5] ; (semicolon)
    [6] () (parenthesis)
    [7] & (ampersand sign)
    [8] + (plus sign)
    B. To fix the <%00scrīpt> variant see MS article 821349
    C. For UTF-7 attacks:

    [-] When possible, it is recommended to enforce a specific charset encoding (using 'Content-Type' header or <meta> tag).

    HTTP response splitting:
    Sanitize user input (at least, such input that is later embedded in HTTP responses).
    Make sure that malicious characters are not part of the input, such as:

    [1] CR (Carriage return, ASCII 0x0d)
    [2] LF (Line feed, ASCII 0x0a)


    Remote command execution:
    Sanitize input to exclude symbols that are meaningful to the operating system's command execution, such as:

    [1] | (pipe sign)
    [2] & (ampersand sign)
    [3] ; (semicolon sign)

    Shell command execution:
    A. Never pass unchecked user-input to Perl commands such as: eval(), open(), sysopen(), system().
    B. Make sure malicious characters are not part of the input, such as:

    [1] $ (dollar sign)
    [2] % (percent sign)
    [3] @ (at sign)


    XPath injection:
    Sanitize input to exclude context changing symbols such as:

    [1] ' (single apostrophe)
    [2] " (quotation mark)
    Etc.

    LDAP injection:
    A. Use positive validation. Alphanumeric filtering (A..Z,a..z,0..9) is suitable for most LDAP queries.
    B. Special LDAP characters which should be filtered out or escaped:

    [1] A space or "#" character at the beginning of the string
    [2] A space character at the end of the string
    [3] , (comma sign)
    [4] + (plus sign)
    [5] " (quotation mark)
    [6] \ (backslash)
    [7] <> (triangular parenthesis)
    [8] ; (semicolon sign)
    [9] () (parenthesis)
    Asp.Net
    Here are two possible ways to protect your web application against SQL injection attacks:

    [1] Use a stored procedure rather than dynamically built SQL query string. The way parameters are passed to SQL Server stored procedures, prevents the use of apostrophes and hyphens.

    Here is a simple example of how to use stored procedures in ASP.NET:


      ' Visual Basic example
      Dim DS As DataSet
      Dim MyConnection As SqlConnection
      Dim MyCommand As SqlDataAdapter
      Dim SelectCommand As String = "select * from users where username = @username"
      ...
      MyCommand.SelectCommand.Parameters.Add(New SqlParameter("@username", SqlDbType.NVarChar, 20))
      MyCommand.SelectCommand.Parameters("@username").Value = UserNameField.Value
      // C# example
      String selectCmd = "select * from Authors where state = @username";
      SqlConnection myConnection = new SqlConnection("server=...");
      SqlDataAdapter myCommand = new SqlDataAdapter(selectCmd, myConnection);
      myCommand.SelectCommand.Parameters.Add(new SqlParameter("@username", SqlDbType.NVarChar, 20));
      myCommand.SelectCommand.Parameters["@username"].Value = UserNameField.Value;

     

    [2] You can add input validation to Web Forms pages by using validation controls. Validation controls provide an easy-to-use mechanism for all common types of standard validation - for example, testing for valid dates or values within a range - plus ways to provide custom-written validation. In addition, validation controls allow you to completely customize how error information is displayed to the user. Validation controls can be used with any controls that are processed in a Web Forms page's class file, including both HTML and Web server controls.

    In order to make sure user input contains only valid values, you can use one of the following validation controls:


    a. "RangeValidator": checks that a user's entry (value) is between specified lower and upper boundaries. You can check ranges within pairs of numbers, alphabetic characters, and dates.


    b. "RegularExpressionValidator": checks that the entry matches a pattern defined by a regular expression. This type of validation allows you to check for predictable sequences of characters, such as those in social security numbers, e-mail addresses, telephone numbers, postal codes, and so on.

    Important note: validation controls do not block user input or change the flow of page processing; they only set an error state, and produce error messages. It is the programmer's responsibility to test the state of the controls in the code before performing further application-specific actions.

    There are two ways to check for user input validity:

    1. Testing for a general error state:

    In your code, test the page's IsValid property. This property rolls up the values of the IsValid properties of all the validation controls on the page (using a logical AND). If one of the validation controls is set to invalid, the page's property will return false.

    2. Testing for the error state of individual controls:

    Loop through the page's Validators collection, which contains references to all the validation controls. You can then examine the IsValid property of each validation control.
    J2EE
    ** Prepared Statements:

    There are 3 possible ways to protect your application against SQL injection, i.e. malicious tampering of SQL parameters. Instead of dynamically building SQL statements, use:

    [1] PreparedStatement, which is precompiled and stored in a pool of PreparedStatement objects. PreparedStatement defines setters to register input parameters that are compatible with the supported JDBC SQL data types. For example, setString should be used for input parameters of type VARCHAR or LONGVARCHAR (refer to the Java API for further details). This way of setting input parameters prevents an attacker from manipulating the SQL statement through injection of bad characters, such as apostrophe.

    Example of how to use a PreparedStatement in J2EE:


      // J2EE PreparedStatemenet Example
      // Get a connection to the database
      Connection myConnection;
      if (isDataSourceEnabled()) {
          // using the DataSource to get a managed connection
          Context ctx = new InitialContext();
          myConnection = ((DataSource)ctx.lookup(datasourceName)).getConnection(dbUserName, dbPassword);
      } else {
          try {
              // using the DriverManager to get a JDBC connection
              Class.forName(jdbcDriverClassPath);
              myConnection = DriverManager.getConnection(jdbcURL, dbUserName, dbPassword);
          } catch (ClassNotFoundException e) {
              ...
          }
      }
      ...
      try {
          PreparedStatement myStatement = myConnection.prepareStatement("select * from users where username = ?");
          myStatement.setString(1, userNameField);
          ResultSet rs = myStatement.executeQuery();
          ...
          rs.close();
      } catch (SQLException sqlException) {
          ...
      } finally {
          myStatement.close();
          myConnection.close();
      }

     

    [2] CallableStatement, which extends PreparedStatement to execute database SQL stored procedures. This class inherits input setters from PreparedStatement (see [1] above).

    The following example assumes that this database stored procedure has been created:

    CREATE PROCEDURE select_user (@username varchar(20))
    AS SELECT * FROM USERS WHERE USERNAME = @username;

    Example of how to use a CallableStatement in J2EE to execute the above stored procedure:


      // J2EE PreparedStatemenet Example
      // Get a connection to the database
      Connection myConnection;
      if (isDataSourceEnabled()) {
          // using the DataSource to get a managed connection
          Context ctx = new InitialContext();
          myConnection = ((DataSource)ctx.lookup(datasourceName)).getConnection(dbUserName, dbPassword);
      } else {
          try {
              // using the DriverManager to get a JDBC connection
              Class.forName(jdbcDriverClassPath);
              myConnection = DriverManager.getConnection(jdbcURL, dbUserName, dbPassword);
          } catch (ClassNotFoundException e) {
              ...
          }
      }
      ...
      try {
          PreparedStatement myStatement = myConnection.prepareCall("{?= call select_user ?,?}");
          myStatement.setString(1, userNameField);
          myStatement.registerOutParameter(1, Types.VARCHAR);
          ResultSet rs = myStatement.executeQuery();
          ...
          rs.close();
      } catch (SQLException sqlException) {
          ...
      } finally {
          myStatement.close();
          myConnection.close();
      }

     

    [3] Entity Bean, which represents an EJB business object in a persistent storage mechanism. There are two types of entity beans: bean-managed and container-managed. With bean-managed persistence, the developer is responsible of writing the SQL code to access the database (refer to sections [1] and [2] above). With container-managed persistence, the EJB container automatically generates the SQL code. As a result, the container is responsible of preventing malicious attempts to tamper with the generated SQL code.

    Example of how to use an Entity Bean in J2EE:


      // J2EE EJB Example
      try {
          // lookup the User home interface
          UserHome userHome = (UserHome)context.lookup(User.class);   
          // find the User remote interface
          User = userHome.findByPrimaryKey(new UserKey(userNameField));   
          ...   
      } catch (Exception e) {
          ...
      }

     

    RECOMMENDED JAVA TOOLS
    N/A

    REFERENCES
    http://java.sun.com/j2se/1.4.1/docs/api/java/sql/PreparedStatement.html
    http://java.sun.com/j2se/1.4.1/docs/api/java/sql/CallableStatement.html


    ** Input Data Validation:

    While data validations may be provided as a user convenience on the client-tier, data validation must be performed on the server-tier using Servlets. Client-side validations are inherently insecure because they can be easily bypassed, e.g. by disabling Javascrīpt.

    A good design usually requires the web application framework to provide server-side utility routines to validate the following:
    [1] Required field
    [2] Field data type (all HTTP request parameters are Strings by default)
    [3] Field length
    [4] Field range
    [5] Field options
    [6] Field pattern
    [7] Cookie values
    [8] HTTP Response

    A good practice is to implement the above routine as static methods in a "Validator" utility class. The following sections describe an example validator class.

    [1] Required field
    Always check that the field is not null and its length is greater than zero, excluding leading and trailing white spaces.

    Example of how to validate required fields:


      // Java example to validate required fields
      public Class Validator {
          ...
          public static boolean validateRequired(String value) {
              boolean isFieldValid = false;
              if (value != null && value.trim().length() > 0) {
                  isFieldValid = true;
              }
              return isFieldValid;
          }
          ...
      }
      ...
      String fieldValue = request.getParameter("fieldName");
      if (Validator.validateRequired(fieldValue)) {
          // fieldValue is valid, continue processing request
          ...
      }

     

    [2] Field data type
    In web applications, input parameters are poorly typed. For example, all HTTP request parameters or cookie values are of type String. The developer is responsible for verifying the input is of the correct data type. Use the Java primitive wrapper classes to check if the field value can be safely converted to the desired primitive data type.

    Example of how to validate a numeric field (type int):


      // Java example to validate that a field is an int number
      public Class Validator {
          ...
          public static boolean validateInt(String value) {
              boolean isFieldValid = false;
              try {
                  Integer.parseInt(value);
                  isFieldValid = true;
              } catch (Exception e) {
                  isFieldValid = false;
              }
              return isFieldValid;
          }
          ...
      }
      ...
      // check if the HTTP request parameter is of type int
      String fieldValue = request.getParameter("fieldName");
      if (Validator.validateInt(fieldValue)) {
          // fieldValue is valid, continue processing request
          ...
      }

     

    A good practice is to convert all HTTP request parameters to their respective data types. For example, the developer should store the "integerValue" of a request parameter in a request attribute and use it as shown in the following example:


      // Example to convert the HTTP request parameter to a primitive wrapper data type
      // and store this value in a request attribute for further processing
      String fieldValue = request.getParameter("fieldName");
      if (Validator.validateInt(fieldValue)) {
          // convert fieldValue to an Integer
          Integer integerValue = Integer.getInteger(fieldValue);
          // store integerValue in a request attribute
          request.setAttribute("fieldName", integerValue);
      }
      ...
      // Use the request attribute for further processing
      Integer integerValue = (Integer)request.getAttribute("fieldName");
      ...

     

    The primary Java data types that the application should handle:
    - Byte
    - Short
    - Integer
    - Long
    - Float
    - Double
    - Date

    [3] Field length
    Always ensure that the input parameter (whether HTTP request parameter or cookie value) is bounded by a minimum length and/or a maximum length.

    Example to validate that the length of the userName field is between 8 and 20 characters:


      // Example to validate the field length
      public Class Validator {
          ...
          public static boolean validateLength(String value, int minLength, int maxLength) {
              String validatedValue = value;
              if (!validateRequired(value)) {
                  validatedValue = "";
              }
              return (validatedValue.length() >= minLength &&
                          validatedValue.length() <= maxLength);
          }
          ...
      }
      ...
      String userName = request.getParameter("userName");
      if (Validator.validateRequired(userName)) {
          if (Validator.validateLength(userName, 8, 20)) {
              // userName is valid, continue further processing
              ...
          }
      }

     

    [4] Field range
    Always ensure that the input parameter is within a range as defined by the functional requirements.

    Example to validate that the input numberOfChoices is between 10 and 20:


      // Example to validate the field range
      public Class Validator {
          ...
          public static boolean validateRange(int value, int min, int max) {
              return (value >= min && value <= max);
          }
          ...
      }
      ...
      String fieldValue = request.getParameter("numberOfChoices");
      if (Validator.validateRequired(fieldValue)) {
          if (Validator.validateInt(fieldValue)) {
              int numberOfChoices = Integer.parseInt(fieldValue);
              if (Validator.validateRange(numberOfChoices, 10, 20)) {
                  // numberOfChoices is valid, continue processing request
                  ...
              }
          }
      }

     

    [5] Field options
    Often, the web application presents the user with a set of options to choose from, e.g. using the SELECT HTML tag, but fails to perform server-side validation to ensure that the selected value is one of the allowed options. Remember that a malicious user can easily modify any option value. Always validate the selected user value against the allowed options as defined by the functional requirements.

    Example to validate the user selection against a list of allowed options:


      // Example to validate user selection against a list of options
      public Class Validator {
          ...
          public static boolean validateOption(Object[] options, Object value) {
              boolean isValidValue = false;
              try {
                  List list = Arrays.asList(options);
                  if (list != null) {
                      isValidValue = list.contains(value);
                  }
              } catch (Exception e) {
              }
              return isValidValue;
          }
          ...
      }
      ...
      // Allowed options
      String[] ōptions = {"option1", "option2", "option3");
      // Verify that the user selection is one of the allowed options
      String userSelection = request.getParameter("userSelection");
      if (Validator.validateOption(options, userSelection)) {
          // valid user selection, continue processing request
          ...
      }

     

    [6] Field pattern
    Always check that the user input matches a pattern as defined by the functionality requirements. For example, if the userName field should only allow alpha-numeric characters, case insensitive, then use the following regular expression:
    ^[a-zA-Z0-9]*$

    Java 1.3 or earlier versions do not include any regular expression packages. Apache Regular Expression Package (see Resources below) is recommended for use with Java 1.3 to resolve this lack of support. Example to perform regular expression validation:


      // Example to validate that a given value matches a specified pattern
      // using the Apache regular expression package
      import org.apache.regexp.RE;
      import org.apache.regexp.RESyntaxException;
      public Class Validator {
          ...
          public static boolean matchPattern(String value, String expression) {
              boolean match = false;
              if (validateRequired(expression)) {
                   RE r = new RE(expression);
                   match = r.match(value);            
              }
              return match;
          }
          ...
      }
      ...
      // Verify that the userName request parameter is alpha-numeric
      String userName = request.getParameter("userName");
      if (Validator.matchPattern(userName, "^[a-zA-Z0-9]*$")) {
          // userName is valid, continue processing request
          ...
      }

     

    Java 1.4 introduced a new regular expression package (java.util.regex). Here is a modified version of Validator.matchPattern using the new Java 1.4 regular expression package:


      // Example to validate that a given value matches a specified pattern
      // using the Java 1.4 regular expression package
      import java.util.regex.Pattern;
      import java.util.regexe.Matcher;
      public Class Validator {
          ...
          public static boolean matchPattern(String value, String expression) {
              boolean match = false;
              if (validateRequired(expression)) {
                  match = Pattern.matches(expression, value);
              }
              return match;
          }
          ...
      }

     

    [7] Cookie value
    Use the javax.servlet.http.Cookie object to validate the cookie value. The same validation rules (described above) apply to cookie values depending on the application requirements, e.g. validate a required value, validate length, etc.

    Example to validate a required cookie value:


      // Example to validate a required cookie value
      // First retrieve all available cookies submitted in the HTTP request
      Cookie[] cookies = request.getCookies();
      if (cookies != null) {
          // find the "user" cookie
          for (int i=0; i<cookies.length; ++i) {
              if (cookies[i].getName().equals("user")) {
                  // validate the cookie value
                  if (Validator.validateRequired(cookies[i].getValue()) {
                      // valid cookie value, continue processing request
                      ...
                  }
              }   
          }
      }

     

    [8] HTTP Response
    [8-1] Filter user input
    To guard the application against cross-site scrīpting, sanitize HTML by converting sensitive characters to their corresponding character entities. These are the HTML sensitive characters:
    < > " ' % ; ) ( & +

    Example to filter a specified string by converting sensitive characters to their corresponding character entities:


      // Example to filter sensitive data to prevent cross-site scrīpting
      public Class Validator {
          ...
          public static String filter(String value) {
              if (value == null) {
                  return null;
              }       
              StringBuffer result = new StringBuffer(value.length());
              for (int i=0; i<value.length(); ++i) {
                  switch (value.charAt(i)) {
                  case '<':
                      result.append("&lt;");
                      break;
                  case '>':
                      result.append("&gt;");
                      break;
                  case '"':
                      result.append("&quot;");
                      break;
                  case '\'':
                      result.append("&#39;");
                      break;
                  case '%':
                      result.append("&#37;");
                      break;
                  case ';':
                      result.append("&#59;");
                      break;
                  case '(':
                      result.append("&#40;");
                      break;
                  case ')':
                      result.append("&#41;");
                      break;
                  case '&':
                      result.append("&amp;");
                      break;
                  case '+':
                      result.append("&#43;");
                      break;
                  default:
                      result.append(value.charAt(i));
                      break;
              }       
              return result;
          }
          ...
      }
      ...
      // Filter the HTTP response using Validator.filter
      PrintWriter ōut = response.getWriter();
      // set output response
      out.write(Validator.filter(response));
      out.close();

     

    The Java Servlet API 2.3 introduced Filters, which supports the interception and transformation of HTTP requests or responses.

    Example of using a Servlet Filter to sanitize the response using Validator.filter:


      // Example to filter all sensitive characters in the HTTP response using a Java Filter.
      // This example is for illustration purposes since it will filter all content in the response, including HTML tags!
      public class SensitiveCharsFilter implements Filter {
          ...
          public void doFilter(ServletRequest request,
                          ServletResponse response,
                          FilterChain chain)
                  throws IOException, ServletException {
              PrintWriter ōut = response.getWriter();
              ResponseWrapper wrapper = new ResponseWrapper((HttpServletResponse)response);
              chain.doFilter(request, wrapper);
              CharArrayWriter caw = new CharArrayWriter();
              caw.write(Validator.filter(wrapper.toString()));
             
              response.setContentType("text/html");
              response.setContentLength(caw.toString().length());
              out.write(caw.toString());
              out.close();
          }
          ...
          public class CharResponseWrapper extends HttpServletResponseWrapper {
              private CharArrayWriter output;
              public String toString() {
                  return output.toString();
              }
         
              public CharResponseWrapper(HttpServletResponse response){
                  super(response);
                  ōutput = new CharArrayWriter();
              }
             
              public PrintWriter getWriter(){
                  return new PrintWriter(output);
              }
          }
      }
      }

     

    [8-2] Secure the cookie
    When storing sensitive data in a cookie, make sure to set the secure flag of the cookie in the HTTP response, using Cookie.setSecure(boolean flag) to instruct the browser to send the cookie using a secure protocol, such as HTTPS or SSL.

    Example to secure the "user" cookie:


      // Example to secure a cookie, i.e. instruct the browser to
      // send the cookie using a secure protocol
      Cookie cookie = new Cookie("user", "sensitive");
      cookie.setSecure(true);
      response.addCookie(cookie);

     

    RECOMMENDED JAVA TOOLS
    The two main Java frameworks for server-side validation are:
    [1] Jakarta Commons Validator (integrated with Struts 1.1)
    The Jakarta Commons Validator is a powerful framework that implements all the above data validation requirements. These rules are configured in an XML file that defines input validation rules for form fields. Struts supports output filtering of dangerous characters in the [8] HTTP Response by default on all data written using the Struts 'bean:write' tag. This filtering may be disabled by setting the 'filter=false' flag.

    Struts defines the following basic input validators, but custom validators may also be defined:
    required: succeeds if the field contains any characters other than whitespace.
    mask: succeeds if the value matches the regular expression given by the mask attribute.
    range: succeeds if the value is within the values given by the min and max attributes ((value >= min) & (value <= max)).
    maxLength: succeeds if the field is length is less than or equal to the max attribute.
    minLength: succeeds if the field is length is greater than or equal to the min attribute.
    byte, short, integer, long, float, double: succeeds if the value can be converted to the corresponding primitive.
    date: succeeds if the value represents a valid date. A date pattern may be provided.
    creditCard: succeeds if the value could be a valid credit card number.
    email: succeeds if the value could be a valid e-mail address.

    Example to validate the userName field of a loginForm using Struts Validator:

      <form-validation>
          <global>
              ...
              <validator name="required"
                  classname="org.apache.struts.validator.FieldChecks"
                  method="validateRequired"
                  msg="errors.required">
              </validator>
              <validator name="mask"
                  classname="org.apache.struts.validator.FieldChecks"
                  method="validateMask"
                  msg="errors.invalid">
              </validator>
              ...
          </global>
          <formset>
              <form name="loginForm">
                  <!-- userName is required and is alpha-numeric case insensitive -->
                  <field property="userName" depends="required,mask">
                      <!-- message resource key to display if validation fails -->
                      <msg name="mask" key="login.userName.maskmsg"/>
                      <arg0 key="login.userName.displayname"/>
                      <var>
                          <var-name>mask</var-name>
                          <var-value>^[a-zA-Z0-9]*$</var-value>
                      </var>
                  </field>
              ...
              </form>
              ...
          </formset>
      </form-validation>

     

    [2] JavaServer Faces Technology
    JavaServer Faces Technology is a set of Java APIs (JSR 127) to represent UI components, manage their state, handle events and input validation.

    The JavaServer Faces API implements the following basic validators, but custom validators may be defined:
    validate_doublerange: registers a DoubleRangeValidator on a component
    validate_length: registers a LengthValidator on a component
    validate_longrange: registers a LongRangeValidator on a component
    validate_required: registers a RequiredValidator on a component
    validate_stringrange: registers a StringRangeValidator on a component
    validator: registers a custom Validator on a component

    The JavaServer Faces API defines the following UIInput and UIOutput Renderers (Tags):
    input_date: accepts a java.util.Date formatted with a java.text.Date instance
    output_date: displays a java.util.Date formatted with a java.text.Date instance
    input_datetime: accepts a java.util.Date formatted with a java.text.DateTime instance
    output_datetime: displays a java.util.Date formatted with a java.text.DateTime instance
    input_number: accepts a numeric data type (java.lang.Number or primitive), formatted with a java.text.NumberFormat
    output_number: accepts a numeric data type (java.lang.Number or primitive), formatted with a java.text.NumberFormat
    input_text: accepts a text string of one line.
    output_text: displays a text string of one line.
    input_time: accepts a java.util.Date, formatted with a java.text.DateFormat time instance
    output_time: displays a java.util.Date, formatted with a java.text.DateFormat time instance
    input_hidden: allows a page author to include a hidden variable in a page
    input_secret: accepts one line of text with no spaces and displays it as a set of asterisks as it is typed
    input_textarea: accepts multiple lines of text
    output_errors: displays error messages for an entire page or error messages associated with a specified client identifier
    output_label: displays a nested component as a label for a specified input field
    output_message: displays a localized message

    Example to validate the userName field of a loginForm using JavaServer Faces:

      <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
      <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
      ...
      <jsp:useBean id="UserBean"
          class="myApplication.UserBean" scope="session" />
      <f:use_faces>
        <h:form formName="loginForm" >
          <h:input_text id="userName" size="20" modelReference="UserBean.userName">
              <f:validate_required/>
              <f:validate_length minimum="8" maximum="20"/>   
          </h:input_text>
          <!-- display errors if present -->
          <h:output_errors id="loginErrors" clientId="userName"/>
          <h:command_button id="submit" label="Submit" commandName="submit" /><p>
        </h:form>
      </f:use_faces>

     


    REFERENCES
    Java API 1.3 - http://java.sun.com/j2se/1.3/docs/api/
    Java API 1.4 - http://java.sun.com/j2se/1.4/docs/api/
    Java Servlet API 2.3 - http://java.sun.com/products/servlet/2.3/javadoc/
    Java Regular Expression Package - http://jakarta.apache.org/regexp/
    Jakarta Validator - http://jakarta.apache.org/commons/validator/
    JavaServer Faces Technology - http://java.sun.com/j2ee/javaserverfaces/

    ** Error Handling:

    Many J2EE web application architectures follow the Model View Controller (MVC) pattern. In this pattern a Servlet acts as a Controller. A Servlet delegates the application processing to a JavaBean such as an EJB Session Bean (the Model). The Servlet then forwards the request to a JSP (View) to render the processing results. Servlets should check all input, output, return codes, error codes and known exceptions to ensure that the expected processing actually occurred.

    While data validation protects applications against malicious data tampering, a sound error handling strategy is necessary to prevent the application from inadvertently disclosing internal error messages such as exception stack traces. A good error handling strategy addresses the following items:

    [1] Defining Errors
    [2] Reporting Errors
    [3] Rendering Errors
    [4] Error Mapping

    [1] Defining Errors
    Hard-coded error messages in the application layer (e.g. Servlets) should be avoided. Instead, the application should use error keys that map to known application failures. A good practice is to define error keys that map to validation rules for HTML form fields or other bean properties. For example, if the "user_name" field is required, is alphanumeric, and must be unique in the database, then the following error keys should be defined:

    (a) ERROR_USERNAME_REQUIRED: this error key is used to display a message notifying the user that the "user_name" field is required;
    (b) ERROR_USERNAME_ALPHANUMERIC: this error key is used to display a message notifying the user that the "user_name" field should be alphanumeric;
    (c) ERROR_USERNAME_DUPLICATE: this error key is used to display a message notifying the user that the "user_name" value is a duplicate in the database;
    (d) ERROR_USERNAME_INVALID: this error key is used to display a generic message notifying the user that the "user_name" value is invalid;

    A good practice is to define the following framework Java classes which are used to store and report application errors:

    - ErrorKeys: defines all error keys


          // Example: ErrorKeys defining the following error keys:   
          //    - ERROR_USERNAME_REQUIRED
          //    - ERROR_USERNAME_ALPHANUMERIC
          //    - ERROR_USERNAME_DUPLICATE
          //    - ERROR_USERNAME_INVALID
          //    ...
          public Class ErrorKeys {
              public static final String ERROR_USERNAME_REQUIRED = "error.username.required";
              public static final String ERROR_USERNAME_ALPHANUMERIC = "error.username.alphanumeric";
              public static final String ERROR_USERNAME_DUPLICATE = "error.username.duplicate";
              public static final String ERROR_USERNAME_INVALID = "error.username.invalid";
              ...
          }

     

    - Error: encapsulates an individual error


          // Example: Error encapsulates an error key.
          // Error is serializable to support code executing in multiple JVMs.
          public Class Error implements Serializable {
             
              // Constructor given a specified error key
              public Error(String key) {
                  this(key, null);
              }
             
              // Constructor given a specified error key and array of placeholder objects
              public Error(String key, Object[] values) {
                  this.key = key;
                  this.values = values;
              }
             
              // Returns the error key
              public String getKey() {
                  return this.key;
              }
             
              // Returns the placeholder values
              public Object[] getValues() {
                  return this.values;
              }
             
              private String key = null;
              private Object[] values = null;
          }   

     

    - Errors: encapsulates a Collection of errors


          // Example: Errors encapsulates the Error objects being reported to the presentation layer.
          // Errors are stored in a HashMap where the key is the bean property name and value is an
          // ArrayList of Error objects.
          public Class Errors implements Serializable {
         
              // Adds an Error object to the Collection of errors for the specified bean property.
              public void addError(String property, Error error) {
                  ArrayList propertyErrors = (ArrayList)errors.get(property);
                  if (propertyErrors == null) {
                      propertyErrors = new ArrayList();
                      errors.put(property, propertyErrors);
                  }
                  propertyErrors.put(error);           
              }
             
              // Returns true if there are any errors
              public boolean hasErrors() {
                  return (errors.size > 0);
              }
             
              // Returns the Errors for the specified property
              public ArrayList getErrors(String property) {
                  return (ArrayList)errors.get(property);
              }
              private HashMap errors = new HashMap();
          }

     

    Using the above framework classes, here is an example to process validation errors of the "user_name" field:


      // Example to process validation errors of the "user_name" field.
      Errors errors = new Errors();
      String userName = request.getParameter("user_name");
      // (a) Required validation rule
      if (!Validator.validateRequired(userName)) {
          errors.addError("user_name", new Error(ErrorKeys.ERROR_USERNAME_REQUIRED));
      } // (b) Alpha-numeric validation rule
      else if (!Validator.matchPattern(userName, "^[a-zA-Z0-9]*$")) {
          errors.addError("user_name", new Error(ErrorKeys.ERROR_USERNAME_ALPHANUMERIC));
      }
      else
      {
          // (c) Duplicate check validation rule
          // We assume that there is an existing UserValidationEJB session bean that implements
          // a checkIfDuplicate() method to verify if the user already exists in the database.
          try {
              ...       
              if (UserValidationEJB.checkIfDuplicate(userName)) {
                  errors.addError("user_name", new Error(ErrorKeys.ERROR_USERNAME_DUPLICATE));
              }
          } catch (RemoteException e) {
              // log the error
              logger.error("Could not validate user for specified userName: " + userName);
              errors.addError("user_name", new Error(ErrorKeys.ERROR_USERNAME_DUPLICATE);
          }
      }
      // set the errors object in a request attribute called "errors"
      request.setAttribute("errors", errors);
      ...

     

    [2] Reporting Errors
    There are two ways to report web-tier application errors:
    (a) Servlet Error Mechanism
    (b) JSP Error Mechanism

    [2-a] Servlet Error Mechanism
    A Servlet may report errors by:
    - forwarding to the input JSP (having already stored the errors in a request attribute), OR
    - calling response.sendError with an HTTP error code argument, OR
    - throwing an exception

    It is good practice to process all known application errors (as described in section [1]), store them in a request attribute, and forward to the input JSP. The input JSP should display the error messages and prompt the user to re-enter the data. The following example illustrates how to forward to an input JSP (userInput.jsp):


      // Example to forward to the userInput.jsp following user validation errors
      RequestDispatcher rd = getServletContext().getRequestDispatcher("/user/userInput.jsp");
      if (rd != null) {
          rd.forward(request, response);
      }

     

    If the Servlet cannot forward to a known JSP page, the second option is to report an error using the response.sendError method with HttpServletResponse.SC_INTERNAL_SERVER_ERROR (status code 500) as argument. Refer to the javadoc of javax.servlet.http.HttpServletResponse for more details on the various HTTP status codes. Example to return a HTTP error:


      // Example to return a HTTP error code
      RequestDispatcher rd = getServletContext().getRequestDispatcher("/user/userInput.jsp");
      if (rd == null) {
          // messages is a resource bundle with all message keys and values
          response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                                  messages.getMessage(ErrorKeys.ERROR_USERNAME_INVALID));
      }

     

    As a last resort, Servlets can throw an exception, which must be a subclass of one of the following classes:
    - RuntimeException
    - ServletException
    - IOException

    [2-b] JSP Error Mechanism
    JSP pages provide a mechanism to handle runtime exceptions by defining an errorPage directive as shown in the following example:


          <%@ page errorPage="/errors/userValidation.jsp" %>

     

    Uncaught JSP exceptions are forwarded to the specified errorPage, and the original exception is set in a request parameter called javax.servlet.jsp.jspException. The error page must include a isErrorPage directive as shown below:


          <%@ page isErrorPage="true" %>

     

    The isErrorPage directive causes the "exception" variable to be initialized to the exception object being thrown.

    [3] Rendering Errors
    The J2SE Internationalization APIs provide utility classes for externalizing application resources and formatting messages including:

    (a) Resource Bundles
    (b) Message Formatting

    [3-a] Resource Bundles
    Resource bundles support internationalization by separating localized data from the source code that uses it. Each resource bundle stores a map of key/value pairs for a specific locale.

    It is common to use or extend java.util.PropertyResourceBundle, which stores the content in an external properties file as shown in the following example:


      ################################################
      # ErrorMessages.properties
      ################################################
      # required user name error message
      error.username.required=User name field is required
      # invalid user name format
      error.username.alphanumeric=User name must be alphanumeric
      # duplicate user name error message
      error.username.duplicate=User name {0} already exists, please choose another one
      ...

     

    Multiple resources can be defined to support different locales (hence the name resource bundle). For example, ErrorMessages_fr.properties can be defined to support the French member of the bundle family. If the resource member of the requested locale does not exist, the default member is used. In the above example, the default resource is ErrorMessages.properties. Depending on the user's locale, the application (JSP or Servlet) retrieves content from the appropriate resource.

    [3-b] Message Formatting
    The J2SE standard class java.util.MessageFormat provides a generic way to create messages with replacement placeholders. A MessageFormat object contains a pattern string with embedded format specifiers as shown below:


      // Example to show how to format a message using placeholder parameters
      String pattern = "User name {0} already exists, please choose another one";
      String userName = request.getParameter("user_name");
      Object[] args = new Object[1];
      args[0] = userName;
      String message = MessageFormat.format(pattern, args);

     

    Here is a more comprehensive example to render error messages using ResourceBundle and MessageFormat:


      // Example to render an error message from a localized ErrorMessages resource (properties file)
      // Utility class to retrieve locale-specific error messages
      public Class ErrorMessageResource {
         
          // Returns the error message for the specified error key in the environment locale
          public String getErrorMessage(String errorKey) {
              return getErrorMessage(errorKey, defaultLocale);
          }
         
          // Returns the error message for the specified error key in the specified locale
          public String getErrorMessage(String errorKey, Locale locale) {
              return getErrorMessage(errorKey, null, locale);
          }
         
          // Returns a formatted error message for the specified error key in the specified locale
          public String getErrorMessage(String errorKey, Object[] args, Locale locale) {   
              // Get localized ErrorMessageResource
              ResourceBundle errorMessageResource = ResourceBundle.getBundle("ErrorMessages", locale);
              // Get localized error message
              String errorMessage = errorMessageResource.getString(errorKey);
              if (args != null) {
                  // Format the message using t

  • 学习loadrunner性能测试建议路线图

    2008-03-19 23:02:41

  • 扩展LoadRunner功能的一种实现思路

    2008-03-19 22:57:14

    http://bbs.51testing.com/viewthread.php?tid=108978&pid=916421&page=1&extra=page%3D2

    由于时间关系,没有来得及实现。呵呵,供各位碰到同类问题的同学参考。

       具体的实现思路可以和我再交流.
        附件提出一种比较复杂的协议的扩展思路 。

       

1616/9<123456789>
Open Toolbar