我经历过的网络攻击

这几天GitHub遭受持续的网络攻击,在工程师们的积极响应下,目前所有系统稳定运行(“19:50 UTC All systems reporting at 100%. Attack traffic continues, so we remain on high alert.” Retrieved from https://status.github.com/messages/2015-03-30)。回想我自己这几年维护网络服务的经历,也在屡次被攻击中积累了一些经验教训,在此总结出来以供参考。

SSH暴力登陆

最早开设的网络服务是SSH,当年Linux系统图形界面不稳定,系统经常莫名其妙地就冻住了,键盘和鼠标有时也会失灵。一开始遇到这种情况我是用强行关机/重启来解决的。后来觉得这样可能会丢失系统文件,积累更多的不稳定因素,于是就想了个办法,在系统冻住的时候,通过其他计算机远程登录到这台电脑上,执行正常的关机程序。SSH就是那时开始使用的远程登录工具。不过后来实在是受不了图形界面崩溃造成的未保存用户数据丢失,就再也不在桌面系统上用Linux了。不过用SSH登陆的习惯却被保留了下来。

第一次发现被SSH暴力登陆攻击是在一台Windows台式机上,当时那台计算机有公网IP,可以从外网访问,于是我就在上面开设了SSH服务。当天晚上远程试用了一下没什么问题就放着没管了。第二天本地登录一看,发现一大堆登陆失败的日志。登录请求来自各个国家的IP,用户名也多种多样。那些尝试暴力登陆的,很多用root身份登陆,但是因为我是在Windows上开的SSH服务,所以有效的用户只设置了一个,就是MiffyLiye,root根本就不存在。虽然没有被攻下来,但我还是临时把SSH服务给关了,重新设置后才上线。

后来用运行Linux系统的虚拟个人主机(VPS)时,第一件事就是下载公钥(from https://special.miffyliye.org/keys/miffyliye.org.id_rsa.pub)并修改SSH的登陆设置(/etc/ssh/sshd_config):

  • 禁止密码登录(PasswordAuthentication);
  • 使用公钥验证(RSAAuthentication, PubkeyAuthentication);
  • 禁止root身份登陆(PermitRootLogin no)。

这个过程中,一开始生成密钥对可能有些麻烦,不过一旦完成密钥生成,后来的部署就非常容易了,使用起来也很方便。

DNS放大攻击

最早开设DNS服务是在架设OpenVPN的时候,那时在校园内一台有公网IP的Windows台式机上通过VirtualBox运行SUSE Linux,提供OpenVPN服务。当时DNS服务只监听通过OpenVPN接入的请求(listen on 10.8.0.1)。

后来在海外VPS上也开设了DNS服务,但是一开始没有限制请求的来源IP。没过两天我就发现服务器上一直有20-30 kbps的流量,而之前的数值应该是0。查看更细致的实时流量发现,DNS所使用的53端口一直在向乌克兰的总统府网站发送数据。当时正值俄罗斯和乌克兰发生军事冲突,可能我这儿的DNS服务被黑客利用了,于是就临时把DNS服务给关了。

DNS是域名解析服务的应用层协议,所依赖的传输层协议一般是UDP。最简单的情况下,源IP发送一个查询域名的数据包给DNS服务器,服务器返回一个查询结果给源IP,就算一次查询完成。问题在于如果源A伪造了自己的IP,在发送的数据包里写上B的IP,那么服务器就会将查询结果发送给B。通过精心设置,A可以发送一个很小的数据包,而服务器会查到很大的查询结果,服务器将包含查询结果的大数据包发给B,就占用了B的大量带宽。这样A就用很小的流量,利用DNS服务器,产生了对B的大流量数据。

后来我再开DNS服务的时候,就只监听通过VPN接入的用户,不提供公网访问了。有些ISP(网络服务提供者)会检查用户发出的UDP数据的源IP,如果发现是伪造的IP,就会拦截UDP数据,所以能否实施这种攻击还要看ISP有没有反制措施。

另一种广泛使用的传输层协议TCP需要先通过握手建立连接才能传输数据,看上去可以避免伪造IP的问题,但是在握手的过程中依然会被攻击。

SYN洪水攻击

这种攻击我没有亲身经历过,可能是因为目前还没有相关的仇家。不过我还是提前部署了防御措施,其实是系统默认设置下自带了。

正常的TCP握手过程中,首先A向B发送连接请求SYN=1,seq=x,接着B接收并反馈SYN=1,seq=y,ACK=x+1,最后A确认并完成双向连接SYN=0,seq=x+1,ACK=y+1。

如果A发出了连接请求之后就不管了,那么虽然双向连接尚未建立,但B发出反馈消息的时候就已经为此分配了内存等资源用于支持TCP的一些功能。如果A大量伪造IP发出SYN请求,那么B就会有大量资源被占用而无法提供正常的服务。

一种解决方案是使用SYN Cookies。服务端在收到连接请求后,并不立即分配服务器资源,而是综合请求来源和目标的IP和端口等信息,生成一个特殊的Sequence Number:cookie,然后发出回应SYN=1,seq=cookie,ACK=x+1。之后把一切都忘掉,不分配内存,不等待回应。等到客户端发回回应SYN=0,seq=x+1,ACK=z+1的时候,服务端计算一下对应的cookie,如果z=cookie,虽然服务端没有之前的记忆,但也可以通过z=cookie确认之前有进行了一半的握手,于是就在之前的基础上继续下去,建立起TCP连接。如果客户端不回应,那也没什么影响,服务器早就忘了这事儿了。可以通过cat /proc/sys/net/ipv4/tcp_syncookies查看此功能是否开启,我的服务器上默认是开启的。

此外,还可以通过防火墙限制TCP连接建立的频率。SUSE Linux默认的防火墙规则里就有很多预设的规则,虽然看不懂,但应该有防SYN Flood的规则。

如果A控制大量其他客户端发出真实的SYN请求并最终建立连接,这时候服务器就很难区分正常的SYN和攻击性的SYN了,不过这种手法成本较高,需要与相关人士结仇才有较大机会被攻击。

我在了解了一些信息安全的原理后,觉得其实并没有哪一种方法能够保证100%的安全。安全措施所能做的更多的是提高攻击的成本,使得攻击时的付出大于攻击成功后的收益,或者攻击所需要的技术超出时代发展的水平,这样来降低被攻下的概率。

上面这些都是防住了的网络攻击,但是现实中总是有些事防不胜防。

OpenSSL心脏滴血

DNS Amplification Attack可以说是协议本身的缺陷造成的问题,而现实生活中还有一些是软件实现出了问题。例如我还在用Linux当桌面系统的时候,曾经一年内遇到两个普通用户权限提升漏洞,其中一个(CVE-2009-1185)是udev的实现没有检查消息的来源,把本地用户构造出来的消息当成kernel消息,从而被骗走root权限。OpenSSL的Heartbleed(心脏滴血)漏洞与之类似,轻信了对方发来的心跳包的长度,造成返回的心跳包携带了部分服务器上的额外信息。在反复攻击之下总是能挖出一些有价值的东西,比如SSL证书的私钥。当时我的校园网里一台OpenVPN服务器受到了波及,但是因为启用了TLS-Auth Key,所以只有持有TLS-Auth Key的人才才能成功发动攻击(Heartbleed – OpenVPN Community Wiki)。我当时觉得这些同学们当中应该不会有人去实施攻击,所以只是更新了服务器证书,发邮件提醒大家更新客户端软件,觉得有必要可以找我换发证书,不过最后也没有人找我换证书。

Bash Shellshock

这个漏洞潜伏了二十多年,爆出来之后陆陆续续修了好几次才修好。造成的影响是服务器会被注入远程执行命令。我的VPS上发现了两条相关记录,一个是Errata Security通过注入ping命令调查漏洞的影响范围,另一条也是一个ping命令,不过没有留名。

服务器日志中还有很多访问不存在资源的记录,诸如*.php,*.py。估计是在扫描其他网络应用,寻找漏洞,伺机攻击。

对于这类攻击,我只能通过订阅系统安全更新的邮件列表,及时更新系统,和少用不安全的应用来减少影响。

劫持JavaScript脚本

这个我可能没有遇到过,不过这次对GitHub的攻击最开始是通过劫持百度的JS脚本来实现的。我的网站上虽然没有百度的JS,但是有其他的JS脚本(如放在自己服务器上的MathJax),同样存在被劫持的风险。解决方案之一就是启用SSL。

之前我是给自己的网站用了自签名的证书,然后在登陆页面强制跳转SSL加密,最近换成了权威机构的证书,全站强制跳转SSL加密。配置参考了Mozilla SSL Configuration Generator给的建议。为了兼容性向TLS 1.0妥协了,其他的都按照现代标准来。评分是SSL Labs A+Global Sign SSL Configuration Checker A+。目前发现了少量不兼容问题,WordPress和MediaWiki运行正常。

全站SSL配合HSTS也解决了我以前担忧过的另一个问题。当时我在局域网开设OpenVPN服务器,同时提供客户端下载,由于不好要求同学们将我的自签证书导入系统,所以下载页面一直没有启用SSL,对于OpenVPN客户端这类要求管理员权限的软件,一旦被人劫持替换,后果不堪设想。这次启用SSL和HSTS,就再也不用担心这些问题了。

Leave a Reply

Your email address will not be published. Required fields are marked *