文档章节

t-io im小站攻防实录

talent-tan
 talent-tan
发布于 2017/06/01 10:37
字数 1166
阅读 3531
收藏 31

http://t-io.org:9292/newim/index.html是作者用tio写的一个web im小站,目前代码还在开发阶段,问题也比较多,暂未开源(t-io刚开源时的时候问题也不少,尤其是一些调试代码,眼尖的网友很容易看出来),废话少说,说一下本小站的一些攻防故事吧。

  1. 跨站脚本攻击

    这个比较简单,直接用对html进行转义就好,譬如:
    org.apache.commons.lang3.StringEscapeUtils.escapeHtml4("<script>alert(1)</script>")
  2. 言语攻击

    譬如在聊天中输入"fuck, av, 国家领导人名字"等,策略是敏感词过滤
    先找到词库,作者用的部分词库在https://git.oschina.net/tywo45/t-io/tree/master/docs/dict,然后用https://www.oschina.net/p/hutool的com.xiaoleilu.hutool.dfa.WordTree来处理就好,具体用法请去hutool的官网。
  3. DDos攻击

    这个是作者没想到的,其实DDos攻击的性质还可以分成几个情况:
    • 单纯的技术玩耍(就是好玩,也不怀恶意,在快要攻击死对方后马上休手)
    • 单纯的技术破坏(攻击死对方后,自己在家偷着乐)
    • 恶意的技术破坏(譬如攻击后向受害者索要财物、或是攻击后散布谣言说随便刷新一下就把小站给弄死了)
    tio这个演示小站被攻击后,其实受损失的是为tio提供服务器的公司,他们为此额外买了一台新服务器,牢骚少发,否则红薯又要来教训我了,tio做了以下防范措施,可供大家参考
    • 记录所有访问交互动作,这个是相对容易做到的,也没什么技术含量,就不细说了,这一步主要是为了留下证据,万一构成刑事纠分,可能会有用。
    • 利用RateLimiter实现访问频率控制,不过作者在此基础上作了改造,下面可能会花点篇幅来介绍这个
      1. 对RateLimiter进一步封装,也没什么好说的,直接看代码吧,最核心的代码是Guava提供的RateLimiter
        package org.tio.monitor;
        
        import java.util.concurrent.atomic.AtomicInteger;
        
        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;
        import org.tio.core.utils.SystemTimer;
        
        import com.google.common.util.concurrent.RateLimiter;
        
        /**
         * @author tanyaowu 
         * 2017年5月23日 下午1:09:55
         */
        public class RateLimiterWrap {
        	private static Logger log = LoggerFactory.getLogger(RateLimiterWrap.class);
        
        	/**
        	 * 频率控制
        	 */
        	private RateLimiter rateLimiter = null;//RateLimiter.create(3);
        
        	/**
        	 * 本阶段已经收到多少次警告
        	 */
        	private AtomicInteger warnCount = new AtomicInteger();
        	
        	/**
        	 * 总共已经收到多少次警告
        	 */
        	private AtomicInteger allWarnCount = new AtomicInteger();
        
        	/**
        	 * 本阶段最多警告多次数
        	 */
        	private int maxWarnCount = 20;
        	
        	/**
        	 * 一共最多警告多次数
        	 */
        	private int maxAllWarnCount = maxWarnCount * 10;
        
        	/**
        	 * 上一次警告时间
        	 */
        	private long lastWarnTime = SystemTimer.currentTimeMillis();
        
        	/**
        	 * 警告清零时间间隔,即如果有这么长时间没有收到警告,则把前面的警告次数清零
        	 */
        	private int warnClearInterval = 1000 * 60 * 60 * 2;
        
        	/**
        	 * 
        	 * @param permitsPerSecond QPS
        	 * @param warnClearInterval 清理本阶段警告的时间间隔,参考值1000 * 60 * 60 * 2,单位为ms
        	 * @param maxWarnCount 本阶段最多警告多次数,参考值10
        	 * @param maxAllWarnCount 一共最多警告多次数
        	 * @author: tanyaowu
        	 */
        	public RateLimiterWrap(int permitsPerSecond, int warnClearInterval, int maxWarnCount, int maxAllWarnCount) {
        		this.rateLimiter = RateLimiter.create(permitsPerSecond);
        		this.warnClearInterval = warnClearInterval;
        		this.maxWarnCount = maxWarnCount;
        		this.maxAllWarnCount = maxAllWarnCount;
        	}
        
        	/**
        	 * 
        	 * @return 
        	 * 0位置:根据QPS获取执行锁, false: 没拿到锁<br>
        	 * 1位置:根据警告次数获取执行锁, false: 没拿到锁<br>
        	 * @author: tanyaowu
        	 */
        	public boolean[] tryAcquire() {
        		boolean ret = rateLimiter.tryAcquire();
        		if (!ret) {
        			synchronized (this) {
        				long nowTime = SystemTimer.currentTimeMillis();
        				if ((nowTime - lastWarnTime) > warnClearInterval) {
        					warnCount.set(0);
        				}
        				lastWarnTime = SystemTimer.currentTimeMillis();
        				int wc = warnCount.incrementAndGet();
        				int awc = allWarnCount.incrementAndGet();
        
        				if (wc > maxWarnCount || awc > maxAllWarnCount) {
        					return new boolean[]{false, false};
        				}
        				return new boolean[]{false, true};
        			}
        		} else {
        			return new boolean[]{true, true};
        		}
        
        	}
        ///其它非核心代码
        }

         

      2. 在消息处理入口处,用上前面这个东西即可
        ImSessionContext imSessionContext = channelContext.getSessionContext();
        RateLimiterWrap rateLimiterWrap = imSessionContext.getRequestRateLimiter();
        boolean[] ss = rateLimiterWrap.tryAcquire();
        String group = "g";
        if (ss[0] == false && ss[1] == false) {
        
        	log.error("{} 访问过频繁,本次命令:{}, 将拉黑其IP", channelContext.toString(), command);
        	//			String imgsrc = UserService.nextImg();
        	String text = "<span style='font-size:16px;'>对不起大家,由于我发消息太频繁,已经被服务器拉黑了,大家珍重</span>";
        	ChatRespBody.Builder builder = ChatRespBody.newBuilder();
        	builder.setType(ChatType.CHAT_TYPE_PUBLIC);
        	builder.setText(text);
        	builder.setFromClient(org.tio.examples.im.service.UserService.sysClient);
        
        	builder.setGroup(group);
        	builder.setTime(SystemTimer.currentTimeMillis());
        	ChatRespBody chatRespBody = builder.build();
        	ImPacket respPacket1 = new ImPacket(Command.COMMAND_CHAT_RESP, chatRespBody.toByteArray());
        	Aio.sendToGroup(groupContext, group, respPacket1);
        
        	Aio.IpBlacklist.add(groupContext, channelContext.getClientNode().getIp());
        	return null;
        } else if (ss[0] == false && ss[1] == true) {
        	log.error("{} 访问过频繁,本次命令:{},将警告一次", channelContext.toString(), command);
        
        	Client client = imSessionContext.getClient();
        	String nick = client.getUser().getNick();
        	String region = client.getRegion();
        	String ip = client.getIp();
        
        	int warnCount = rateLimiterWrap.getWarnCount().get();
        	int maxWarnCount = rateLimiterWrap.getMaxWarnCount();
        	int xx = maxWarnCount - warnCount;
        
        	String formatedUserAgent = ImUtils.formatUserAgent(channelContext);
        
        	String text = "<div class='tio-danger'>第" + warnCount + "次警告【" + nick + "】【" + region + "】【" + ip + "】【" + formatedUserAgent + "】,还剩" + xx + "次警告机会"
        			+ "</div>";
        	//				text += "<div style='font-size:14px;color:#ff0033'><a href='http://t-io.org:9292/ecosphere.html?v=4514545454' target='_blank'>如果被拉黑请联系作者, 欢迎对t-io生态圈进行投资建设,谢谢!</a></div>";
        	ChatRespBody.Builder builder = ChatRespBody.newBuilder();
        	builder.setType(ChatType.CHAT_TYPE_PUBLIC);
        	builder.setText(text);
        	builder.setFromClient(org.tio.examples.im.service.UserService.sysClient);
        
        	builder.setGroup(group);
        	builder.setTime(SystemTimer.currentTimeMillis());
        	ChatRespBody chatRespBody = builder.build();
        	ImPacket respPacket1 = new ImPacket(Command.COMMAND_CHAT_RESP, chatRespBody.toByteArray());
        	Aio.sendToGroup(groupContext, group, respPacket1);
        	return null;
        }
        }

         

  4. 其它方面的攻击

    作者也在慢慢积累各种经验,也希望大家是友好的攻防演练,而不要变成恶意攻击。

 

© 著作权归作者所有

共有 人打赏支持
talent-tan

talent-tan

粉丝 826
博文 30
码字总数 15014
作品 3
杭州
程序员
加载中

评论(14)

狮子追求真理
@talent-tan 看到您这个站点的配置是1g内存和1m带宽的,不知道有没有统计过可以同时在线多少人,最近也想在构建类似的个人站点,不知道该选用什么样的服务器合适
狮子追求真理
开源点赞
狮子追求真理
不知是否有什么交流群可供交流的
l
lblin

引用来自“花米”的评论

10秒,20秒,30秒内只能发言一次。这个限制应该比这个规则效率更高.

引用来自“talent-tan”的评论

一个是产品层面,一个是技术层面,我这个主要是技术玩耍和积累
请教下,您的tio到底是支持100W没有动作的连接还是支持100W同时聊天的连接+业务逻辑(发文字+同步文字到客户端)?
l
lblin

引用来自“花米”的评论

10秒,20秒,30秒内只能发言一次。这个限制应该比这个规则效率更高.
体验差
talent-tan
talent-tan

引用来自“花米”的评论

10秒,20秒,30秒内只能发言一次。这个限制应该比这个规则效率更高.
一个是产品层面,一个是技术层面,我这个主要是技术玩耍和积累
花米
花米
10秒,20秒,30秒内只能发言一次。这个限制应该比这个规则效率更高.
路小磊
路小磊

引用来自“talent-tan”的评论

引用来自“路小磊”的评论

RateLimiter看起来好棒,我要学习下:grin:
RateLimiter还不是太灵活,你要不要按照文中的套路加强一把?

先吃透原理再说,嘿嘿
talent-tan
talent-tan

引用来自“路小磊”的评论

RateLimiter看起来好棒,我要学习下:grin:
RateLimiter还不是太灵活,你要不要按照文中的套路加强一把?
路小磊
路小磊
RateLimiter看起来好棒,我要学习下:grin:
t-io 1.7.1 发布:不仅仅是百万级 TCP 长连接框架

t-io 目标提升 不仅仅是百万级TCP长连接框架,这是t-io的第三个目标了,前两个都已实现。 目标先定下来,逐步实现,当年吹过的牛,大都含着泪完成了 要往短连接方面扩展 支持更多的传输层协议...

talent-tan
2017/07/03
6.1K
67
、轨迹/tio-im

tio-im简介 tio-im是基于t-io写的IM,主要目标降低即时通讯门槛,通过极简洁的消息格式就可以实现多端不同协议间的消息发送如(http、websocket、tcp自定义im协议)等,并可以通过http协议的a...

、轨迹
2017/08/31
0
0
t-io 3.2.0 发布:王谢堂前燕,飞入寻常百姓家

t-io简介 t-io 是基于aio(nio2)的网络编程框架,和netty属于同类,但t-io更注重开发一线工程师的感受,提供了大量和业务相关的API。基于t-io来开发IM、TCP私有协议、RPC、游戏服务器端、推送...

talent-tan
09/14
0
0
t-io 3.1.9 发布,王谢堂前燕,飞入寻常码农家

t-io简介 t-io 是基于aio(nio2)的网络编程框架,和netty属于同类,但t-io更注重开发一线工程师的感受,提供了大量和业务相关的API。基于t-io来开发IM、TCP私有协议、RPC、游戏服务器端、推送...

talent-tan
08/30
0
0
支持百万在线用户IM - J-IM

J-IM简介 J-IM(原名tio-im)是基于t-io写的轻量、高性能、(可能)支持百万在线用户IM,主要目标降低即时通讯门槛,快速打造低成本接入在线IM系统,通过极简洁的消息格式就可以实现多端不同协议...

轨迹_
05/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

IE浏览器http请求,中文传参报400错误-解决方法

做项目的时候,遇到一个小的问题.一个get请求列表数据的接口,在其它浏览器上是可以正常请求的.但是在ie浏览器上确出现奇怪的http请求400错误,其含义是你访问的页面域名不存在或者请求错误,自...

青衫旧巷
34分钟前
1
0
Spring中@RequestParam与@PathVariable的区别

@RequestParam与@PathVariable为spring的注解,都可以用于在Controller层接收前端传递的数据,不过两者的应用场景不同。 @PathVariable主要用于接收http://host:port/path/{参数值}数据。@Re...

王子城
37分钟前
0
0
数据运营者的福音:海量数据处理利器Greenplum

作者:李树桓 个推数据研发工程师 前言:近年来,互联网的快速发展积累了海量大数据,而在这些大数据的处理上,不同技术栈所具备的性能也有所不同,如何快速有效地处理这些庞大的数据仓,成为...

个推
37分钟前
1
0
进程和线程的区别介绍

1、首先是定义 进程:是执行中一段程序,即一旦程序被载入到内存中并准备执行,它就是一个进程。进程是表示资源分配的的基本概念,又是调度运行的基本单位,是系统中的并发执行的单位。 线程...

linuxprobe16
39分钟前
1
0
IntelliJ IDEA 工具的学习与使用

当前标签: IntelliJ IDEA IntelliJ IDEA(十一) :Debug的使用 JaJian 2018-08-04 02:32 阅读:402 评论:0 IntelliJ IDEA(十) :常用操作 JaJian 2018-05-22 18:43 阅读:1272 评论:0 Inte......

glen_xu
47分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部