基于网关的ip频繁访问web限制

基于网关的ip频繁访问web限制

码农世界 2024-06-05 前端 87 次浏览 0个评论

一、前言

     外部ip对某一个web进行频繁访问,有可能是对web进行攻击,现在提供一种基于网关的ip频繁访问web限制策略,犹如带刀侍卫,审查异常身份人员。如发现异常或者暴力闯关者,即可进行识别管制。

二、基于网关的ip频繁访问web限制策略

1、ServerHttpReques的方式t获取

获取访问端ip地址

/**
	 * 获取客户端IP地址
	 * 
	 * @param request
	 * @return
	 */
	public String getIpAddress(ServerHttpRequest request) {
		 
		String ip = getHeaderValue(request, "x-forwarded-for");
	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
	      ip = getHeaderValue(request, "Proxy-Client-IP");
	    }
	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
	      ip = getHeaderValue(request, "X-Forwarded-For");
	    }
	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
	      ip = getHeaderValue(request, "WL-Proxy-Client-IP");
	    }
	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
	      ip = getHeaderValue(request, "X-Real-IP");
	    }
	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
	      ip = request.getRemoteAddress().getAddress().getHostAddress();
	    }
	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
	      ip = request.getLocalAddress().getAddress().getHostAddress();
	    }
	    return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
 
	}
	
	 public static String getHeaderValue(ServerHttpRequest request, String name) {
		    List stringList = request.getHeaders().get(name);
		    if (!CollectionUtils.isEmpty(stringList)) {
		      return stringList.get(0);
		    }
		    return "";
		  }
/**
	 * 判断大规模异常请求是否受限(同一个IP)
	 * 
	 * @param count   1分钟内限制次数
	 * @param request
	 * @return
	 */
	public boolean isLimit(ServerHttpRequest request, int count) {
		String clientIp = getIpAddress(request);
		String noPermissIP = redisUtils.get(RedisKeys.getNoPermissClientIP(clientIp));
		if (!StringUtils.isEmpty(noPermissIP)) {
			String noPermissIPLog = redisUtils.get(RedisKeys.getNoPermissIPLog(clientIp));
			if (!StringUtils.isEmpty(noPermissIPLog)) {
				log.info("ip:" + clientIp + "访问系统接口频繁,被限制访问1天!");
				redisUtils.set(RedisKeys.getNoPermissIPLog(clientIp), "1", RedisUtils.DEFAULT_A_DAY);
			}
			return false;
		}
		String stratTime = redisUtils.get(RedisKeys.getRequestIPStartTime(clientIp));
		if (StringUtils.isEmpty(stratTime)) {
			stratTime = String.valueOf(System.currentTimeMillis());
			redisUtils.set(RedisKeys.getRequestIPPermiss(clientIp), "1", RedisUtils.DEFAULT_A_DAY);
			redisUtils.set(RedisKeys.getRequestIPStartTime(clientIp), stratTime, RedisUtils.DEFAULT_A_MIN);
		}
		Long interval = System.currentTimeMillis() - Long.parseLong(stratTime);
		String reqCount = redisUtils.get(RedisKeys.getRequestIPPermiss(clientIp));
		if (StringUtils.isEmpty(reqCount)) {
			redisUtils.set(RedisKeys.getRequestIPPermiss(clientIp), "1", RedisUtils.DEFAULT_A_DAY);
		} else {
			redisUtils.set(RedisKeys.getRequestIPPermiss(clientIp), (Integer.parseInt(reqCount) + 1) + "",
					RedisUtils.DEFAULT_A_DAY);
		}
		if (interval < 60000) { // 一分钟
			if (!StringUtils.isEmpty(reqCount)) {
				if (Integer.parseInt(reqCount) > count) {
					redisUtils.set(RedisKeys.getNoPermissIP(clientIp), clientIp, RedisUtils.DEFAULT_A_DAY);
					log.info(clientIp + "在最近" + (double) (Math.round(interval / 1000) / 100.0) + "秒内访问系统接口累计" + reqCount
							+ "次");
					log.info("ip:" + clientIp + "访问系统接口频繁,被限制访问1天!");
					return false;
				}
			}
		}
		return true;
	}

2、HttpServletReques的方式

	/**
	 * 获取客户端IP地址
	 * 
	 * @param request
	 * @return
	 */
	public String getIpAddress(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		 
		String [] ipArr = ip.split(",");
		
		ip = ipArr[0];
		
		ip.replaceAll("0:0:0:0:0:0:0:1", "127.0.0.1");
	 
		return  ip;
	}

ip频繁访问限制

这里需要借助redis缓存

	/**
	 * 判断大规模异常请求是否受限(同一个IP)
	 * 
	 * @param request
	 * @return
	 */
	public boolean isLimit(HttpServletRequest request) {
		String clientIp = getIpAddress(request);
		String noPermissIP = redisUtils.get(RedisKeys.getNoPermissIP(clientIp));
		if (!StringUtils.isEmpty(noPermissIP)) {
			String noPermissIPLog = redisUtils.get(RedisKeys.getNoPermissIPLog(clientIp));
			if (!StringUtils.isEmpty(noPermissIPLog)) {
				log.info("ip:" + clientIp + "访问系统接口频繁,被限制访问1天!");
				redisUtils.set(RedisKeys.getNoPermissIPLog(clientIp), "1", RedisUtils.DEFAULT_A_DAY);
			}
			return false;
		}
		String stratTime = redisUtils.get(RedisKeys.getRequestIPStartTime(clientIp));
		if (StringUtils.isEmpty(stratTime)) {
			stratTime = String.valueOf(System.currentTimeMillis());
			redisUtils.set(RedisKeys.getRequestIPPermiss(clientIp), "1", RedisUtils.DEFAULT_A_DAY);
			redisUtils.set(RedisKeys.getRequestIPStartTime(clientIp), stratTime, RedisUtils.DEFAULT_A_MIN);
		}
		Long interval = System.currentTimeMillis() - Long.parseLong(stratTime);
		String reqCount = redisUtils.get(RedisKeys.getRequestIPPermiss(clientIp));
		if (StringUtils.isEmpty(reqCount)) {
			redisUtils.set(RedisKeys.getRequestIPPermiss(clientIp), "1", RedisUtils.DEFAULT_A_DAY);
		} else {
			redisUtils.set(RedisKeys.getRequestIPPermiss(clientIp), (Integer.parseInt(reqCount) + 1) + "",
					RedisUtils.DEFAULT_A_DAY);
		}
		if (interval < 60000) { // 一分钟
			if (!StringUtils.isEmpty(reqCount)) {
				if (Integer.parseInt(reqCount) > 2000) {
					redisUtils.set(RedisKeys.getNoPermissIP(clientIp), clientIp, RedisUtils.DEFAULT_A_DAY);
					log.info(clientIp + "在最近" + (double) (Math.round(interval / 1000) / 100.0) + "秒内访问系统接口累计" + reqCount
							+ "次");
					log.info("ip:" + clientIp + "访问系统接口频繁,被限制访问1天!");
					return false;
				}
			}
		}
		return true;
	}

三、制作开关

对策略应该增加开关,作为启用策略和关闭策略使用

    /**

     * 1为开启,其他都是关闭

     */

    @Value("${interceptor.isAccLimit:-1}")

    private String isAccLimit;

四、对敏感性信息进行识(扩展)

  1. 定义敏感信息:
    • 首先,明确哪些信息被认为是敏感的。这通常包括但不限于:密码、信用卡信息、社会保险号、个人身份信息(如全名、地址、电话号码、电子邮件地址)、医疗记录等。
  2. 输入验证:
    • 使用输入验证来确保用户输入的数据符合预期的格式和类型。这可以防止恶意用户输入可能导致安全漏洞的数据。
    • 对于密码,确保它们足够复杂,并符合安全标准(如长度、特殊字符、大小写等)。
  3. 加密存储:
    • 不要以明文形式存储敏感信息。使用加密算法(如AES、RSA等)对敏感信息进行加密,并确保密钥得到妥善保管。
    • 对于密码,使用哈希算法(如SHA-256、bcrypt等)进行存储,并加入“盐”(salt)来增加哈希的复杂性。
  4. 传输安全:
    • 使用HTTPS来加密用户与Web服务器之间的通信,确保敏感信息在传输过程中不被窃取或篡改。
    • 避免在URL或GET请求中传递敏感信息,因为它们可能会被记录在浏览器历史、服务器日志或代理缓存中。
  5. 访问控制:
    • 实现严格的访问控制策略,确保只有授权的用户和应用程序可以访问敏感信息。
    • 使用身份验证和授权机制(如OAuth、JWT等)来验证用户身份并授予相应的权限。
  6. 日志和监控:
    • 记录与敏感信息相关的所有活动,包括访问、修改和删除等。这有助于在发生安全事件时进行调查和追溯。
    • 使用日志分析工具来监控潜在的安全威胁,并设置警报以在发现异常活动时进行通知。
  7. 定期审查:
    • 定期对代码和配置进行安全审查,以确保没有意外的敏感信息泄露或安全漏洞。
    • 遵循最新的安全标准和最佳实践来更新和加固应用程序。
  8. 使用安全框架和库:
    • 利用现有的安全框架和库(如Spring Security、OWASP等)来简化安全性的实现和维护。
    • 这些框架和库通常提供了许多内置的安全功能和防护措施,可以大大降低安全风险。
  9. 培训和教育:
    • 对开发人员和管理员进行安全培训和教育,使他们了解如何识别和处理敏感信息以及如何遵循最佳的安全实践。
  10. 备份和恢复:
    • 定期备份敏感信息,并确保备份数据的安全性。
    • 制定灾难恢复计划,以便在发生安全事件或数据丢失时能够迅速恢复敏感信息。

 

转载请注明来自码农世界,本文标题:《基于网关的ip频繁访问web限制》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,87人围观)参与讨论

还没有评论,来说两句吧...

Top