前两天因为需要修正一个Windows Live Contacts Gadget在https连接下无法工作的错误,在dev machine的IIS上设置了一下SSL功能。
大家都知道要开启SSL服务关键需要两个东西:
1. A Certificate Authority (such VeriSign.com)
2. A site certificate
如果你使用的是Windows Server 2003或者XP Advanced Server,你其实可以利用系统提供的“Certificate Services”服务来“冒充”一个CA并给自己发一个site certificate,这里有一个tutorial:
Building your own certificate authority: http://searchwindowssecurity.techtarget.com/tip/1,289483,sid45_gci1110403,00.html
如果你使用的是XP Professional,就没有CA服务了。但作为程序调试或测试用的话,其实就只需要生成一个self-signed certificate就可以了。等browser提示你是否接受这个untrusted certificate的时候,只要选Yes就行。
生成self-signed certificate有很多方法。稍微繁琐一点的可以用OpenSSL (OpenSSL for windows: http://www.openssl.org/related/binaries.html)或者keytool (http://java.sun.com/j2se/1.4.2/docs/tooldocs/solaris/keytool.html)来sign一个certificate,然后再在IIS中导入这个certificate就行了。如果你想对IIS的相关设置有所了解的话,可以试试做一遍,这里也有一个tutorial:
Enabling SSL in IIS on Windows XP Professional: http://www.somacon.com/p41.php
当然,如果你想省掉所有这些麻烦也行,最简单的在IIS启动SSL的方法只要3步:
1. 下载 IIS 6.0 Resource Kit Tools: http://www.microsoft.com/downloads/details.aspx?FamilyID=56fc92ee-a71a-4c73-b628-ade629c89499&DisplayLang=en
2. 安装.
3. “All Programs->IIS Resources->SelfSSL->SelfSSL”, 在命令行中键入 “selfssl”, 回答 “y”, and you are done.
现在你试试在browser里访问:https://localhost,你会发现会出现一个窗口询问是否接受一个untrusted certificate,选Yes, and you are in a safe channel now.
在channel 9上有一个Danny Thorpe的interview,主要是聊到新发布的Windows Live Contacts Gadget。
Contacts Gadget的关键在于一个设计很巧妙的用来绕过“臭名昭著”的prevention of cross domain scripting的channel mechanism。Danny在interview里概括地介绍了这个技巧的实现思路。
Cross Domain Scripting一直是web hacking最主要的手段之一,所以所有的browser, as far as I know,都在某种程度上地禁止了cross domain scripting。当然,实现的手段和限制的程度都有所不同。比如在FireFox里,除非你的scripts是signed,否则你无法从domain A的webpage里用XMLHttpRequest.open去调用domain B里的一个web service,即使你用netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead")来escalate权限也不行。而在IE中,你可以做到。
这样的防护手段有提高安全性的好处,但有时也限制了web app的实现功能。而绕过browser的限制,或者说,在受控的情况下允许cross domain calling,是很多web develop platform在实现的主要功能之一。比如Flash就有它自己独到的方法。
在Contact Gadget里用到的channel mechanism也是一种方法,虽然它还有很多缺陷,不过我们仍然在做很多工作让它更完善而实用。
- Yet another IPC method.
这是前几天一个同学让我帮忙做的一点东西,他一端有一个做Speech Recognition的C#程序,另一端是控制一个voice collector的C++程序(因为collector的sdk是C++的),但在两个进程间传递信息的时候遇到了点麻烦。
传统的Windows IPC有蛮多的方法的,比如named piple, shared memory map,等等。这里要讲的是yet another method: Event Tracing for Windows (ETW)。
至于Managed<->Unmanaged程序之间的通信转换问题,理论上来讲是容易的:既然两个unmanaged program可以通信,那么只要把一端用managed code wrap一下就好了。但在实际操作中其中会有很多细小的问题。比如calling convention的差异,name managling,等等。
这里有我写的一个Demo,一共有4个部分:
1. Provider: 信息发送端 (C/C++ code)
2. Consumer: 信息接受端 (C/C++ code)
3. Managed: 是Consumer的一个wrapper (managed C++)
4. Demo: 用Managed.dll来调用Consumer的功能 (C#)
编译后,先运行Provider.exe, 是一个console program. 然后再运行Demo.exe(注意:并没有UI显示)。然后你可以在Provider.exe的console里打数字(注意:numerical value only, 否则程序可能会crash,this is just a demo, so I am kinda sloppy on error checking.),比如:2, enter, 3, enter, 8, enter, 0, enter. 0代表输入完毕了,这时Demo.exe的UI就出现了,而且纪录下了你从Provider.exe发过来的这串secret word.
下面是我很久以前写的一个tutorial,不过那时没有涉及到mananged和unmanaged code之间的通信,只是介绍ETW的用法。
=============================================================
最近在用Event Tracing for Windows (简称ETW) 做Longhorn里resource cache loader和resource cache service之间的通讯。不知道ETW这个东东MS外面的人用的多不多?Anyway,从我使用的经验来讲,觉得这是一个不错的IPC方法,至少除了Named Pipe之外,你还有另一种选择(shared memory map当然也可以,但我的意思是那种有点像网络通讯的传递方式)。
ETW主要包括3个component:Controller, Provider, and Consumer. 这3个的角色从名字一看就清楚了。我简单介绍一下使用的方法:
Provider首先应该用RegisterTraceGuids注册一个Event Trace,同时提供给RegisterTraceGuids的还有一个ControlCallback,这个callback在Provider被Controller启动(enable)和停止(disable)的时候会被调用,然后Provider就可以相应地开始用TraceEvent来发送Event Trace或者停止发送。当然,Provider还要通过这个callback的一个参数来了解应该往哪里送trace,这个参数就是一个由Controller打开的event trace session。什么是event trace session?往下看
Controller的主要任务有两个:一是用StartTrace在内存中创建一个event trace session,这样Provider就知道该往哪里送trace,而Controller也会负责将session里记录的trace送到Consumer手里。Controller的第二个任务就是启动(API: EnableTrace)和停止(API: ControlTrace)Provider。为了避免额外的开销,Provider不会一直都在工作,只有当被Enable的时候,才开始工作(注:其实这么说是不正确的,Provider其实是不必收Controller控制的,它可以随时随地发送trace,只要它知道那个event trace session的句柄,这完全取决于Provider具体是怎么写的。但在实际操作上,Provider都是根据Controller的Enable/Disable信号来启动和停止tracing的。我自己写的一个snippet program是这样,其他现有的正规的Provider也是这样。)
第三个是Consumer,Consumer主要做这几件事:1. 用OpenTrace打开和event trace session之间的通道。2. 设计event trace callback,你可以设计一个generic的callback用来handle所有的event trace,不管是不是你感兴趣的。你也可以为特定的event trace设计callback,专门处理你关心的trace。Generic的callback实在OpenTrace的时候在参数中指定的,而特定的callback可以用SetTraceCallback来注册。3. 调用ProcessTrace,开始处理Trace。注意,这里有一个很tricky的地方:ProcessTrace是block的!就是说ProcessTrace不会返回,除非Controller结束这个session或者Consumer自己调用CloseTrace(注:CloseTrace只有在Longhorn可以使ProcessTrace返回,XP不行)。呵呵,那你问了,ProcessTrace都不返回,我的Consumer还怎么调用CloseTrace啊?答案很简单:你需要第二个线程,那个线程什么也没干,就调用了ProcessTrace,然后它就待在那里,直到Consumer的主线程调用CloseTrace或者Controller关闭了整个session。我知道这个方法很奇怪,但,不要问我,这是ETW team给我的答案,他们肯定有他们的考虑。
最后想说的是:很多时候你会发现,Controller和Consumer都是在一个program里的。这个很好理解,Provider都在场面上了,你要用它们发送的trace来取得信息,你的程序当然会既做Controller (打开session,启动Provider)又做Consumer。
看到Keso的“三言二拍:微软指责新浪抄袭”(Trackback),自己也想说两句。
先简略说一下事情的概要吧:8月31日,Windows Live Expo组的manager,Garry Wiseman在team blog上发布了一则消息,指责sina.com抄袭了前一版Live Expo界面设计上的一些元素和思路。这个消息被TechCrunch报道以后,迅速传播开来。Garry后来更关闭了他那则帖子的评论功能,删除了原有的评论。
我的一些看法:
1. IMHO, Garry的处理是不太明智的。我不知道是什么触动了他的神经,让他起初的反应如此激烈以至于用了"steal"一词,但无论如何,他的post对解决问题既起不了他所说的:“to raise the issue of cross-border copyright infrigments ”,更拉不到同情分,只能给公司带来negative publicity。 而此后的关闭评论之类的举动更是负薪救火,雪上加霜。
2. Garry并没有提出令人信服的证据,客观的讲,从截图来看,新浪的界面确有类似于Live Expo的地方,但实在还不足以作为呈堂证供,而在第三者看来微软也实在小题大做。我相信,从专业web设计的角度来讲,确实有一些关键的细节元素令Garry觉得新浪不经授权地使用了Live Expo的设计,但问题是你在blog这样一个半专业的媒介上发布这样的消息,最好考虑到读者对信息的接受层次。就现在Garry自己拿出的证据来讲,实在是比较牵强。
3. Keso的帖子,也没什么专业水准,甚至可以说是及其幼稚的,基本属于图个口舌之快。比如说什么“可以说IE7偷了Maxthon和Firefox的设计;微软MSN搜索偷了Google搜索的设计;微软本地搜索偷了Google Maps的设计”,这些评论虽然有戏谑的成分,但要比Garry的指控更不着边际。至于“微软偷得更彻底、更本质、更高明,新浪与微软相比,偷窃技术还差得太远,该拜微软为师。”,这种恶意的攻击对良性的讨论和理智的思考毫无意义,只能让人感觉到作者是要出一口恶气。
4. Garry Wiseman不等于微软。这个也是转载这条新闻的几乎所有媒体都犯了的错误。微软的小组的Team Blog上的言论完全是由group member自行控制的,甚至post帖子基本都不经过“民主集中制”,所以Garry的言论只代表他个人的意见。不是微软公司的立场。Keso喜欢把Garry扩大到代表整个微软,那我也没办法。我只想说,微软是一个很多元的团队,并不是每个人都同意Garry的立场,至少我不是。
5. 如果是一般人的blog,我也大可不必这么在意评论的专业性。但Keso作为中国IT界最负盛名的blogger,应该体现不流于一般的专业素养。是的,他说过“少跟我提客观”这样的论调,这是他的自由,我表示尊重。我只是觉得,像这样充满了互相恶意攻击、cheap shot、冷嘲热讽、唯恐天下不乱的内容的post,实在有失Keso一贯的职业表现。
Keso所写的“一条壮汉泪眼婆娑故作可怜状”和Garry所写的“Couldn't they afford to hire a designer?”一样,都很幼稚。
===============================================================
Disclaimer: Microsoft Weekly News Wire 是每周微软相关新闻的一个摘录,以技术新闻为主,一般选取10条左右的消息,以时间降序排列。当然,每个星期关于微软不可能只有10条新闻,我只是根据自己的判断选录一些重要或有趣的消息。
美国时间本周五(北京时间周六),微软发布了Windows Vista RC1。这应该说是本周的最重要的一件事了,但一来展波前辈已经先发布了消息,二来真正能用到Vista RC1的普通读者未必很多,我这里就不说了,展波前辈的blog里有详细消息。
Reuse code and encapsulate frozen code
- 比如下列的code就可以分离出来
function buildRequest(target,method,params,handler,isAsync) {
var req = window.XmlHTTPRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
if(req) {
req.open(method, target, isAsync); req.setRequestHeader("Content-type","application/x-www-form-urlencoded");
req.setRequestHeader("Content-length",params.length);
if(handler && isAsync)
req.onreadystatechange = eval(handler);
return req;
}
}
Use Relative references to elements using DOM
- 尽量使用parentNode, previousSibling, nextSibling, childNodes等等。这有两个好处:1. 省掉了getElementById的hash lookup。2. 不需要maintian一堆的element id,这样webpage的payload就减小了一点。当然这也有缺点,就是code比较难懂了,呵呵,加comment吧。那么有人就说了:加了comment,payload不是反而大了么。呵呵,其实商业的javascript程序在发布前都需要用comment stripper处理过的,带comment的源文件只是内部使用。
Use external JavaScript files
- 最主要的目的当然是caching,大量的内嵌javascript会增加page load time。如果分离成一个独立的js文件而其他文件间接reference的话,那用户只需要下载一次这个js文件,browser会自动cache的(除非你改掉了browser的默认设置)。当然有一个问题是如果你server端的js文件更新了怎么办?如果client端cahce下来的js文件还没有expire,那么用户就不会使用你更新后的程序逻辑了。这个也是可以简单解决的,就是在js文件后面加一个versioning query variable:proxy.js?v=101,当你更新了js文件后,只要在deploy的时候改动一下这个query variable就可以了。
Use Synchronous XMLHTTP request, when Asynchronous Call is not needed.
- 这让你对程序的follow有更好的控制,并且,async call会调用4到5次的callback handler(depending on which browser the client is using)。那些都是不必要的浪费。
Use Server side validations with AJAX
- 原因很简单:
1. ASP.NET 1.1提供的client-side validator controls很多和FireFox不兼容,you are dead. ASP.NET 2.0应该没问题。
2. 把关键的validation logic推到client side确实减轻了server的负担,但从安全上看,完全是打开了cross domain scripting的闸门,恶意的攻击者可以直接绕过你的validation(because it's all downloaded to the client side!!),然后往你的数据库里放一些小礼物...
当然这些理由都不是绝对的,just keep this in mind.
Balance server calls, use forward-fetch or timer based fetch if events are higher in number
- 比如你要显示一个很大的data grid,一屏显示不完,data grid control上有一个scroll bar。那么你完全可以在每次处理scroll event的时候预先多下载几个row,这样在user再次滚动scroll bar的时候,你就可以直接显示刚才pre-fetch的内容了。再想想那些keyword autocompletion (比如你在gmail里打email address的时候,gmail会自动提示匹配的address),如果每个keypress event我们都提交一个request的话,那按现在用户平均的打字速度,这个程序基本就不要用了。
有人说,反正是async call,不怕。呵呵,其实AJAX不是真的asynchronous,AJAX是bi-synchronous的,就是说,任何时刻,只能有两个active的asynch call,多的asynch call全部被queue起来了。IE如此,FireFox亦如此。所以太多的asynch call的话,用户是不会喜欢的。
一个解决的方法是用timer based fetch,比如上面这个keyword autocompletion的例子,当用户键入第一个字母的时候,我们一方面向server提交request要求匹配的autocompletion,同时我们又设置一个timer(say, expires in 500 msec),如果在这个timer expire之前用户又键入了一些字母,我们就不重复提交request了。这个方法很简单,但也足够有效了。(注:我不知道google是否用的这种方法,just cited as an example)