五一劳动节放假三天,我也确实劳动了三天,主要的工作就是完成了对网站(http://www.step1.cn)的访问进行了控制,这个功能我觉得挺必要的,可是我在网上搜索了很久,也没有发现相关的东西,无奈只好自己写了一个,功能虽然不怎么样,不过目的达到就行了。
事情的起因是这样的:4月最后一天我下载了网站的服务器端日志(由于是虚拟主机,获取日志比较麻烦,因此这个事情不是很经常做),于是从各个方面仔细的分析了一下,其他方面问题不大,最关键的是我发现有几个IP对网站的访问特别频繁,分析一下之后,发现其中有几个是baidu的蜘蛛(说老实话,我也没有想到百度蜘蛛对网站的访问如此频繁),还有几个不是蜘蛛的就很值得怀疑了。
首先我到一个可以根据IP反查域名的网站查了一下,结果查出来一些很值得怀疑的网站,其中有一个极为典型,公布出来,大家帮我鄙视一下:(ditu.123175.com/place/cn),(我不想给这个地址加上连接,搞不好给这个垃圾站加上连接影响我的博客站的信誉度了),该网站多个栏目完全的照抄我的网站内容,并且服务器一直不停的在我的网站抓取内容,大哥,做点有技术含量的事情好不好?这样的行为真是……算了不说了,本文依然是技术主题,就不在这个问题上发挥了。
于是我就要采取措施了,我开始是写了一个简单的程序来直接屏蔽该IP,之后又在五一节的三天里对这个程序进行了完善,,目前该程序大致能满足我的要求了,因为程序还在线上调试之中,我暂时不会公布代码,仅仅说一下具体的实现过程和原理:
1.我的网站基本架构依然是来源于URL重写机制(很久以前上过我的网站的用户可能知道,我的网站原先其实就是一个博客,使用的是博客园的源码,后来因为我要发布一些地图相关的程序,渐渐的将博客迁移到博客园,可是我将其中的URL重写的代码拆出来保留了),这个机制是通过Web.Config之中的httpHandlers的设置来控制所有的ASP.NET的响应,所有的ASP.NET请求都会被截获处理。
2.我在原来的截获的类之调用一个静态方法,在这个方法之中,执行请求的统计和限制过程,一旦判断该请求不合法,就立即返回400(Bad Request)而不继续执行,因此,一旦请求被限制,就不会返回正常内容了。
3.由于我是在ASP.NET之中实现的截获,因此,不会影响静态内容如htm之类的内容,一来这些内容对服务器的影响很大,二来这些内容不包含数据,因此不需要加入限制。
4.我的基础实现逻辑是这样的:每个IP每分钟最多访问30个ASP.NET页面,每小时最多访问600个页面,每天最多访问1800个页面,这是我对网站的目前的访问情况进行统计之后做出的部署,我觉得这样是不会影响正常的使用的,当然这些数字都可以在web.config之中配置的。
5.每当有一个IP访问之时,我会将这个IP加入到分钟列表mList,这个列表记录了当前分钟范围内每个IP访问了多少次了,一旦这个分钟结束之后,我就将这个分钟列表按照访问次数排序,并将前十位的IP加入到小时列表hList(为什么只要前十位的呢,要避免这个IP列表太大,影响性能),同样,这个小时结束之后,将这个小时列表的前十位添加到日列表dList。
6.在添加到列表之后,再分别在3个列表之中检查该IP的访问次数是否超出限制,如果是,则返回400错误,也就是说,超出每分钟次数限制的IP在该分钟结束前禁止访问,超出每小时次数限制的IP在该小时内禁止访问。
7.每次禁止了某次访问,都要将该次访问的时间、IP、访问路径、UserAgent输出到日志,以便观察是否存在不合理的访问限制,每次日列表dList的更改(每天24次),都将其内容输出到日志文件,以便观察是否有不正常的现象。
8.除了以上访问次数的限制之外,我还顺便加入了IP黑名单的限制,一旦加入黑名单,所有的访问都会被限制,这种情况下,将只能访问本站的静态内容,当然这个黑名单也是在web.config之中可以配置的。
9.最大的问题在于记录的保持,要知道,我不想用数据库,因为我做访问限制的目的之一就是要减少数据库的压力,要是这个用数据库,估计数据库就要挂了,因此,我开始想的是使用ASP.NET之中的静态变量,毕竟也就是3个长度不大的list而已,结果,经过线上检测发现,该数据一定时间之后就会被清空,至今我也不知道问题出在哪儿,开始总是怀疑是自己的程序的问题,研究了好久,后来怀疑到是静态变量的生命周期的问题,在网上查了一下,好像说有一些大侠不建议使用静态变量,可是并没有明确的说会出现什么问题,网络上大家也差不多都认为Statici变量应该和网站整体生命周期是一样的,可是我的程序的3个list好像是每隔20分钟左右就会被清空一次,因此只有分钟的次数限制能起到作用。
后来我觉得有可能是虚拟主机的问题,我一生气,就决定每分钟将3个list的数据使用序列化的方式写入到文件之中,然后每次发生数据被清空的时候从文件里面去读,这样的话损失的记录肯定不会超过1分钟,而且正常的重启服务业不会影响到统计数据了,例如有时候我要更新东西,肯定会要重启Application的,按照目前的这个写法,性能虽然会差一点,不过实现的效果还是不错的。
以上就是我五一的劳动,就是那些不爱劳动,喜欢不劳而获的站长同仁们毁了我的3天的劳动节,我想:有盗取别人网站的技术和时间,为什么不自己写一些独特的东西出来呢?我承认我的网站也借鉴过别的网站的内容,可是我从来不愿意照抄,因为我要给我的网站一个存在的理由。
PS:因为别人评论我的网站广告太多,有点像垃圾站,我正在反省,准备对网站布局进行调整,调整之后,网站广告将会变少,不会还会存在,而且可能会更加显眼,以后可能将左侧栏扩大为350的宽度(现在是200),因此左侧就会存在更大的广告了,呵呵,不过左侧栏的变大主要是因为右侧栏被我取消了,而且有一些功能确实需要更大的左侧空间来展现。页面上可能就只存在左侧栏的广告了。