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

奋力向前123 2024-06-12 16:03:04 阅读 56

一、前言

     外部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<String> 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;

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

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

 



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。