URIBuilder与SSRF

在使用一个静态扫描工具时,报了一个SSRF的问题,经过数据流的分析,导致此工具报SSRF的原因是在调用URIBuilder的setPath函数时,参数是从请求里获取的,导致了数据流被污染,因此认为由URIBuilder构造的URL也被污染,最终导致URIBuilder构造出来的URI被污染,所以,认为可能会导致SSRF问题。

为了弄清楚到底是否会导致SSRF问题,针对URIBuilder进行了以下探索。

URIBuilder有多个实现,首先看看apache的【org.apache.http.client.utils.URIBuilder】实现如下:

public URIBuilder setPath(String path) {
        return this.setPathSegments(path != null ? URLEncodedUtils.splitPathSegments(path) : null);
    }

    public URIBuilder setPathSegments(String... pathSegments) {
        this.pathSegments = pathSegments.length > 0 ? Arrays.asList(pathSegments) : null;
        this.encodedSchemeSpecificPart = null;
        this.encodedPath = null;
        return this;
    }

path变量经过segments处理之后直接就赋值给了pathSegments,没有进行任何处理。从代码的角度可以看出,这里的path如果含有../../之类的字符,URIBuilder应该没有处理。于是写了以下代码进行测试:

public static void testPath(){
        URIBuilder uriBuilder = new URIBuilder();
        uriBuilder.setPath("../../example/path");
        URI uri = null;
        try {
            uri = uriBuilder.build();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        System.out.println("test path result:"+uri.toString());
    }

打印的结果如下:

可以看出这里的路径如预料的一样没有被处理。

由于URIBuilder还有setParameter和setParameters方法,于是为了测试设置参数时,是否进行了处理,进一步测试代码如下:

public static void testPatameter(){
        URIBuilder uriBuilder = new URIBuilder();
        uriBuilder.setScheme("https");
        uriBuilder.setHost("www.test.com");
        uriBuilder.setPath("../../example/path");
        uriBuilder.setParameter("para1", "val1&para2=val2");
        uriBuilder.setParameter("para2", "val2");
        URI uri = null;
        try {
            uri = uriBuilder.build();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        System.out.println("test parameter result:"+uri.toString());
    }

    public static void testPatameterList(){
        URIBuilder uriBuilder = new URIBuilder();
        uriBuilder.setScheme("https");
        uriBuilder.setHost("www.test.com");
        uriBuilder.setPath("../../example/path");

        List<NameValuePair> paraList = new ArrayList<NameValuePair>();
        paraList.add(new BasicNameValuePair("para3", "val3&para4=val4"));
        paraList.add(new BasicNameValuePair("para4", "val4"));
        uriBuilder.setParameters(paraList);
        URI uri = null;
        try {
            uri = uriBuilder.build();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        System.out.println("test parameter list result:"+uri.toString());
    }

运行结果如下图:

查看代码setParameter时,发现在设置时也没有编码,于是进一步探测在构建URI时的代码如下:

    private String buildString() {
        StringBuilder sb = new StringBuilder();
        if (this.scheme != null) {
            sb.append(this.scheme).append(':');
        }

        if (this.encodedSchemeSpecificPart != null) {
            sb.append(this.encodedSchemeSpecificPart);
        } else {
            if (this.encodedAuthority != null) {
                sb.append("//").append(this.encodedAuthority);
            } else if (this.host != null) {
                sb.append("//");
                if (this.encodedUserInfo != null) {
                    sb.append(this.encodedUserInfo).append("@");
                } else if (this.userInfo != null) {
                    sb.append(this.encodeUserInfo(this.userInfo)).append("@");
                }

                if (InetAddressUtils.isIPv6Address(this.host)) {
                    sb.append("[").append(this.host).append("]");
                } else {
                    sb.append(this.host);
                }

                if (this.port >= 0) {
                    sb.append(":").append(this.port);
                }
            }

            if (this.encodedPath != null) {
                sb.append(normalizePath(this.encodedPath, sb.length() == 0));
            } else if (this.pathSegments != null) {
                sb.append(this.encodePath(this.pathSegments));
            }

            if (this.encodedQuery != null) {
                sb.append("?").append(this.encodedQuery);
            } else if (this.queryParams != null && !this.queryParams.isEmpty()) {
                sb.append("?").append(this.encodeUrlForm(this.queryParams));
            } else if (this.query != null) {
                sb.append("?").append(this.encodeUric(this.query));
            }
        }

        if (this.encodedFragment != null) {
            sb.append("#").append(this.encodedFragment);
        } else if (this.fragment != null) {
            sb.append("#").append(this.encodeUric(this.fragment));
        }

        return sb.toString();
    }

在buildString里,将参数进行了URIEncode,所以,转成的URL字符串里参数的值是URL编码的。

在组装Path时,虽然调用了normalizePath,但是,根据normalizePath的实现代码如下:

    private static String normalizePath(String path, boolean relative) {
        String s = path;
        if (TextUtils.isBlank(path)) {
            return "";
        } else {
            if (!relative && !path.startsWith("/")) {
                s = "/" + path;
            }

            return s;
        }
    }

可以了解normalizePath只是在不是空的情况下在path前面添加一个斜线,其他并没有对输入的path进行任何处理。

通过以上实现可以看出,针对URL中的Path的处理是不安全的,但是对Parameter的处理是安全的。所以,在使用path之前,需要对path进行有效性验证,否则可能组装出以上例子里给出的路径。

接着,又测试了一下Spring framework的org.springframework.web.util.UriComponentsBuilder,测试代码如下:

public static void testPath(){
        UriComponentsBuilder builder = UriComponentsBuilder.newInstance();
        builder.scheme("https")
                .host("www.example.com")
                .port(443)
                .path("../../example/path")
                .queryParam("page", 1)
                .queryParam("size", 10);

        System.out.println("Spring test path result:"+builder.toUriString());
    }

    public static void testPatameter(){
        UriComponentsBuilder builder = UriComponentsBuilder.newInstance();
        builder.scheme("https")
                .host("www.example.com")
                .port(443)
                .path("../../example/path")
                .queryParam("para1", "val1&para2=val2")
                .queryParam("para2", "val2");

        System.out.println("Spring test parameter result:"+builder.toUriString());
    }

测试结果如下:

看来可能各个库对路径和参数的实现还是比较一致的,设置参数时,库会对参数进行编码处理,不会导致HPP问题【HPP的介绍可以参考:应用安全系列之九:HTTP参数污染_java http参数污染怎么解决-CSDN博客】。

但是关于路径,就需要使用者在调用URIBuilder之前对path的值进行验证之后才能使用。

不过,根据SSRF在OWASP TOP10网站的定义如下:

SSRF flaws occur whenever a web application is fetching a remote resource without validating the user-supplied URL. It allows an attacker to coerce the application to send a crafted request to an unexpected destination, even when protected by a firewall, VPN, or another type of network access control list (ACL).

可见,这里定义只是把SSRF定义为访问远程的资源。如果设置host时,输入的参数没有进行白名单范围验证,毫无争议地就是SSRF问题。但是,由于路径遍历导致访问此服务器的资源也已经偏离了这个URL原始的初衷,也可以认为它时一种影响范围比较小的SSRF。无论如何都需要在使用输入的参数作为URL的path的一部分之前,要进行输入验证,避免路径跳跃的问题出现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/237042.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

作为一个产品经理带你了解Axure的安装和基本使用

1.Axure的简介 Axure是一种强大的原型设计工具&#xff0c;它允许用户创建交互式的、高保真度的原型&#xff0c;以及进行用户体验设计和界面设计。Axure可以帮助设计师和产品经理快速创建和共享原型&#xff0c;以便团队成员之间进行沟通和反馈。Axure提供了丰富的交互组件和功…

【EI会议征稿中|JPCS出版】第三届电子与集成电路技术国际学术会议(EICT 2024)

第三届电子与集成电路技术国际学术会议&#xff08;EICT 2024&#xff09; 2024 3rd International Conference on Electronics and Integrated Circuit Technology 第三届电子与集成电路技术国际学术会议&#xff08;EICT 2024&#xff09;将于2024年4月12至14日在南昌市举行…

Vue3封装一个轮播图组件

先看效果 编写组件代码 CarouselChart.vue <template><div classimg-box><el-button clickpreviousImages v-ifprops.showBtn>←</el-button><div classimg><div styledisplay: flex;gap: 20px idmove><imgclassimg-item v-for(item…

Github上火爆的个人知识管理AI大脑:Quivr

Github上火爆的个人知识管理AI大脑&#xff1a;Quivr。 演示视频&#xff1a; Github上火爆的个人知识管理AI大脑&#xff1a;Quivr 点击上面视频观看&#xff01;&#xff01;&#xff01; II. Quivr 的强大功能 与文件和应用程序聊天 把你的文件和应用看成你的对话伙伴&…

“险棋”更是“好棋”,鸿蒙生态为什么值得加入?

作者 | 曾响铃 文 | 响铃说 支付宝大张旗鼓与鸿蒙合作后&#xff0c;已经有高德地图、哔哩哔哩、阿里钉钉、美团、支付宝、小红书等十多个领域的独角兽企业集体宣布将开发鸿蒙原生应用&#xff0c;携手华为共同推动鸿蒙生态发展。 早前&#xff0c;有关华为鸿蒙系统可能将于…

Java中的IO流③——转换流、序列化流、反序列化流、打印流

目录 转换流 代码演示 总结 序列化流&反序列化流 序列化流 构造和成员方法 细节 代码演示 反序列化流 代码演示 序列化流和反序列化流细节 综合练习 打印流 字节打印流 代码演示 字符打印流 代码演示 总结 转换流 转换流可以将字节流转成字符流&#xff0…

【MySQL】:表的操作

表的操作 一.创建表二.查看表结构三.修改表四.删除表 一.创建表 field 表示列名。 datatype 表示列的类型。 character set 字符集&#xff0c;如果没有指定字符集&#xff0c;则以所在数据库的字符集为准。 collate 校验规则&#xff0c;如果没有指定校验规则&#xff0c;则以…

侯捷C++ 程序的生前死后

生前&#xff1a;CRT startup code 看完课程&#xff0c;能够回答一下问题&#xff1a; C进入点是main()嘛&#xff1f;什么代码比main更早执行&#xff1f;什么代码在main结束后执行&#xff1f;为什么上述代码可以如此行为&#xff1f;Heap的结构如何&#xff1f;I/O的结构…

redis(设置密码)配置文件详细

1.设置账号密码端口 config set requirepass 123456 设置密码为123456 config get requirepass 查看账号密码 auth 123456 登入的时候输入这个确定账号密码 1. 首先连接到Redis服务器: redis-cli 2. 然后使用CONFIG SET命令设置requirepass参数并指定密码: CONFIG SET requi…

代码随想录二刷| 二叉树 |二叉树的所有路径

代码随想录二刷&#xff5c; 二叉树 &#xff5c;二叉树的所有路径 题目描述解题思路递归 代码实现递归 题目描述 257.二叉树的所有路径 给你一个二叉树的根节点 root &#xff0c;按 任意顺序 &#xff0c;返回所有从根节点到叶子节点的路径。 叶子节点 是指没有子节点的节…

AP9111手电筒专用集成电路芯片 单节干电池 LED手电筒IC

概述 AP9111 是 LED 手电筒专用集成电路芯片 &#xff0c;是一款采用大规模集成电路技术&#xff0c;专门针对单节干电池的 LED 手电筒设计的一款专用集成电路。外加 1 个电感元件&#xff0c;即可构成 LED 手电筒驱动电路板。AP 9111 性能优越、可靠性高、使用简单、生产一致…

Java - JVM内存区域的划分

Java 程序运行时&#xff0c;需要在内存中分配空间。为了提高运算效率&#xff0c;就对空间进行了不同区域的划分&#xff0c;因为每一片区域都有特定的处理数据方式和内存管理方式。 分配&#xff1a;通过关键字new创建对象分配内存空间&#xff0c;对象存在堆中。 释放 &…

编译 Flink代码

构建环境 JDK1.8以上和Maven 3.3.x可以构建Flink&#xff0c;但是不能正确地遮盖某些依赖项。Maven 3.2.5会正确创建库。所以这里使用为了减少问题选择 Maven3.2.5版本进行构建。要构建单元测试&#xff0c;请使用Java 8以上&#xff0c;以防止使用PowerMock运行器的单元测试失…

011 数据结构_哈希

前言 本文将会向你介绍哈希概念&#xff0c;哈希方法&#xff0c;如何解决哈希冲突&#xff0c;以及闭散列与开散列的模拟实现 1. 哈希概念 顺序结构以及平衡树中&#xff0c;元素关键码与其存储位置之间没有对应的关系&#xff0c;因此在查找一个元素时&#xff0c;必须要经…

【MATLAB】基于CEEMDAN分解的信号去噪算法(基础版)

代码的使用说明 【MATLAB】基于CEEMDAN分解的信号去噪算法&#xff08;基础版&#xff09; 代码流程图 代码效果图 获取代码请关注MATLAB科研小白的个人公众号&#xff08;即文章下方二维码&#xff09;&#xff0c;并回复CEEMDAN去噪 本公众号致力于解决找代码难&#xff0c;…

数据结构与算法-Rust 版读书笔记-2线性数据结构-队列

数据结构与算法-Rust 版读书笔记-2线性数据结构-队列 1、队列&#xff1a;先进先出 队列是项的有序集合&#xff0c;其中&#xff0c;添加新项的一端称为队尾&#xff0c;移除项的另一端称为队首。一个元素在从队尾进入队列后&#xff0c;就会一直向队首移动&#xff0c;直到…

最大上升子序列和

欢迎大家到我的博客浏览&#xff0c;请点击 YinKai s Blog。 题目&#xff1a;最大上升子序列和 一个数的序列 bi&#xff0c;当 b1<b2<…<bS 的时候&#xff0c;我们称这个序列是上升的。 对于给定的一个序列(a1,a2,…,aN)&#xff0c;我们可以得到一些上升的子序列…

c语言中怎么把字符串变成浮点型

大家好&#xff0c;今天给大家介绍c语言中怎么把字符串变成浮点型&#xff0c;文章末尾附有分享大家一个资料包&#xff0c;差不多150多G。里面学习内容、面经、项目都比较新也比较全&#xff01;可进群免费领取。 可以使用Python内置函数float()将字符串转换为浮点型。例如&a…

应对复杂环境:配网故障定位系统的挑战与解决方案

随着电力系统的不断发展&#xff0c;配电网络日益庞大&#xff0c;复杂的环境和多样化的故障类型给电网运维带来了巨大的挑战。为了提高配电网络的安全性和可靠性&#xff0c;需要研发一套高效的配网故障定位系统。恒峰智慧科技将探讨这一系统面临的挑战以及解决方案。 一、监测…

【Java 基础】30 JDK动态代理

文章目录 1.定义2.原理3.使用1&#xff09;定义业务接口2&#xff09;实现 InvocationHandler 接口3&#xff09;生成代理类 4.优点5.缺点总结 动态代理是一种重要的 设计模式&#xff0c;它允许在运行时生成代理类来代替实际的类。动态代理主要通过反射机制实现&#xff0c;为…