【拦截工具】Java将判断properties中是否含有某一字段,提取properties文件中一个key对应多个value内容

目录

1、背景

2、解决问题的思路

3、解决问题方法:

1、采用AOP对请求进行拦截。

2、在请求方法上加入该注解

3、将拦截作为一个单独的模块封装成类

4、使用SpringAOP做拦截器拦截非法请求


1、背景

原来做的项目上线了,但是将地址作为参数传递到后台请求的时候被我们公司安全部门拦截了,问题是可能将本服务器作为跳板,获取公司内部的数据,可能会出现以下问题:

1.攻击者操控服务器发出自定义http(或其他支持的协议)请求,探测生产网中的服务。
2.将攻击者直接代理进内网中,绕过网络访问控制,直接访问内网进行漫游、甚至获取服务器敏感信息和凭证。为攻击者进一步渗透测试打开了大门。

2、解决问题的思路

1、首先验证请求的路径是否为http或https这种形式,如果是file:///, dict://, ftp://, gopher:// 等请求禁止。

2、满足条件1后,采用黑白名单的方式进行判断,将需要的IP地址放到数据库中或者配置文件中作为白名单,每次请求访问方法前都拦截,判断请求参数IP是否属于白名单,如果不属于白名单,判断是否为公司的内网或是黑名单若是则终止本次请求,否则认为是普通网站请求

3、解决问题方法:

1、采用AOP对请求进行拦截。

首先创建注解类,代码如下所示:

import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Diffintercept {

}

2、在请求方法上加入该注解

3、将拦截作为一个单独的模块封装成类

       这里涉及了想表达的地方:首先本次采用的是将白名单作为配置文件进行管理的(也可以采用数据库),白名单应该是一个list列表而不是key-value,我在ResourceBundle类中找到了getStringArray()方法,以为能够将下图1中存储方式转为String[] 数组或者List集合,在下面代码注释掉的那一句,但是抛出了转型失败错误(String不能转为String数组)我以为不支持“,”做识别符,又换成“;”、“-”但是不行,真正的解释如下:

PropertyResourceBundle在读文件时使用Properties.load(stream),它存储的是String。所以它永远返回的都是String而不是String数组。简言之,PropertyResourceBundle不支持getStringArray这个方法。

        遇到上述错误我就使用了ResourceBundlecontainsKey(ip)方法,这招有效果,配置文件需要改成图二的形式,但是有一点,实在是太别扭了,所以我还是想变成比较友好的形式,这时候我想到了--虽然获取不了字符串,但是我可以获取value后自己利用split函数解析啊,这个我熟啊哈哈,于是最后的代码就是下面这一段,同时最终的配置文件也就是图一。

import java.net.InetAddress;
import java.util.ArrayList;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.ResourceBundle;
public class SSRFChecker {
    ResourceBundle resourceBundle = ResourceBundle.getBundle("diff");
    public boolean checkURL(String urlString) {
        try {
            //String[] whiteLists = resourceBundle.getStringArray("whiteList");
            String whiteList = resourceBundle.getString("whiteList");
            String[] whiteLists = whiteList.split(",");
            URL url = new URL(urlString);
            String protocol = url.getProtocol();
            if (!whitelistProtocolArray.contains(protocol)) {
                System.out.println("Unsupported protocol~ Error:" + url);
                return false;
            }
            String host = url.getHost();
            InetAddress address = InetAddress.getByName(host);
            String ip = address.getHostAddress();
            boolean contains = Arrays.asList(whiteLists).contains(ip);
            //resourceBundle.containsKey(ip)
            if(contains) {
                System.out.println("Good Ip~ Success:" + ip + ", " + host + "," + url);
                return true;
            }
            for (String blacklistIp : blacklistIpArray) {
                if (equalIpSubnet(ip, blacklistIp)) {
                    System.out.println("Bad IP~ Error:" + ip + ", " + host + "," + url);
                    return false;
                }
            }
            System.out.println("Good Ip~ Success:" + ip + ", " + host + "," + url);
            return true;
        } catch (Exception e) {
            //e.printStackTrace();
            System.out.println("Bad URL~ Error:" + urlString);
            return false;
        }
    }
    //支持以下内网IP形式:
    //10.0.0.0/8
    //172.16.0.0/12
    //192.168.0.0/16
    private boolean equalIpSubnet(String ip, String blacklistIp) {
        long ipAddr = IpUtil.ip2long(ip);
        int type = Integer.parseInt(blacklistIp.replaceAll(".*/", ""));
        int mask = 0xFFFFFFFF << (32 - type);
        String cidrIp = blacklistIp.replaceAll("/.*", "");
        long cidrIpAddr = IpUtil.ip2long(cidrIp);
        return (ipAddr & mask) == (cidrIpAddr & mask);

    }    
}

在上述代码中,有一个识别是否为内网的代码通过计算是否在ip范围来实现检测,还是比较实用的。

4、使用SpringAOP做拦截器拦截非法请求

      这部分就比较常用了。

@Component
public class Interceptor implements HandlerInterceptor {
    SSRFChecker ssrfChecker = new SSRFChecker();
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
//        // 获取方法上的注解
        Diffintercept requiredStatistics = handlerMethod.getMethod().getAnnotation(Diffintercept.class);
       //如果不为空,说明有方法请求
        if(requiredStatistics!=null){
            //获取参数
            String requestUrl = request.getParameter("requestUrl");
            String requestUrl2 = request.getParameter("requestUrl2");
            //解码
            requestUrl = URLDecoder.decode(requestUrl, "UTF-8");
            requestUrl2 = URLDecoder.decode(requestUrl2, "UTF-8");
            //判断是否为白名单账号,防止请求非法数据。
            boolean b1 = ssrfChecker.checkURL(requestUrl);
            boolean b2 = ssrfChecker.checkURL(requestUrl2);
            //如果不相等,说明存在非法请求,返回false
            if(!b1||!b2) {
                //重置response
                response.reset();
                 //设置编码格式
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json;charset=UTF-8");
                PrintWriter pw = response.getWriter();
                pw.write("非法访问地址,请先注册后在使用diff工具");
                pw.flush();
                pw.close();
                return false;
            }
            //在这里可以做一个一个参数是否规范的验证,也可以在前端做校验。明后天完成这部分内容
            return true;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //System.out.println("afterCompletion");
    }
}

 

好的,下面是一个Java自定义flume拦截器的示例代码,可以用于拦截指定文件的地名数据: ```java import org.apache.flume.Context; import org.apache.flume.Event; import org.apache.flume.interceptor.Interceptor; import java.nio.charset.Charset; import java.util.List; public class LocationInterceptor implements Interceptor { @Override public void initialize() { } @Override public Event intercept(Event event) { String body = new String(event.getBody(), Charset.forName("UTF-8")); if (body.contains("北京") || body.contains("上海") || body.contains("广州")) { return event; } else { return null; } } @Override public List<Event> intercept(List<Event> events) { for (int i = 0; i < events.size(); i++) { Event interceptedEvent = intercept(events.get(i)); if (interceptedEvent == null) { events.remove(i); i--; } else { events.set(i, interceptedEvent); } } return events; } @Override public void close() { } public static class Builder implements Interceptor.Builder { @Override public void configure(Context context) { } @Override public Interceptor build() { return new LocationInterceptor(); } } } ``` 上面的代码,我们定义了一个`LocationInterceptor`类,用于拦截包含指定地名数据的日志事件。在`intercept`方法,我们获取到事件的内容判断是否包含北京、上海或广州这三个地名,如果包含则返回该事件,否则返回null。在`intercept(List<Event> events)`方法,我们对事件列表的每个事件都进行拦截操作,并返回拦截后的事件列表。 接下来,是flume的配置文件示例: ```properties # flume 的配置文件 # 定义 source、channel 和 sink a1.sources = r1 a1.channels = c1 a1.sinks = k1 # 定义 source 的类型、参数和拦截器 a1.sources.r1.type = exec a1.sources.r1.command = tail -F /path/to/your/log/file a1.sources.r1.interceptors = i1 a1.sources.r1.interceptors.i1.type = com.example.LocationInterceptor$Builder # 定义 channel 的类型和参数 a1.channels.c1.type = memory a1.channels.c1.capacity = 1000 a1.channels.c1.transactionCapacity = 100 # 定义 sink 的类型、参数和 channel a1.sinks.k1.type = logger a1.sinks.k1.channel = c1 # 绑定 source、channel 和 sink a1.sources.r1.channels = c1 a1.sinks.k1.channel = c1 ``` 上面的配置文件,我们定义了一个名为`LocationInterceptor`的拦截器,并将其绑定到source上。在source,我们使用`exec`类型的source,指定要收集的日志文件路径。在sink,我们使用`logger`类型的sink,将日志信息输出到控制台。 注意:在使用这个示例代码时,需要将`/path/to/your/log/file`替换成你要收集的日志文件路径。同时,记得将`LocationInterceptor`类所在的包名修改为你自己的包名。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值