【转载】t-io im小站攻防实录

t-io im小站攻防实录
 
 
  •  

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. 言语攻击

    譬如在聊天中输入"fXXk, XV, 国家LING人名字"等,策略是敏感词过滤
    先找到词库,作者用的部分词库在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. 其它方面的攻击

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

 

posted @ 2022-09-01 11:32  陈鸿  阅读(59)  评论(0)    收藏  举报