DNSSEC迫在眉睫

DNS污染作为一个已知的安全问题已经存在了好长时间了。但是一直以来没有十分好的办法来解决这个问题。比较一劳永逸的解决方案是DNSSec,但应用它要求在所有DNS通讯上实现安全协议,实施难度相当于把整个DNS生态重新搭建一遍,因此一直以来没有什么厂商来推动。DNS的安全问题也就一直被睁一只眼闭一只眼地忽略了。

这两天翻文章的时候翻到了ICCAN网站上,发现他们公布的DNSSec实施Timeline已经快到期了:

Planned High Level Timeline

December 1, 2009: Root zone signed for internal use by VeriSign and ICANN.  ICANN and VeriSign exercise interaction protocols for signing the ZSK with the KSK.
January, 2010: The first root server begins serving the signed root in the form of the DURZ (deliberately unvalidatable root zone). The DURZ contains unusable keys [...]

有关DSR的网络拓扑结构和实现方法

前两天在delphij老大的blog中看到了一篇《使用DSR模式实现单IP服务冗余》,觉得很有意思,因为这个实现方式与我以往所见到的有些不同,通过关闭ARP响应来解决虚拟IP在负载均衡设备和服务器上可能冲突的问题。随即提问了一下我所熟悉方式的实现是否可行,勤恳的delphij竟然又写了一篇来解释这个问题。不过这篇的思路似乎与我原来的想法有点出入,所以仔细又思考了一下,最终决定还是要完整的阐述一下我的思路。

我虽然见过一些DSR的实现方式,然而只不过是阅读架构文档而已,想当然来的东西跟最后实际实施出来的东西肯定有差距,所以把自己认为的设计思路记录下来,看看最终是否可行。

首先是拓扑图:

介绍一下简单的信息:

Public VLAN直连Internet,LB和Router分别有一个网卡接口连在这里,用于承载Internet的虚拟IP自然也就是绑在LB连在Public VLAN的NIC上了,方便起见,随便起个IP: 202.96.100.100(202.96段是中国电信骨干IP段,很多坏事都是这里发生的:D)
Internal VLAN是放服务器集群的网段,当然就用私有地址,就用典型的192.168.1.0/24吧,这里的Server使用IP 192.168.1.101

首先从数据流角度来看(红色箭头上的标号):

客户发起到请求: 61.152.X.X:1025 –> 202.96.100.100:80
负载均衡设备通过匹配包,发现目的IP为虚拟IP,根据Load balance算法挑选一台Server,将数据报直接路由到这台Server,不做任何修改(减TTL不算)61.152.X.X:1025 –> 202.96.100.100:80
Server看到数据报的目的IP是虚拟IP,并发现虚拟IP绑定在自己的lo上,认为目的地是自己,OS派发到应用层Web Server处理Request并生成结果,结果数据包变为 202.96.100.100:80 –> 61.152.X.X:1025
数据报发往路由器,路由器看到目的地为客户IP,路由到Internet去。

这个过程与传统NAT方式的Load Balance的区别在于,LB不修改目的地址,直接将数据报通过路由的方式转发给服务器集群。然而这里的难点就在于:如果不修改目的IP,那必须让Server能够对发往虚拟IP的请求做出响应,那就必须要把虚拟IP绑定在Server端,因此虚拟IP就同时出现在了两个地方:LB和Server,解决这个冲突就是完成DSR的关键所在。对于此点引用delphij的原话:

实现DSR结构的关键是,通往Internet路由器的那个网络上,只有负载平衡设备在网络上宣示虚拟出来的那个IP的MAC地址,这样,当请求进来的时候,数据会发到负载平衡设备,而不是某一台服务器上。

Delphij采用的方法是,将服务器上网卡的ARP功能关闭,这样服务器虽然绑定了虚拟IP,但不会对外界对于虚拟IP的MAC地址解析请求做出响应,所以完美解决了IP重复的问题。缺点是ARP一关Server自己会找不到Router或者网络内的其他服务器,因此需要手工维护一个静态ARP表。

而我所采用的方式,是不将虚拟IP绑定在实际网卡上,只是绑定在Server的还回(lo)上,这样依旧可以起到缩减ARP响应域的作用。

Delphij认为这样会需要一个额外的Public IP,不过我认为如果Server放在私有地址VLAN的话,应该是不需要额外的IP,在如图的这种拓扑中应该可以完美的工作。只要LB和Server中作出如下配置(红色罗马数字):

I.  Load Balancer要特别设置的地方有:

需要有合适的负载均衡算法以便于把流量分发给不同的Server。
对于TCP这种有状态的服务,需要使用较为宽松的状态机制来维持会话。

这里引用delphij的pf命令为例,如下,round-robin是负载均衡算法,keep-state(slopppy)是宽松状态匹配,这一点对于DSR也是尤为重要,因为DSR的特点就是从Server发回的响应不经过LB,LB看不见回去的响应包,所以Session track必须能容忍这种半吊子连接。而且这里似乎也必须修改Session的timeout时间,否则会有问题,这里无关者略过:

FreeBSD pf规则举例:pass in on em0 route-to { em1 内网IP1, em1 内网IP2, em1 内网IP3 } round-robin proto tcp from any to 公网IP port http keep state (sloppy)

II.  Server端需要的设置:

在lo上绑定虚拟IP 202.96.100.100,这样Server才会认为目的地是自己。
Web Server本身要使用虚拟IP作为监听IP,比如Apache配置Virtualhost的话这样用:<VirtualHost 202.96.100.100:80> ,如此以来Web server会对到虚拟IP的请求做出响应,且响应的源地址也是虚拟IP而不是自己网卡上的私有IP。
Server将默认网关设置为Router的IP,这样对于请求的响应就会发往Router而不会返回LB了。

III. Router上应该不需要什么特殊设置,知道把发往Internet的包路由出去就行

这样整个DSR就应该能走通了,不过这个玩法我也只是想出来而已,还没有经过实践,当初看到过F5的nPath实现,应该就是这么种玩法,不过估计实际应用时应该会有我这里没有想到得地方,所以有时间的话,最好还是找几个设备搭一下看看吧,先把设想架构放这儿,改天回来验证。说实话,delphij指出这里必须要有一个额外的公网IP才能保证知道出去的包怎么走,我这点还是没有想通。不管怎样,写出来让大家指正吧,至少在写这篇的过程中,我已经将自己以前没考虑到得一些细节补充完整了,对于自己来说,也算是不小的收获。

TCP/IP协议栈DoS漏洞

在本月的周二补丁日,微软发布了一组补丁用于修复存在于TCP/IP协议栈上的漏洞。可以从http://www.microsoft.com/technet/security/bulletin/MS09-048.mspx看到微软的更新声明。

同时,Cisco也发布了用于解决存在于IOS同样漏洞的补丁,声明于此http://www.cisco.com/warp/public/707/cisco-sa-20090908-tcp24.shtml

发布补丁其实并没什么稀奇的,特地为这个漏洞/补丁写一篇Blog的原因是这个漏洞背后有点非常有意思的八卦:

这个漏洞能造成的影响其实相当巨大,当初问题被发现时,非常多的TCP/IP协议栈实现都被证明是存在问题的。而在接下来的一段时间内,发现这个问题的几个人开发了一个攻击工具,经证明可以对Windows/Linux/BSD等等的机器发起攻击,仅仅需要发起数kbps的流量,持续几分钟之后就会导致目标服务器完全停止响应。
可被攻击的目标非常广泛,任何有端口在监听的服务器、PC甚至路由器都会被攻击。
实际这个问题属于协议的设计缺陷,所以当发现者公布这个问题时,他们没有使用漏洞(Vulnerability)这个词,而是使用了瑕疵(Flaw)。
厂商们对此问题的反应是承认此瑕疵存在,但因为对其修补需要反复的研究论证后才可能实现,因此拖了相当久的时间。Linux似乎挺早就做了相应的修补措施,但MS和Cisco却花了一年多直到今天才真正去修复这个瑕疵。以至于发现者其一还没有熬到这个问题修复就已经驾鹤西去。

其实这个问题的原理并不是很复杂,它起源于针对SYN Flood的解决方案SYN Cookie,对于SYN Flood/SYN Cookie不了解的人可以先补补课,这里有篇不错的文章:http://www.ibm.com/developerworks/cn/linux/l-syncookie/index.html

简单说,SYN Flood是因为攻击者发送虚假的SYN包而本身不做其他任何多余的工作,而被攻击者在接收到SYN后需要进行一系列建立Session、分配内存等资源分配的操作,导致攻击者可以用极小的代价耗尽被攻击者的所有资源,从而达到DoS(Denial of Service)的效果。而SYN Cookie则使服务器在接到SYN后并不立即进行资源分配,而是将SourceIP:SourcePort – DestinationIP:DestinationPort的4元组通过某稍微复杂但又不怎么消耗资源的算法转换得到一个值放入SYN/ACK的ISN中发送出去(称作Cookie)。此时真正的客户会响应这个SYN/ACK并在发回的ACK再次包含这个Cookie,服务器通过验证Cookie和四元组是否对应来判断客户是否合法后,才进行资源的分配工作。伪造SYN的攻击者因为无法收到或者猜出Cookie,无法完成三次握手,也就达成不了DoS的效果了。

而这个TCP/IP协议栈的瑕疵的思路是将SYN Cookie的思路用于攻击,客户端本身不消耗资源,也不维护连接状态,通过在发送的包中加入Cookie来辨识服务器,通过构建特定包使服务器完成三次握手,完成后服务器必然开始分配连接所需要的资源,例如维持连接状态表,分配内存,定时器。在此之后攻击者发送0窗口的ACK通知服务器这一端没有足够的buffer来传输数据,这样服务器就会持续维持此连接,并分配定时器定时来探测攻击者的窗口是否打开。此时攻击者所要做的只是间隔一定时间内继续发送0窗口包告诉服务器继续维持连接,但攻击者本身仍机不需要消耗任何资源。反复此过程多次,服务器中将会有多个持续的连接,虽无数据传输,但服务器本身需要维持这些链接,并还需要不时触发定时器来探测窗口,导致服务器的协议栈资源被大大消耗,到达一定程度后,服务器会因为资源耗尽而停止响应。

问题的发现者撰写了很详细的资料用于描述这个问题,我将个人认为非常不错的一个PPT放到Google Docs上供大家研究,Sockstress是作者开发出来验证这个漏洞可以被利用造成DoS的工具:

作者的主页上还有更多的资料可供研究:http://sockstress.com/

目前这个漏洞在这一年内究竟有多少真正实现DoS的案例还没有统计资料,个人认为应该有不少实际被攻击成功的例子,但只是没有广泛引起关注而已。

对于此问题的修复,MS和Cisco都没有披露补丁的原理,个人猜测是加强对于恶意空置连接的检测,并强制对端如果持续0窗口一段时间后强行关闭连接并释放资源。因为协议RFC本身并未对此作出强制或建议规定,各厂商的协议栈实现可能会有所不同。就像SYN Cookie当初的情况一样,实现本身对RFC的要求有所相违背,但为了保护协议栈本身却不得不做出此类抉择,估计这也是厂商拖了这么久才真正放出补丁的原因之一吧。不知以后的RFC中是否对比会有所补充。

说了这么多东西,其实我个人并不是对这个漏洞的实现细节特别感兴趣,只是刚好最近这个事儿比较热门,而我工作上上维护的某个Service的程序设计行为与这个漏洞的原理有非常大的共通之处。程序本身的行为对协议栈造成了很大的压力,刚好最近流量突增,使得部分服务器过载而开始间歇性罢工,一帮兄弟们在焦头烂额的想办法修,所以实在是想对这个漏洞吐个槽。程序本身的行为设计时就没考虑周全,流量增加到Server撑不住才想办法修,对于运营人员来说,实在不是什么令人爽得起来的事,

最后附送一个SLashdot上对这个事儿讨论的链接:http://it.slashdot.org/story/09/09/08/1839258/Microsoft-Cisco-Finally-Patch-TCP-DoS-Flaw,其实这个站上的人们也挺有娱乐精神的,吵着吵着就跑题,甚至连Windows NT最早某些工具用了BSD协议代码的那些旧八卦也挖出来了。无聊时看看还真提神-_-

DNS漏洞

这个月出现的一个关于DNS的漏洞已经可以在很多新闻里看到了,然而如以前一样,国内对于类似事件的报道毫无深度,甚至在技术上还存在不少翻译带来的的误读,非常不靠谱。

首先必须要知道的一点是这是DNS解析机制本身的漏洞,并不是单纯某一个产品的问题,因此几乎所有的DNS Server都会受影响。

其次这个漏洞的攻击表现是未经授权地篡改某些DNS解析出来的地址结果,其最终目的是诱使客户在没有意识到的情况下访问到黑客精心布置的页面,从而达到其目的。也就是说此漏洞影响的不仅仅是DNS Server,域名或网站运营者,还有所有的访问互联网的人。

早些时候的讨论,仅仅认为这是个比较难以利用的潜在漏洞,但从这几个月的形式来看,漏洞被成功利用的几率在精心构建的攻击行为下大大增加,甚至就在昨天,被证明是有效的漏洞利用方式的细节已经在小范围内传播了。据发布者预测,应该就在今天,将会有确实的攻击行为出现。对细节感兴趣的可以看这里。

即将产生的破坏究竟有多大,是很难估量的,但至少可以确认,将会有很多客户的敏感资料遭受威胁。对于整个互联网DNS体系,从来没有像这样一次如此大规模的影响事件,同时考虑到互联网整体对于DNS安全的重视程度还远远未如Web安全那样高,接下来应该会有比较长时间的动荡期。国内在这方面尤为落后,恐怕会在接近半年的时间内,将会出现很多帐号盗窃,流量注入,甚至域名劫持之类的事件出现。

要将此漏洞完全解决,必须是互联网上所有解析服务器和缓存服务器都做好相应升级之后才可能,对于DNS Server管理员,要做的就是尽快将自己手头的Server补丁打好。而对于普通互联网使用者,在这段期间内所能做的,就是尽量选择可靠的DNS服务器。考虑到国内电信等ISP的技术能力和响应速度,恐怕比较靠谱的临时解决放案是使用本地架设的DNS缓存服务器或者使用已经证实不存在问题的服务器,例如OpenDNS。

这就像是一场瘟疫,光自己做好防护还不够,至少要你周围的人都可信才行。

但愿我过于悲观地预测了这次事故造成的影响。

弱智的上海移通

公司的网络一直是走得移动的企业宽带,貌似是光纤到楼的吧。3个月前去申请从2M扩容到10M。对方很早就说做好了,但是从我本地网关出口的流量监控来一直都没突破过2M。

昨天下午,网络突然不通了,于是报修。半小时后来了个扛着笔记本的技术员,把本子往出口网线处一接,ping了下对端,不通,然后就说了句去对端机房看看,就跑了。

然后就是持续到今天上午的网络瘫痪,移通的说法在换了n个版本后,网络还是依旧不通。

一上午没办法干活不行,于是再把出口接上自己看看能不能查到线索,于是发现了如下tcpdump结果:

09:55:00.006472 00:00:00:22:25:8c > ff:ff:ff:ff:ff:ff, ethertype ARP (0×0806), length 42: arp who-has 211.X.X.33 tell 211.X.X.34
09:55:01.003376 00:00:00:22:25:8c > ff:ff:ff:ff:ff:ff, ethertype ARP (0×0806), length 42: arp who-has 211.X.X.33 tell 211.X.X.34
09:55:01.763189 00:0b:be:51:b9:00 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0×8100), length 64: vlan 209, p 0, ethertype ARP, arp who-has 211.X.X.34 tell 211.X.X.33
09:55:01.791808 00:0b:46:2b:e2:82 > 01:00:0c:cc:cc:cd, ethertype 802.1Q (0×8100), length 68: vlan [...]

MySQL Proxy应用:读写分离

前一阵子看到了MySQL Proxy这个东西出世,就推断将会从这个玩艺发展出很多架构方面翻新的花样,还没来得及研究,这就有人有研究成果了。

如下图:

通过MySQL Proxy实现一个连接池,并在其中分辩客户端连接为读或写操作,将不同操作导向到不同的后端数据库服务器,来实现性能的提升。

具体实现方法和步骤参考原文:

http://jan.kneschke.de/2007/8/1/mysql-proxy-learns-r-w-splitting

中国联网20周年

突然想到我个人做网民满十周年了,然后就顺便查了一下中国互联网的历史,发现至上个月9月20日起,刚满20周年,并且找到了一个十分有趣的东西,如下图:

看不懂?没关系,其实我也看不懂,只有懂德文的才能看懂:D

只需要知道一件事:这是中国联入互联网发往国外的第一封信件,目的地是德国,此图片为这封信的打印件。

而这封信的内容只有一句话:

Across the Great Wall we can reach every coner in the world.

这对于中国互联网20周年来说,这可真是一个莫大的讽刺阿。

所以后面我再加一句:

Now we have the Great Fire Wall.

虚拟机格式有望统一?

今天看到这么一则新闻:DMTF Accepts New Format for Portable Virtual Machines from Virtualization Leaders

说是几个“Leader”厂商正拟定统一虚拟机的格式,以便于在各种产品中移植以及确立标准,这几个“Leader”来头不小,以下: Dell, HP, IBM, Microsoft, VMware, XenSource 。

有标准可依大家都高兴,不过估计又会出现虚拟机产品同质化的问题吧。不过对于Full Virtualization这种形式来说,解决方案比较重要,由固定几个大公司把持标准应该不是坏事。

个人更关心OS Level Virtualization。

比较少见的DNS问题

今天碰到了一个DNS解析记录总是不生效的troubleshooting案例,故障现象很诡异,有部分解析记录是完全没有问题的,而有部分则完全不生效。通过dig诊断来看就好像根本不存在这几条记录一样,而这几条记录又是确确实实地写在了zone file里。

正在莫名其妙的时候,发现log里在加载这个zone的时候有这样一条日志:loading master file /var/named/xxxxxx.zone: CNAME and other data。

还有一条标明了行号,于是检查,发现在此行配置了一条MX记录,同时下面还有一行是同一子域名配置了一条CNAME记录。于是怀疑对于同一子域名不能同时存在这两种记录,删除其MX,reload发现没有日志出现。再dig,发现先前解析不出来的记录都恢复正常。

然后回顾了一下,认为我这个推断是正确的。因为CNAME本身就是将子域名委派至其他DNS服务器解析管理,此时其自身配置的A与MX应当失效,所以不应该存在此类记录才对。BIND在此应该是拒绝zone file里同时写了同一子域名的CNAME与其他记录。

再想了一下,刚才故障中正常的解析都是位于此条之上的记录,失败的都是位于之下,说明BIND在加载zone的时候是按照配置文件逐条读入,碰到失败则放弃之下的所有内容,所以才有此奇特的故障现象。

后经测试,有CNAME存在时,确实A和MX都不能建立,否则报错,NS倒是可以,但是不起作用。

看来有空还是要好好研读RFC,一些细节方面的东西不能忽视。

实现Wordpress的URL静态化以及Dreamhost的Analog共存

Wordpress的URL静态化其实是通过Apache的URL Rewrite功能实现的伪静态话。在开启这个功能后,blog的根目录会生成一个.htaccess的文件,通过这个文件的一些配置项,来实现URL静态化功能。默认创建的.htaccess内容如下:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

简单来说,就是将访问到非实际存在的文件或者目录的URL全部转向至index.php。index.php接受到这个URL后可以根据这个URL的某些部分来确定要访问的具体页面。

然而启用这个静态化之后,会发现Dremhost后台通过 analog 6.0搭建的访问日志分析工具会访问不到了,会直接跳出Wordpress theme的404页面。原因大概是因为这套系统的入口是http://yourdomain/stats/这样的URL,实际/stats/是在Dreamhost的Apache配置中通过Alias指令添加的虚拟目录,并不存在于站点目录下。然而.htaccess中已经通过URL Rewrite将不存在实际文件或路径的URL直接定向到index.php中去了,因此/stats/这个虚拟目录就无法被访问了。       

解决办法自然是修改URL Rewrite的配置,让其额外对待/stats/这个URL。将.htaccess中的代码增加2行,变成如下即可:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^/(stats/|missing\.html|failed_auth\.html) [NC]
RewriteRule . – [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

这样修改后/stats还会按照原有Dreamhost的配置访问,同时又不影响Wordpress的静态化功能。

此技巧来自Dreamhost的Wiki,另外还有其他Blog或CMS程序的配置方法,具体可以访问这个页面了解:http://wiki.dreamhost.com/index.php/Mod_rewrite