2009年6月14日星期日

从技术层面分析“绿坝-花季护航”存在的问题

  工信部日前下发《关于计算机预装绿色上网过滤软件的通知》,要求在7月1日之后在我国所有销售的个人电脑预装该软件,这个消息在网络上引起了轩然大波,网友纷纷质疑:软件是否会被强制使用?网友的隐私能否得到有效保护?软件一年的注册费用真的值4170万吗?我先前曾经对此做过一些简单的评论,今天我将从技术层面对“绿坝-花季护航”可能存在的问题再进行一些探讨。

  软件产品的质量是否合格

  从技术上将,“绿坝-花季护航”对于文字信息的审查是通过巨大的关键字库进行过滤分析的,将需要审查的文字进行分词处理,然后进行关键词对比过滤,有可能使用了TF-IDF对词频进行分析以确定文章的主要内容,进行语义分析,同时“绿坝”具有在线更新数据库功能,可以定时同步最新的关键词列表。根据已经公布的一些关键词以及网友实际测试效果来看,在很大程度上会存在“误判”的可能性,有可能会将用户浏览的正常网页或者文档误判为“有害信息”。

  对于色情图片的检测可能使用了一些开源产品,通过肤色分割模型对色情图片进行检测,设置不同的阈值会出现不同的误差率。在很多情况下会错误的将带有大量肤色的图片判断为色情图片,同时,对于黑人的色情图片却无法识别。

  总的来说,该软件在语义分析上的判断准确性,比起百度和Google的语义识别还有很大的差距。

  软件产品的价格

  工信部以每年4170万元的价格购买了“绿坝-花季护航”一年的使用许可,预计的安装量大概是一千万左右,在同类软件产品中,可谓“天价”。

  举个例子,在国家公布的中国软件行业百强之中第20位,开发企业管理软件的用友公司,一年的净利润也只有四亿多元,而且销售的大部分软件都是终身许可的。有使用期限的License通常价格极低甚至免费,做为软件行业的通用做法,一套商业软件通常会有三个月到半年左右的免费试用期,例如360安全卫士自带的NOD32杀毒软件就可以免费试用半年,在这个阶段,用户可以免费使用该软件的全部功能,超过期限后用户可自行决定是否购买该软件,这种方法可以有效避免用户退货的概率。对于装机量巨大的软件,例如腾讯QQ、迅雷等,全部都是免费使用的软件,开发商通过第三方增值服务(例如广告等)就可以获得巨大的收入。如果安装量在千万级别,相信有大量的软件厂商都会愿意免费提供政府使用。工信部在这个软件的招标过程的确令人感到疑惑。

  软件开发商的研发能力

  以中标的金惠和大正两家公司,其研发能力的确令人质疑,在国家公布的中国软件百强名单中根本找不到他们的名字,研发过程中也存在一些不规范的做法,例如未经授权使用国外开源技术等,在安全方面,很多安全公司(如奇虎江民)都发现“绿坝”存在高风险的安全漏洞,黑客可以利用这些漏洞传播病毒,中毒电脑存在严重泄密或被黑客远程控制的可能。

  我先前曾经提到过,这样一款小公司开发的软件很容易存在各种安全漏洞,在未经过广泛测试之前,冒然就安装到大量电脑客户端上,存在极大的安全隐患。一旦“绿坝-花季护航”的安全漏洞被黑客发现,那么所有安装这个软件的电脑都成为黑客的“肉鸡”(受别人远程控制的电脑),大量的“肉鸡”不但可能引发各种网络安全事故,还完全有可能重演先前“暴风影音断网”的灾难。没想到我的这些猜想这么快就被一一证实了。

  预装过滤软件的原因

  工信部原本是通过购买美国Cisco(思科公司)的入侵检测系统(IDS)和入侵防御系统(IPS)来监控和管理中国互联网,但这存在一些问题,Cisco的安全产品目前只能针对文字类型的数据包进行监控和分析,对于图像和视频显得无能为力,同时,Cisco做为一个美国公司,很难保证其产品中会不会留有后门,一旦出现战争等紧急情况,美国可以通过Cisco的产品完全控制中国的互联网通讯,这会使得中国在战争中处于极为不利的局面,而做为国产的华为中兴等公司,又不具备开发这种应对数亿网民的超大型产品的能力,因此,Cisco(思科公司)的产品不但不怕没有生意,还可以漫天要价。

  可能是出于这方面的考虑,工信部才决定通过在客户端电脑预装过滤软件的形式,来打破Cisco一统天下的局面,这种分布式技术,将大量的计算分配到了客户端的电脑上,实现了单个节点所无法实现的巨大计算能力,并在一定程度上解决了图像智能识别等问题。如果客户端的过滤软件运行良好的话,可以大为减轻电信部署的IDS和IPS的负荷,如果负荷降的足够低的话,就完全可以使用华为的同类产品进行替代,以防止未来战争期间可能出现的变数。

  可惜的是,中标的企业拿出来的软件产品实在不争气,产品质量不过关,存在着大量安全隐患,如果大规模安装的话,可能会带来更多的问题,我建议,如果政府真的要想购买软件的话,中国软件百强中任何一家民营软件企业的研发能力都比这两家强,从那些公司招标的话,不难获得真正物美价廉的软件。

2009年6月13日星期六

Facebook正式推出个性化网址

  今天中午十二点,全球最大社交网站Facebook正式推出个性化网址服务,所有六月十日之前注册的Facebook用户都可以在第一时间抢注属于自己的个性化网址。

  Facebook用户可以通过这项新服务为自己建立一个容易以及的个人网址,还可以象个人主页那样来使用他们的Facebook网页,而先前的Facebook用户网址是由一个数列构成的。Facebook的竞争对手MySpace早在2005年就推出了个性化网址服务。

  面对微博客Twitter的威胁,Facebook推出的个性化网址,不但可以提升Facebook的流量,还能帮助Facebook在与Twitter的竞争中再次获得优势。这也是Facebook针对搜索引擎进行优化的一个措施。

  在北京时间中午12:01分,Facebook的个性化网址功能准时开放,令人惊讶的是,短短三分钟Facebook就已经注册了200,000个用户名,15分钟内注册的用户高达500,000个。Facebook这么大型的社交网站,全球所有网民统计时刻登录抢注用户名,居然网页一点也不卡,速度还很快,Facebok的技术能力真的很强,Twitter要好好学学。

  我成功的注册了我自己的用户名: http://www.facebook.com/williamlong

Twitter和饭否的好友管理工具

  微博客做为社会化网络的重要组成部分,具有比传统即时通讯(IM)软件更多的优势,例如可以看到好友的好友,可以关注陌生人的信息,但这也带来另一个问题:信息过载。

  如果用户关注(Follow)的用户数非常多,那么将在短时间内接收到大量来自好友的“信息轰炸”,这显然会给降低未必可的可用性。微博客和IM不同的是,你Follow的很多人可能你并不认识,为了能更加有效的使用微博客,获得更多有用的信息,对自己的好友进行合理管理势在必然。

  我个人觉得,对于好友的管理可以遵循以下几点:

  1、关注自己认识的朋友或者同事、亲人等。

  2、关注一些知名用户,通常知名用户的关注者都非常多,名气越大,Followers越多。

  3、合理取舍,特别是那些更新频率非常高的“话痨”,如果其更新的内容没有太大价值,就删除掉。

  经过这样的好友管理,微博客的使用就会变得更为有效。

  然而可惜的是,目前流行的微博客,如Twitter和饭否等,都没有这样的好友管理工具,在好友界面中,只能看到好友的id和名称,无法看到其关注着数量和更新数量,因此,我通过研究Twitter和饭否的API,写了一个Twitter和饭否的好友管理工具,可以方便的实现上面的功能。

  此工具为开源工具,全部源代码只有20多行,对于Twitter用户来说,先输入用户名和页数,提交后即可看到显示的前100个好友,信息包含好友的id、姓名、关注者(Followers)数量、更新数量,如果要想删除一个好友,点后面的“del”按钮即可删除,点击后会转到Twitter的API服务器,需要输入用户的Twitter用户名和密码才能真正删除。

  由于Twitter对于API有每小时100次查询的限制,超过了这个次数就会封IP,因此这个工具我就不在线提供演示了,大家将下面的ASP代码复制到一个支持ASP的主机空间上运行即可。

Response.Write "<form action=" + Request.ServerVariables("URL") + " method='post'>Twitter Username:<input type='text' id='username' name='username' value='" + Request.Form("username") + "'>  Page:<input type='text' id='page' name='page' value='" + Request.Form("page") + "' size='2'> (Page>=1) <input type='submit'> </form>"
if Request.Form("username")<>"" Then
  Set xmlHttp = Server.CreateObject("MSXML2.ServerXMLHTTP")
  xmlHttp.open "GET", "http://twitter.com/statuses/friends.xml?page=" + Request.Form("page") + "&screen_name=" + Request.Form("username"), false
  xmlHttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"
  xmlHttp.send (null)
  If (xmlHttp.Status = 200) Then set root = xmlHttp.responseXML.documentElement Else Response.End
  for i=1 to root.childNodes.length
    set node = root.childNodes.item(i)
    if not node is Nothing then
      set node2 = node.childNodes.item(1)
      name = node2.nodeTypedValue
      set node2 = node.childNodes.item(2)
      id = node2.nodeTypedValue
      set node2 = node.childNodes.item(8)
      followers = node2.nodeTypedValue
      set node2 = node.childNodes.item(21)
      statuses = node2.nodeTypedValue
      Response.Write "<form action='http://twitter.com/friendships/destroy.xml?screen_name=" + id + "' method='post' target='_blank'>"
      Response.Write "id:" + id + " , name:" + name + " , followers:" + followers + " , updates:" + statuses
      Response.Write " - <input type='submit' value='del'></form> <br/>"
    end if
  next
  Set xmlHttp=Nothing
End if

  对于饭否来说,也是同样的道理,其代码和Twitter的非常类似,不过,由于饭否功能的限制,其API并不提供“更新数量”这个字段,因此列表中只显示用户的id、姓名和关注者数量,建议饭否能把“更新数量”这个字段加上去。饭否的好友管理代码如下所示,其安装和运行与Twitter的一样。

Response.Write "<form action=" + Request.ServerVariables("URL") + " method='post'>Fanfou Username:<input type='text' id='username' name='username' value='" + Request.Form("username") + "'>  Page:<input type='text' id='page' name='page' value='" + Request.Form("page") + "' size='2'> (Page>=1) <input type='submit'> </form>"
if Request.Form("username")<>"" Then
  Set xmlHttp = Server.CreateObject("MSXML2.ServerXMLHTTP")
  xmlHttp.open "GET", "http://api.fanfou.com/users/friends.xml?page=" + Request.Form("page") + "&id=" + Request.Form("username"), false
  xmlHttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"
  xmlHttp.send (null)
  If (xmlHttp.Status = 200) Then set root = xmlHttp.responseXML.documentElement Else Response.End
  for i=1 to root.childNodes.length
    set node = root.childNodes.item(i)
    if not node is Nothing then
      set node2= node.childNodes.item(0)
      id = node2.nodeTypedValue
      set node2= node.childNodes.item(1)
      name = node2.nodeTypedValue
      set node2= node.childNodes.item(9)
      followers = node2.nodeTypedValue
      Response.Write "<form action='http://api.fanfou.com/friendships/destroy/fanfou.xml?id=" + id + "' method='post' target='_blank'>"
      Response.Write "id:" + id + " , name:" + name + " , followers:" + followers
      Response.Write " - <input type='submit' value='del'></form> <br/>"
    end if
  next
  Set xmlHttp=Nothing
End if

  如果大家对这个工具还有什么意见和疑问,可以来咨询。

  更新:另外增加了一个嘀咕的好友管理,在线演示点这里,代码如下所示。

Response.Write "<form action=" + Request.ServerVariables("URL") + " method='post'>Digu Username:<input type='text' id='username' name='username' value='" + Request.Form("username") + "'>  Page:<input type='text' id='page' name='page' value='" + Request.Form("page") + "' size='2'> (Page>=1) <input type='submit'> </form>"
if Request.Form("username")<>"" Then
  Set xmlHttp = Server.CreateObject("MSXML2.ServerXMLHTTP")
  xmlHttp.open "GET", "http://api.digu.com/statuses/friends.xml?page=" + Request.Form("page") + "&friendUserId=" + Request.Form("username"), false
  xmlHttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"
  xmlHttp.send (null)
  If (xmlHttp.Status = 200) Then set root = xmlHttp.responseXML.documentElement Else Response.End
  for i=1 to root.childNodes.length
    set node = root.childNodes.item(i)
    if not node is Nothing then
      set node2 = node.childNodes.item(1)
      id = node2.nodeTypedValue
      set node2 = node.childNodes.item(2)
      name = node2.nodeTypedValue
      set node2 = node.childNodes.item(8)
      followers = node2.nodeTypedValue
      set node2 = node.childNodes.item(19)
      statuses = node2.nodeTypedValue
      Response.Write "id:" + id + " , name:" + name + " , followers:" + followers + " , updates:" + statuses
      Response.Write " - <a href='http://api.digu.com/friendships/destroy.xml?userIdOrName=" + id + "' target='_blank'>del</a> </form> <br/>"
    end if
  next
  Set xmlHttp=Nothing
End if

2009年6月12日星期五

基于JavaScript的REST客户端框架

  现在REST是一个比较热门的概念,REST已经成为一个在Web上越来越常用的应用,基于REST的Web服务越来越多,包括Twitter在内的微博客都是用REST做为对外的API,先前我曾经介绍过“基于REST架构的Web Service设计”,并给出了一些服务器端和客户端代码,随着JavaScript的广泛应用,我这里就给出一个轻量级的基于JavaScript的REST客户端框架。

  这个JavaScript客户端主要使用了XMLHttpRequest对象来实现通过HTTP对服务器操作GET、PUT、POST和DELETE以检索和修改资源。值得注意的是,由于安全方面的考虑,Javascript被限制了跨域访问的能力,因此在调用XMLHttpRequest的时候,应该注意跨域访问的问题,比如使用同一个域的动态文件做代理,或者其他方法避开跨域访问的问题。我这里给出的代码主要是根据我先前的那段代码修改过来的,其客户端JavaScript代码如下所示:

function httpGet(url, method, data) {
    var xmlhttp;
    xmlhttp = new XMLHttpRequest();
    xmlhttp.open (method, url + "?" + data, false);
    xmlhttp.setRequestHeader ("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
    xmlhttp.setRequestHeader ("Content-Length", data.length);
    xmlhttp.send (null);
    if (xmlhttp.Status = 200) return xmlhttp.responseText;
}

function httpPost(url, method, data) {
    var xmlhttp;
    xmlhttp = new XMLHttpRequest();
    xmlhttp.open (method, url, false);
    xmlhttp.setRequestHeader ("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
    xmlhttp.setRequestHeader ("Content-Length", data.length);
    xmlhttp.send (data);
    if (xmlhttp.Status = 200) return xmlhttp.responseText;
}

function httpPut(url, method, data) {
    var xmlhttp;
    xmlhttp = new XMLHttpRequest();
    xmlhttp.open (method, url, false);
    xmlhttp.setRequestHeader ("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
    xmlhttp.setRequestHeader ("Content-Length", data.length);
    xmlhttp.send (data);
    if (xmlhttp.Status = 200) return xmlhttp.responseText;
}

function httpDelete(url, method, data) {
    var xmlhttp;
    xmlhttp = new XMLHttpRequest();
    xmlhttp.open (method, url + "?" + data, false);
    xmlhttp.setRequestHeader ("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
    xmlhttp.setRequestHeader ("Content-Length", data.length);
    xmlhttp.send (null);
    if (xmlhttp.Status = 200) return xmlhttp.responseText;
}

function test() {
    document.write (httpGet("http://localhost/rest/service.asp", "GET", "do=GET"));
    document.write (httpGet("http://localhost/rest/service.asp", "POST", "do=POST"));
    document.write (httpGet("http://localhost/rest/service.asp", "PUT", "do=PUT"));
    document.write (httpGet("http://localhost/rest/service.asp", "DELETE", "do=DELETE"));
}

  我这里使用这个代码编写了一个简单的应用例子,就是管理Twitter好友的应用,大家点这里可以下载使用,因为跨域访问的问题,这段JavaScript只支持IE在本地使用。

2009年6月10日星期三

预装过滤软件的疑问

  据工信部的《关于计算机预装绿色上网过滤软件的通知》文件的通知,在2009年7月1日以后,中国境内生产销售的计算机出厂前将预装一款绿色上网过滤软件,而进口计算机在中国销售前也将预装该软件,这款软件具备拦截色情内容、过滤不良网站、控制上网时间、查看上网记录等功能。

  对于这样一款大规模预装的软件,我有一些非常疑惑的问题,从软件的功能介绍上来看,这是一款针对儿童的上网过滤软件,当浏览的含有不良信息的网站(例如色情网站)时,该软件可以自动关闭浏览器。但是,现在要求所有电脑都预装这个软件,如果用户家庭没有儿童呢?如果使用电脑的用户本身就是成年人呢?难道所有成人都要遵守儿童的标准,不能访问所谓的儿童不宜网站?

  我认为网上色情问题,对于未成年人和成年人,性质完全不一样。对于未成年人来说,保护青少年免受网络色情侵害是正确的;但是对于成年人来说,不应该和儿童采用同样的标准,必须在保护青少年身心健康与保护成年人言论自由之间找到平衡点,否则搞不好就变成限制成年人的言论和阅读自由的行为。

  对于成年人来说,在自己的电脑上看什么信息完全属于自己的私生活,只要不进行传播和复制,就属于个人的私事,有关部门不应该把管理之手伸到用户的私人空间,否则会引起大众的强烈不满,并且这本身也不符合法律规定。道德和法律本应该是严格区分的,道德是多元化的,在家浏览黄色网站,固然有悖很多人心中的道德规范,但这最多也属于个人道德的规范,并没有公共危害性,而如果某些国家部门通过这样的技术手段强行禁止成年人访问这些网站,并把这些当成自己所追求治理的理想社会秩序,这就让个人的合法权利受到这些公权力的损害,成为一种彻头彻尾的践踏私人生活空间的违法行为。

  同时,有关部门的审核标准也令人质疑,何为不良信息,审查这些不良信息的标准是什么,审查人是否有足够的知识来辨别何为不良信息,如果错误的将正常信息判断为不良信息,如何处理,如何保证合法网站的正当权益,这些都是很难控制和处理的事情。

  从另一方面将,这个软件本身的安全性就存在很大的疑问,这样一款小公司开发的软件很容易存在各种安全漏洞,在未经过广泛测试之前,贸然就安装到大量电脑客户端上,存在极大的安全隐患。一旦“绿坝-花季护航”的安全漏洞被黑客发现,那么所有安装这个软件的电脑都成为黑客的“肉鸡”(受别人远程控制的电脑),大量的“肉鸡”不但可能引发各种网络安全事故,还完全有可能重演先前“暴风影音断网”的灾难,其未来发展不得不令人感到担忧。

  后记:2010年7月13日,多家媒体报道,曾在中国内外引起强烈反对的“绿坝—花季护航”互联网内容过滤软件北京项目组因缺乏经费关闭。而位于郑州的另一项目组也在艰难维持,随时可能关张。

2009年6月9日星期二

Google发布翻译辅助系统

  据Google黑板报报道,今天,Google推出了一个新产品:Google翻译辅助系统

  该系统主要是供专业翻译人员手动翻译使用,翻译人员可以上传或指定一篇文章的地址,然后通过系统进行翻译,Google会预先使用自己的翻译系统进行翻译,然后翻译人员再进行人工校对和翻译,翻译界面上,左边为原始文章,右边为翻译后的文章,用户选中右边的文字,左边的原始文字会自动变色,除此之外,该系统还提供了翻译记忆库、术语和词汇表的上载复用机制。

  Google翻译辅助系统在机器翻译的同时,还提供了自动翻译搜索功能,使用户在编辑翻译的过程中,可以借鉴其他人翻译过的类似结果,并给予评定。最重要的是,Google翻译辅助系统在用户的编辑翻译中自动“学习”, 从而形成了一个良性循环,进而共同提高翻译的质量。

  对于中文博客来说,很多文章都是翻译国外博客的文章,那么不妨尝试一下这个系统,共同提高大家的翻译水平。

  点击访问:Google翻译辅助系统

 

电影《甜蜜蜜》观后感

  晚上看了部香港的老电影,陈可辛导演,黎明和张曼玉主演的《甜蜜蜜》,一部挺感人的爱情文艺片。

  这部电影的剧情引起了我很大的共鸣,黎小军从遥远的北方城市天津来到了南方的陌生城市“香港”,一个人漂泊在外,却认识了同样从大陆过来的李翘,同在异乡的孤独、迷茫和彷徨让他们的心离得更近。

  共同的奋斗和挫折让他们相爱了,那个磅礴大雨的夜晚,黎小军才发现,自己喜欢的可能并不是远方的爱人小婷,而是自己对面的李翘。但是他一直在逃避,逃避自己的感情。后来和李翘分手,接来了远方的爱人小婷并和她结婚,开始自己原先梦想中的新的生活。

  然而,当所有的梦想都实现的时候,黎小军却越发不安起来,这真的是他想要的爱情吗?为什么他心里牵挂的却是另外一个人。他的话越来越少,内心却在不断地挣扎,换来的是更多的痛苦和烦恼。所以,当黎小军搂着新婚妻子黯然地说,以前刚来香港的时候,要是当时你在我身边该多好啊,一句话说的多少无奈在其中。

  最终黎小军还是和小婷离婚了,独自跑到遥远的美国来逃避现实,这样的感情和背叛他承受不起,太深刻的感情,只能让人选择逃离,甚至没有勇气去面对。

  很多人说黎明在影片中的表演很木纳,我却觉得他演的很好,甚至让我产生了共鸣,因为我也有类似黎小军的一段经历,十一年前,我不也是独自一个人从遥远寒冷的北方城市来到了这个陌生的异乡深圳,同样是充满了新奇、迷茫和孤独,早先我也有着为了理想而打拼和奋斗的雄心壮志,后来才发现,原来一切都是命运,一切都是烟云。

  电影的结局,是个很童话的结局,导演可能为了迎合观众,让黎小军和李翘这一对苦命鸳鸯最终戏剧般地实现了重逢。而在现实生活中,这样的机缘巧合般的重逢真的很少,更多的却是擦肩而过的命运捉弄。

  因此,不要把你的爱人留在远方。爱她的话,就带她一起走吧。

电影《甜蜜蜜》