java重定向代码_【缺陷周话】第 34 期:重定向

9fdf8e33be27eecc71dd32e72f0f30df.gif 聚焦源代码安全,网罗国内外最新资讯!

*声明:《缺陷周话》栏目系列文章由奇安信代码卫士团队原创出品。未经许可,禁止转载。转载请注明“转自奇安信代码卫士 www.codesafe.cn”。

代码审计是使用静态分析发现源代码中安全缺陷的方法,辅助开发或测试人员在软件上线前较为全面地了解安全问题,防患于未然,因此一直以来都是学术界和产业界研究的热点,并已成为安全开发生命周期 SDL 和 DevSecOps 等保障体系的重要技术手段。

奇安信代码卫士团队基于自主研发的国内首款源代码安全检测商用工具,以及十余年漏洞技术研究的积累,推出“缺陷周话”系列栏目。每周针对 CWE、OWASP 等标准中的一类缺陷,结合实例和工具使用进行详细介绍,旨在为广大开发和安全人员提供代码审计的基础性标准化教程。

缺陷周话 • 第34期

重定向   

1、重定向

b00090c2385314c69c245ba2fab1b7fb.png

重定向漏洞是指Web应用程序接受用户控制的输入,该输入指向外部站点的URL,攻击者通过对URL进行编码或者携带参数,令篡改后的URL在看起来与原始站点URL很像,并在重定向时使用该URL,导致用户进入恶意站点。本篇文章以JAVA语言源代码为例,分析重定向漏洞产生的原因以及修复方法。详细请参见CWE ID 601:URL Redirection toUntrusted Site ('Open Redirect') (http://cwe.mitre.org/data/definitions/601.html)。

2、 重定向的危害

aa6baf062c75fd7024a36d34d9ff3871.png

利用重定向漏洞可以诱使用户访问恶意站点,盗取用户密码记录、强制用户下载任意文件等。

从2019年1月至2019年5月,CVE中共有30条漏洞信息与其相关。部分漏洞如下:

CVE概况

CVE-2019-4166

IBM StoredIQ 7.6 可能允许远程攻击者使用重定向进行网络钓鱼攻击。通过说服受害者访问特制网站,远程攻击者可以利用此漏洞显示携带恶意参数的正常URL,以将用户重定向到看似可信的恶意网站。这可能允许攻击者获取高度敏感的信息或对受害者进行进一步攻击。

CVE-2019-10255

5.7.7 之前的 Jupyter Notebook 中的所有浏览器以及 0.9.5 之前的JupyterHub中的某些浏览器(Chrome,Firefox)的重定向漏洞允许精心设置的登录页面链接,登录页面成功登录后将重定向到恶意站点。在base_url前缀上运行的服务器不受影响。

CVE-2019-3850

moodle在版本3.6.3,3.5.5,3.4.8和3.1.17之前存在一个重定向漏洞。作业提交评论中的链接将直接打开(在同一窗口中)。虽然链接本身可能是有效的,但在同一窗口内打开并且没有no-referrer头策略使它们更容易受到攻击。

3、示例代码

aa6baf062c75fd7024a36d34d9ff3871.png

示例源于 Samate Juliet Test Suite for Java v1.3 (https://samate.nist.gov/SARD/testsuite.php),源文件名:CWE601_Open_Redirect__Servlet_connect_tcp_01.java。

3.1缺陷代码

67d3596b857678bbda40918c175873fc.png

1e20f5188298db6f4c1f87a5723aa864.png

上述示例代码是获取到用户输入的数据并将该数据作为重定向的URL地址进行跳转,在第54行获取 Socket 对象从客户端发送给服务器端的数据流, InputStreamReader 是从字节流到字符流的桥接器,使用 UTF-8 读取字节并将它们解码为字符。第56行将 readerInputStream作为参数构造字符缓冲输入流,59行缓冲流读取一行数据并赋值给 data。在第125行 response 重定向到 data 指定的 URL。该URL并未被校验,无法确定是否安全,未验证的重定向可能会使用户进入钓鱼网站,窃取用户信息等,会对用户的信息以及财产安全造成严重的威胁。

使用代码卫士对上述示例代码进行检测,可以检出“重定向”缺陷,显示等级为高。在代码行第125行报出缺陷,如图1所示:

669b23be55d0c202b3dde15d74241b3e.png

图1:重定向的检测示例

3.2 修复代码

4e349971d968cae2a975d1ee1593ff1f.png

在上述修复代码中,在第125行不使用用户传入数据,在程序内部控制重定向的URL,避免出现钓鱼,盗取用户信息等安全问题。

使用代码卫士对修复后的代码进行检测,可以看到已不存在“重定向”缺陷。如图2:

daf30f47c20f284c4262793fe6c93c51.png

图2:修复后检测结果

4、  如何避免重定向

aa6baf062c75fd7024a36d34d9ff3871.png

要避免重定向,需要注意以下几点:

1. 尽量避免使用重定向和转发机制,如果使用了,那么在定义目标URL的时候不要包含用户参数。

2. 如果一定要包含用户输入的参数,对每个参数都必须进行验证以确保它的合法性和正确性,或是在服务端提供映射机制,将用户的选择参数转变为真正的白名单目标页面。

推荐阅读

【缺陷周话】第 33期:错误的资源关闭

【缺陷周话】第 32期:弱加密

【缺陷周话】第 31 期:错误的内存释放方法

【缺陷周话】第 30 期:不安全的哈希算法

【缺陷周话】第 29 期:返回栈地址

【缺陷周话】第 28 期:被污染的内存分配

【缺陷周话】第 27 期:不安全的随机数

【缺陷周话】第 26期:被污染的格式化字符串

【缺陷周话】第 25期:硬编码密码

【缺陷周话】第 24期:在scanf 函数中没有对 %s 格式符进行宽度限制

【缺陷周话】第 23期:双重检查锁定

【缺陷周话】第 22期:错误的内存释放对象

【缺陷周话】第 21 期:数据库访问控制

【缺陷周话】第 20 期:无符号整数回绕

【缺陷周话】第19期:LDAP 注入

【缺陷周话】第18 期  XPath 注入

【缺陷周话】第17 期:有符号整数溢出

【缺陷周话】第 16 期 — 资源未释放:流

【缺陷周话】第 15 期 — 资源未释放:文件

【缺陷周话】第 14 期 :HTTP 响应截断

【缺陷周话】第 13期 :二次释放

【缺陷周话】第 12期 :存储型 XSS

【缺陷周话】第 11期 :释放后使用

【缺陷周话】第 10 期 :反射型 XSS

【缺陷周话】第 9 期 :缓冲区下溢

【缺陷周话】第 8 期 :路径遍历

【缺陷周话】第 7 期 :缓冲区上溢

【缺陷周话】第 6 期 :命令注入

【缺陷周话】第5期 :越界访问

【缺陷周话】第4期 :XML 外部实体注入

【缺陷周话】第3期 :内存泄漏

【缺陷周话】第 2 期 :SQL 注入

【缺陷周话】第1期 :空指针解引用

*奇安信代码卫士团队原创出品。未经许可,禁止转载。转载请注明“转自奇安信代码卫士 www.codesafe.cn”。

2c146330d69f79d1ac1fda0a073dc75c.png

奇安信代码卫士 (codesafe)

国内首个专注于软件开发安全的产品线。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JAVA_Thinking in Java(文版 由yyc,spirit整理).chm ------------------------------------------------- 本教程由yyc,spirit整理 ------------------------------------------------- “Thinking in Java”详细目录   写在前面的话 引言 1. 前提 2. Java的学习 3. 目标 4. 联机文档 5. 章节 6. 练习 7. 多媒体CD-ROM 8. 源代码 9. 编码样式 10. Java版本 11. 课程和培训 12. 错误 13. 封面设计 14. 致谢 第1章 对象入门 1.1 抽象的进步 1.2 对象的接口 1.3 实现方案的隐藏 1.4 方案的重复使用 1.5 继承:重新使用接口 1.5.1 改善基础类 1.5.2 等价和类似关系 1.6 多形对象的互换使用 1.6.1 动态绑定 1.6.2 抽象的基础类和接口 1.7 对象的创建和存在时间 1.7.1 集合与继承器 1.7.2 单根结构 1.7.3 集合库与方便使用集合 1.7.4 清除时的困境:由谁负责清除? 1.8 违例控制:解决错误 1.9 多线程 1.10 永久性 1.11 Java和因特网 1.11.1 什么是Web? 1.11.2 客户端编程 1.11.3 服务器端编程 1.11.4 一个独立的领域:应用程序 1.12 分析和设计 1.12.1 不要迷失 1.12.2 阶段0:拟出一个计划 1.12.3 阶段1:要制作什么? 1.12.4 阶段2:开始构建? 1.12.5 阶段3:正式创建 1.12.6 阶段4:校订 1.12.7 计划的回报 1.13 Java还是C++? 第2章 一切都是对象 2.1 用句柄操纵对象 2.2 必须创建所有对象 2.2.1 保存在什么地方 2.2.2 特殊情况:主类型 2.2.3 Java的数组 2.3 绝对不要清除对象 2.3.1 作用域 2.3.2 对象的作用域 2.4 新建数据类型:类 2.4.1 字段和方法 2.5 方法、自变量和返回值 2.5.1 自变量列表 2.6 构建Java程序 2.6.1 名字的可见性 2.6.2 使用其他组件 2.6.3 static关键字 2.7 我们的第一个Java程序 2.8 注释和嵌入文档 2.8.1 注释文档 2.8.2 具体语法 2.8.3 嵌入HTML 2.8.4 @see:引用其他类 2.8.5 类文档标记 2.8.6 变量文档标记 2.8.7 方法文档标记 2.8.8 文档示例 2.9 编码样式 2.10 总结 2.11 练习 第3章 控制程序流程 3.1 使用Java运算符 3.1.1 优先级 3.1.2 赋值 3.1.3 算术运算符 3.1.4 自动递增和递减 3.1.5 关系运算符 3.1.6 逻辑运算符 3.1.7 按位运算符 3.1.8 移位运算符 3.1.9 三元if-else运算符 3.1.10 逗号运算符 3.1.11 字串运算符+ 3.1.12 运算符常规操作规则 3.1.13 造型运算符 3.1.14 Java没有“sizeof” 3.1.15 复习计算顺序 3.1.16 运算符总结 3.2 执行控制 3.2.1 真和假 3.2.2 if-else 3.2.3 反复 3.2.4 do-while 3.2.5 for 3.2.6 断和继续 3.2.7 切换 3.3 总结 3.4 练习 第4章 初始化和清除 4.1 由构建器保证初始化 4.2 方法过载 4.2.1 区分过载方法 4.2.2 主类型的过载 4.2.3 返回值过载 4.2.4 默认构建器 4.2.5 this关键字 4.3 清除:收尾和垃圾收集 4.3.1 finalize()用途何在 4.3.2 必须执行清除 4.4 成员初始化 4.4.1 规定初始化 4.4.2 构建器初始化 4.5 数组初始化 4.5.1 多维数组 4.6 总结 4.7 练习 第5章 隐藏实施过程 5.1 包:库单元 5.1.1 创建独一无二的包名 5.1.2 自定义工具库 5.1.3 利用导入改变行为 5.1.4 包的停用 5.2 Java访问指示符 5.2.1 “友好的” 5.2.2 public:接口访问 5.2.3 private:不能接触 5.2.4 protected:“友好的一种” 5.3 接口与实现 5.4 类访问 5.5 总结 5.6 练习 第6章 类再生 6.1 合成的语法 6.2 继承的语法 6.2.1 初始化基础类 6.3 合成与继承的结合 6.3.1 确保正确的清除 6.3.2 名字的隐藏 6.4 到底选择合成还是继承 6.5 protected 6.6 递增开发 6.7 上溯造型 6.7.1 何谓“上溯造型”? 6.8 final关键字 6.8.1 final数据 6.8.2 final方法 6.8.3 final类 6.8.4 final的注意事项 6.9 初始化和类装载 6.9.1 继承初始化 6.10 总结 6.11 练习 第7章 多形性 7.1 上溯造型 7.1.1 为什么要上溯造型 7.2 深入理解 7.2.1 方法调用的绑定 7.2.2 产生正确的行为 7.2.3 扩展性 7.3 覆盖与过载 7.4 抽象类和方法 7.5 接口 7.5.1 Java的“多重继承” 7.5.2 通过继承扩展接口 7.5.3 常数分组 7.5.4 初始化接口的字段 7.6 内部类 7.6.1 内部类和上溯造型 7.6.2 方法和作用域的内部类 7.6.3 链接到外部类 7.6.4 static内部类 7.6.5 引用外部类对象 7.6.6 从内部类继承 7.6.7 内部类可以覆盖吗? 7.6.8 内部类标识符 7.6.9 为什么要用内部类:控制框架 7.7 构建器和多形性 7.7.1 构建器的调用顺序 7.7.2 继承和finalize() 7.7.3 构建器内部的多形性方法的行为 7.8 通过继承进行设计 7.8.1 纯继承与扩展 7.8.2 下溯造型与运行类型标识 7.9 总结 7.10 练习 第8章 对象的容纳 8.1 数组 8.1.1 数组和第一类对象 8.1.2 数组的返回 8.2 集合 8.2.1 缺点:类型未知 8.3 枚举器(反复器) 8.4 集合的类型 8.4.1 Vector 8.4.2 BitSet 8.4.3 Stack 8.4.4 Hashtable 8.4.5 再论枚举器 8.5 排序 8.6 通用集合库 8.7 新集合 8.7.1 使用Collections 8.7.2 使用Lists 8.7.3 使用Sets 8.7.4 使用Maps 8.7.5 决定实施方案 8.7.6 未支持的操作 8.7.7 排序和搜索 8.7.8 实用工具 8.8 总结 8.9 练习 第9章 违例差错控制 9.1 基本违例 9.1.1 违例自变量 9.2 违例的捕获 9.2.1 try块 9.2.2 违例控制器 9.2.3 违例规范 9.2.4 捕获所有违例 9.2.5 重新“掷”出违例 9.3 标准Java违例 9.3.1 RuntimeException的特殊情况 9.4 创建自己的违例 9.5 违例的限制 9.6 用finally清除 9.6.1 用finally做什么 9.6.2 缺点:丢失的违例 9.7 构建器 9.8 违例匹配 9.8.1 违例准则 9.9 总结 9.10 练习 第10章 Java IO系统 10.1 输入和输出 10.1.1 InputStream的类型 10.1.2 OutputStream的类型 10.2 增添属性和有用的接口 10.2.1 通过FilterInputStream从InputStream里读入数据 10.2.2 通过FilterOutputStream向OutputStream里写入数据 10.3 本身的缺陷:RandomAccessFile 10.4 File类 10.4.1 目录列表器 10.4.2 检查与创建目录 10.5 IO流的典型应用 10.5.1 输入流 10.5.2 输出流 10.5.3 快捷文件处理 10.5.4 从标准输入读取数据 10.5.5 管道数据流 10.6 StreamTokenizer 10.6.1 StringTokenizer 10.7 Java 1.1的IO流 10.7.1 数据的发起与接收 10.7.2 修改数据流的行为 10.7.3 未改变的类 10.7.4 一个例子 10.7.5 重定向标准IO 10.8 压缩 10.8.1 用GZIP进行简单压缩 10.8.2 用Zip进行多文件保存 10.8.3 Java归档(jar)实用程序 10.9 对象串联 10.9.1 寻找类 10.9.2 序列化的控制 10.9.3 利用“持久性” 10.10 总结 10.11 练习 第11章 运行类型鉴定 11.1 对RTTI的需要 11.1.1 Class对象 11.1.2 造型前的检查 11.2 RTTI语法 11.3 反射:运行类信息 11.3.1 一个类方法提取器 11.4 总结 11.5 练习 第12章 传递和返回对象 12.1 传递句柄 12.1.1 别名问题 12.2 制作本地副本 12.2.1 按值传递 12.2.2 克隆对象 12.2.3 使类具有克隆能力 12.2.4 成功的克隆 12.2.5 Object.clone()的效果 12.2.6 克隆合成对象 12.2.7 用Vector进行深层复制 12.2.8 通过序列化进行深层复制 12.2.9 使克隆具有更大的深度 12.2.10 为什么有这个奇怪的设计 12.3 克隆的控制 12.3.1 副本构建器 12.4 只读类 12.4.1 创建只读类 12.4.2 “一成不变”的弊端 12.4.3 不变字串 12.4.4 String和StringBuffer类 12.4.5 字串的特殊性 12.5 总结 12.6 练习 第13章 创建窗口和程序片 13.1 为何要用AWT? 13.2 基本程序片 13.2.1 程序片的测试 13.2.2 一个更图形化的例子 13.2.3 框架方法的演示 13.3 制作按钮 13.4 捕获事件 13.5 文本字段 13.6 文本区域 13.7 标签 13.8 复选框 13.9 单选钮 13.10 下拉列表 13.11 列表框 13.11.1 handleEvent() 13.12 布局的控制 13.12.1 FlowLayout 13.12.2 BorderLayout 13.12.3 GridLayout 13.12.4 CardLayout 13.12.5 GridBagLayout 13.13 action的替用品 13.14 程序片的局限 13.14.1 程序片的优点 13.15 视窗化应用 13.15.1 菜单 13.15.2 对话框 13.16 新型AWT 13.16.1 新的事件模型 13.16.2 事件和接收者类型 13.16.3 用Java 1.1 AWT制作窗口和程序片 13.16.4 再探早示例 13.16.5 动态绑定事件 13.16.6 将商业逻辑与UI逻辑区分开 13.16.7 推荐编码方法 13.17 Java 1.1 UI API 13.17.1 桌面颜色 13.17.2 打印 13.17.3 剪贴板 13.18 可视编程和Beans 13.18.1 什么是Bean 13.18.2 用Introspector提取BeanInfo 13.18.3 一个更复杂的Bean 13.18.4 Bean的封装 13.18.5 更复杂的Bean支持 13.18.6 Bean更多的知识 13.19 Swing入门 13.19.1 Swing有哪些优点 13.19.2 方便的转换 13.19.3 显示框架 13.19.4 工具提示 13.19.5 边框 13.19.6 按钮 13.19.7 按钮组 13.19.8 图标 13.19.9 菜单 13.19.10 弹出式菜单 13.19.11 列表框和组合框 13.19.12 滑杆和进度指示条 13.19.13 树 13.19.14 表格 13.19.15 卡片式对话框 13.19.16 Swing消息框 13.19.17 Swing更多的知识 13.20 总结 13.21 练习 第14章 多线程 14.1 反应灵敏的用户界面 14.1.1 从线程继承 14.1.2 针对用户界面的多线程 14.1.3 用主类合并线程 14.1.4 制作多个线程 14.1.5 Daemon线程 14.2 共享有限的资源 14.2.1 资源访问的错误方法 14.2.2 Java如何共享资源 14.2.3 回顾Java Beans 14.3 堵塞 14.3.1 为何会堵塞 14.3.2 死锁 14.4 优先级 14.4.1 线程组 14.5 回顾runnable 14.5.1 过多的线程 14.6 总结 14.7 练习 第15章 网络编程 15.1 机器的标识 15.1.1 服务器和客户机 15.1.2 端口:机器内独一无二的场所 15.2 套接字 15.2.1 一个简单的服务器和客户机程序 15.3 服务多个客户 15.4 数据报 15.5 一个Web应用 15.5.1 服务器应用 15.5.2 NameSender程序片 15.5.3 15.5.3 要注意的问题 15.6 Java与CGI的沟通 15.6.1 CGI数据的编码 15.6.2 程序片 15.6.3 用C++写的CGI程序 15.6.4 POST的概念 15.7 用JDBC连接数据库 15.7.1 获得学习示例 15.7.2 查找程序的GUI版本 15.7.3 JDBC API为何如何复杂 15.8 远程方法 15.8.1 远程接口概念 15.8.2 远程接口的实施 15.8.3 创建根与干 15.8.4 使用远程对象 15.8.5 RMI的替选方案 15.9 总结 15.10 练习 第16章 设计范式 16.1 范式的概念 16.1.1 单子 16.1.2 范式分类 16.2 观察器范式 16.3 模拟垃圾回收站 16.4 改进设计 16.4.1 “制作更多的对象” 16.4.2 用于原型创建的一个范式 16.5 抽象的应用 16.6 多重派遣 16.6.1 实现双重派遣 16.7 访问器范式 16.8 RTTI有害吗 16.9 总结 16.10 练习 第17章 项目 17.1 文字处理 17.1.1 提取代码列表 17.1.2 检查大小写样式 17.2 方法查找工具 17.3 复杂性理论 17.4 总结 17.5 练习 附录A 使用非Java代码 A.1 Java固有接口 A.1.1 调用固有方法 A.1.2 访问JNI函数:JNIEnv自变量 A.1.3 传递和使用Java对象 A.1.4 JNI和Java违例 A.1.5 JNI和线程处理 A.1.6 使用现成代码 A.2 微软的解决方案 A.3 J/Direct A.3.1 @dll.import引导命令 A.3.2 com.ms.win32包 A.3.3 汇集 A.3.4 编写回调函数 A.3.5 其他J/Direct特性 A.4 本原接口(RNI) A.4.1 RNI总结 A.5 Java/COM集成 A.5.1 COM基础 A.5.2 MS Java/COM集成 A.5.3 用Java设计COM服务器 A.5.4 用Java设计COM客户 A.5.5 ActiveX/Beans集成 A.5.6 固有方法与程序片的注意事项 A.6 CORBA A.6.1 CORBA基础 A.6.2 一个例子 A.6.3 Java程序片和CORBA A.6.4 比较CORBA与RMI A.7 总结 附录B 对比C++和Java 附录C Java编程规则 附录D 性能 D.1 基本方法 D.2 寻找瓶颈 D.2.1 安插自己的测试代码 D.2.2 JDK性能评测[2] D.2.3 特殊工具 D.2.4 性能评测的技巧 D.3 提速方法 D.3.1 常规手段 D.3.2 依赖语言的方法 D.3.3 特殊情况 D.4 参考资源 D.4.1 性能工具 D.4.2 Web站点 D.4.3 文章 D.4.4 Java专业书籍 D.4.5 一般书籍 附录E 关于垃圾收集的一些话 附录F 推荐读物
好的,我知道你的问题了。关于Java实现响应重定向并发送POST请求的操作示例,可以参考以下代码: ```java import java.net.HttpURLConnection; import java.net.URL; import java.io.OutputStream; import java.io.BufferedReader; import java.io.InputStreamReader; public class RedirectAndPost { public static void main(String[] args) throws Exception { String url = "http://www.example.com/redirect"; String postBody = "param1=value1&param2=value2"; HttpURLConnection connection = null; URL redirectUrl = new URL(url); while (true) { connection = (HttpURLConnection) redirectUrl.openConnection(); connection.setInstanceFollowRedirects(false); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); connection.setRequestProperty("charset", "utf-8"); connection.setRequestProperty("Content-Length", Integer.toString(postBody.getBytes().length)); connection.setUseCaches(false); connection.setDoOutput(true); OutputStream outputStream = connection.getOutputStream(); outputStream.write(postBody.getBytes("UTF-8")); outputStream.flush(); outputStream.close(); int statusCode = connection.getResponseCode(); if (statusCode == HttpURLConnection.HTTP_MOVED_TEMP || statusCode == HttpURLConnection.HTTP_MOVED_PERM || statusCode == HttpURLConnection.HTTP_SEE_OTHER) { String redirectLocation = connection.getHeaderField("Location"); redirectUrl = new URL(redirectLocation); continue; } else { BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8")); String line = null; StringBuilder responseBuilder = new StringBuilder(); while ((line = reader.readLine()) != null) { responseBuilder.append(line); } reader.close(); String response = responseBuilder.toString(); System.out.println(response); break; } } } } ``` 这个示例代码实现了向一个URL发送POST请求,并在接收到重定向响应时自动跟随重定向并重新发送POST请求。注意,我们在第一次请求时将`setInstanceFollowRedirects`方法设置为`false`,以便我们能够手动处理重定向响应。当我们接收到重定向响应时,从响应头获取重定向URL,并将其存储在`redirectUrl`变量,然后继续重新发送POST请求,直到我们接收到最终响应为止。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值