总结常见漏洞的代码审计方法

前言

这篇文章主要是总结一下在安全工作中常见漏洞的代码审计方法,以及修复方案,希望能对初学代码审计小伙伴们有所帮助,笔芯♥️

代码审计的思路

通常做代码审计都是检查敏感函数的参数,然后回溯变量,判断变量是否可控并且没有经过严格的过滤,这是一个逆向追踪的过程。而代码审计并非这一种手段,还可以先找出哪些文件在接收外部传入的参数,然后跟踪变量的传递过程,观察是否有变量传入到高危函数里面,或者传递的过程中是否有代码逻辑漏洞,这是一种正向追踪的方式,这样的挖掘方式比逆向追踪挖掘得更全。还有一种方式是直接挖掘功能点漏洞,根据自身的经验判断该类应用通常在哪些功能中会出现漏洞,直接全篇阅读该功能代码。

常见漏洞的代码审计

1. HTTP响应头截断

漏洞描述

HTTP响应截断是由于应用程序未对用户提交的数据进行严格过滤,当用户恶意提交包含 CR(回车,即URL编码%0d或\r)和 LF(换行符,即URL编码%0a或\n)的HTTP请求,服务器可能会创建两个 HTTP 响应,攻击者可以控制第二个响应并加载攻击。 攻击者可控制响应的内容构造XSS攻击,其中响应中包含恶意的JavaScript或其它代码在用户的浏览器中执行,也有可能让用户重定向到攻击者控制的Web内容或在用户的主机上执行恶意操作。

审计方法

检查对响应头字段是否进行安全处理。

如果未对响应头进行任何安全处理,则为确认:

//未对响应头做任何安全处理,审计时为确认
String data;
if (data != null){
	response.addHeader("Location", "/author.jsp?lang=" + data);
}

再举一例:

//同样的未对响应头做任何安全处理,审计时为确认
String author = request.getParameter(AUTHOR_PARAMETER);
// ...
Cookie cookie = new Cookie("author", author);
response.addCookie(cookie);

如果对响应头做了响应的安全处理,则为误报:

//使用Refenence类对环境变量值进行编码,剔除特殊字符,为误报
if (data != null){
	String decode = Reference.decode(data);
	response.addHeader("Location", "/author.jsp?lang=" + decode);
}

修复方案:

1、对用户的输入进行合理验证,对特殊字符(如<、>、’、”等)等进行编码。

2、创建一份安全字符白名单,只接受完全由这些受认可的字符组成的输入出现在 HTTP 响应头文件中。 3、使用源代码静态分析工具,进行自动化的检测,可以有效的发现源代码中的 HTTP 响应截断问题。

2. 硬编码问题

漏洞描述

硬编码问题,是指将敏感数据(包括口令和加密密钥,部分账号的密码以及其他敏感信息等)硬编码在程序中。

审计步骤

1、看扫描出的硬编码是否为常规单词(或通读代码查看是否有硬编码敏感文件)

2、如果是常规单词,则为误报,如:

//fipAddress为硬编码
public class IPaddress
{
private String ipAddress = "172.16.254.1";
public static void main(String[] args)
{
//...
}
}

可以使用 javap -c IPaddress 命令来反编译 class 来发现其中硬编码的服务器 IP 地址,此处反

编译器的输出信息可以直接透漏服务器的明文 IP 地址为172.16.254.1

再举一例:

//SECRET_PASSWORD为硬编码
private String SECRET_PASSWORD = "No fear in my heart!"; 
Properties props = new Properties(); 
props.put(Context.SECURITY_CREDENTIALS, "password");

3、如果是随机字符串,则为确认或待确认,如:

//1546272000000为硬编码
byte[] sr = hBaseClient.buildRowKey(devId, "1546272000000");

再举一例:

//qafgshw1900wxxxx为硬编码
private String accessKeyId = "qafgshw1900wxxxx";

4、追踪key值,如果key为硬编码则为确认,如:

//key值为硬编码
byte[] key = {1, 2, 3, 4, 5, 6, 7, 8};
SecretKeySpec spec = new SecretKeySpec(key, "AES");
Cipher aes = Cipher.getInstance("AES");
aes.init(Cipher.ENCRYPT_MODE, spec);
return aesCipher.doFinal(secretData);

追踪key值,如果追踪不到或者为安全形式,则为误报,如

//无法再继续追踪key值,为误报
public static byte[] encryptByPrivateKey(byte[] data, String key) throws Exception {
    //key为密钥
    byte[] keyBytes = decryptBASE64(key);
    PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
    Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
    cipher.init(Cipher.ENCRYPT_MODE, privateKey);
    return cipher.doFinal(data);
}

再来一栗:

//存储密钥。KeyStore.getInstance("PKCS12")为密钥库,为误报
try{
    KeyStore keyStore = KeyStore.getInstance("PKCS12");
    keyStore.load(null, null);

    KeyGenerator keyGen = KeyGenerator.getInstance("AES");
    keyGen.init(128);
    Key key = keyGen.generateKey();
    keyStore.setKeyEntry("secret", key, "password".toCharArray(), null);

    keyStore.store(new FileOutputStream("output.p12"), "password".toCharArray());
} catch (Exception ex){
    ex.printStackTrace();
}

修复方案

推荐使用配置文件或者通过配置中心来下发这些敏感配置,密码和密钥应存储在单独的加密配置文件或密钥库中。

3. SQL注入

漏洞描述

注入攻击的本质,是程序把用户输入的数据当做代码执行。这里有两个关键条件:

第一是用户能够控制输入;

第二是用户输入的数据被拼接到要执行的代码中从而被执行。

sql 注入漏洞则是程序将用户输入数据拼接到了 sql 语句中,从而攻击者即可构造、改变 sql 语义从而进行攻击。

漏洞举例

(1) 直接通过拼接 sql

@RequestMapping("/SqlInjection/{id}")
public ModelAndView SqlInjectTest(@PathVariable String id){
String mysqldriver = "com.mysql.jdbc.Driver";
String mysqlurl = 
"jdbc:mysql://127.0.0.1:3306/test?user=root&password=123456&useUnicode=true&c
haracterEncoding=utf8&autoReconnect=true";#直接通过拼接 sql
String sql = "select * from user where id=" + id;
ModelAndView mav = new ModelAndView("test2"); 
try{
Class.forName(mysqldriver);
Connection conn = DriverManager.getConnection(mysqlurl);
PreparedStatement pstt = conn.prepareStatement(sql);
ResultSet rs = pstt.executeQuery();

再来一例:

//没有做任何其他安全处理措施
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from user where username = '" + username+"' and password='"+password+"'");

(2) 预编译使用有误

漏洞举例:

//只使用了占位符
@RequestMapping("/SqlInjection/{id}")
public ModelAndView SqlInjectTest(@PathVariable String id){
String mysqldriver = "com.mysql.jdbc.Driver";
String mysqlurl = 
"jdbc:mysql://127.0.0.1:3306/test?user=root&password=123456&useUnicode=true&c
haracterEncoding=utf8&autoReconnect=true";
String sql = "select * from user where id= ?";
ModelAndView mav = new ModelAndView("test2"); 
try{
Class.forName(mysqldriver);
Connection conn = DriverManager.getConnection(mysqlurl);
PreparedStatement pstt = conn.prepareStatement(sql);
//pstt.setObject(1, id); //一般使用有误的是没有用这一句,编码者以为在上面的sql语句中直
接使用占位符就可以了。
ResultSet rs = pstt.executeQuery();

审计步骤:查看预编译的完整性,关键函数定位 setObject()、setInt()、setString()、setSQLXML()关联上下文搜索 set* 开头的函数。

(3) %和_(oracle 中模糊查询)问题

@RequestMapping("/SqlInjection/{id}")
public ModelAndView SqlInjectTest(@PathVariable String id){
String mysqldriver = "com.mysql.jdbc.Driver";
String mysqlurl = 
"jdbc:mysql://127.0.0.1:3306/test?user=root&password=123456&useUnicode=true&c
haracterEncoding=utf8&autoReconnect=true";
String sql = "select * from user where id= ?";
ModelAndView mav = new ModelAndView("test2"); 
try{
Class.forName(mysqldriver);
Connection conn = DriverManager.getConnection(mysqlurl);
PreparedStatement pstt = conn.prepareStatement(sql);
pstt.setObject(1, id); //使用预编译
ResultSet rs = pstt.executeQuery();

审计步骤:定位相关 sql 语句上下文,查看是否有显式过滤机制。

修复方案:上面的代码片段即使这样依然存在 sql 注入,原因是没有手动过滤%。预编译是不能处理这个符号的,以需要手动过滤,否则会造成慢查询,造成 dos。

(4) order by 问题

String sql = “Select * from news where title =?”+ “order by ‘” + time + 
“’asc”

审计步骤:定位相关 sql 语句上下文,查看是否有显式过滤机制。

修复方案:类似上面的这种 sql 语句 order by 后面是不能用预编译处理的只能通过拼接处理,所以需要手动过滤。

(5) 有关$符号的情况

#{}:相当于jdbc中的preparedstatement,传入的字符串,需要赋值后使用,可以有效防止sql注入

${}:是输出变量的值,传入的变量,直接在sql中执行,无法防止sql注入 简单的说就是#{}传过来的参数带单引号’',而${}传过来的参数不带单引号。

但是orderby是动态SQL,只能用${},用#{}会多个’ '导致sql语句失效。此外还有一个like 语句后也需要用${}。

//需要转义的字符串仍使用$
delete from ${tableName}

修复方案:对于可以使用#{}的情况,直接使用#{}即可解决问题对于不能使用#{}的情况(如orderby),需要增加额外的过滤逻辑,以此判断输入内容是否正常,如字段类型、字段长度等

4. maven不安全模块

漏洞描述

Maven,是一个Java开发比较常用的项目管理工具,可以对Java项目进行构建、依赖管理。当它配置一个不安全的模块时,即存在安全风险。

审计方法

查看配置的版本是否属于安全版本区间。 如果是,则确认:

//3.9版本是存在漏洞的版本。安全版本是3.11以上
<dependency>
    <groupId>com.hazelcast</groupId>
    <artifactId>hazelcast-client</artifactId>
    <version>3.9</version>
</dependency>

修复方案

配置为安全版本即可(同时应注意解决兼容性问题)

5. 服务端请求伪造(SSRF)

漏洞描述

SSRF是攻击者让服务端发起指定的请求,攻击的目标一般是从外网无法访问的内网系统。SSRF形成的原因大都是由于代码中提供了从其他服务器应用获取数据的功能但没有对目标地址做过滤与限制。比如从指定URL链接获取图片、下载等。一般利用http协议来探测端口,利用file协议读取任意文件。

利用场景

SSRF漏洞一般位于远程图片加载与下载、图片或文章收藏功能、URL分享、通过URL在线翻译、转码等功能点处。

关键词/接口/类包

// Java
HttpURLConnection.getInputStream
URLConnection.getInputStream
Request.Get.execute
Request.Post.execute
URL.openStream
ImageIO.read
OkHttpClient.newCall.execute
HttpClients.execute
HttpClient.execute

审计方法

1、内网系统的SSRF直接为误报(内网系统之间互调互传)

2、检查请求的URL是否为外部可控,即由外部传入

3、检查请求的返回,是否对请求的返回数据做了安全处理

漏洞示例

//请求URL为外部可控,返回数据直接展示
String url = request.getParameter("picurl");
StringBuffer response = new StringBuffer();

URL pic = new URL(url);
HttpURLConnection con = (HttpURLConnection) pic.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", "Mozilla/5.0");
//发起请求,触发漏洞
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
	response.append(inputLine);
  }
in.close();
modelMap.put("resp",response.toString());
return "getimg.htm";

再举一例:

//HttpClients函数的SSRF漏洞代码,审计时为确认:
String url = request.getParameter("url");
CloseableHttpClient client = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url);
HttpResponse httpResponse = client.execute(httpGet); //发起请求

修复方案

  1. 使用白名单校验HTTP请求url地址
  2. 避免请求url外部可控
  3. 避免将请求响应及错误信息返回给用户
  4. 禁用不需要的协议及限制请求端口,仅仅允许http和https请求等

6. 路径遍历

目录/路径遍历、任意文件上传/下载

漏洞描述

在下载文件相关的代码中,若不对HTTP请求中的待下载文件名进行检查,则有可能产生任意文件下载漏洞。攻击者可以指定文件名、文件路径等文件操作的参数,越权访问正常情况下无法到达的系统资源。

审计方法

  1. 判断是否存在上传下载行为
  2. 判断路径是否可被外部控制,如果外部可控则向下
  3. 判断是否对文件路径做了安全措施,如果做了安全措施为误报

漏洞示例

没有对路径做任何安全处理,如:

//没有对路径做任何安全处理措施
path = "config/"+path;
File file = new File(path);
System.out.println(path);
response.setHeader("Content-Disposition", "attachment;filename=\\""
        + new String(path.getBytes(), "ISO8859-1") + "\\"");
response.setContentLength((int) file.length());
byte[] buffer = new byte[4096];// 缓冲区
BufferedOutputStream output = null;
BufferedInputStream input = null;

再举一例:

//对下载的文件未做安全处理
public Response getImage(@javax.ws.rs.PathParam("image") String image) {
    File file = new File("resources/images/", image);
    if (!file.exists()) {
        return Response.status(Status.NOT_FOUND).build();
    }
    return Response.ok().entity(new FileInputStream(file)).build();
}

修复方案

  1. 使用getCanonicalPath()、getAbsolutePath()等方法获取规范路径
  2. 对文件操作参数进行输入验证,过滤特殊字符
  3. 通过文件头判断来限制文件类型,而不是通过文件后缀来判断
  4. 服务器安全配置策略文件。将所能读取的文件限定在特定的目录下

7. 命令注入

漏洞描述

命令注入是指通过提交恶意构造的参数破坏命令语句结构,当对用户输入的命令没有进行限制或者过滤不严导致用户可以执行任意命令时,就会造成命令执行漏洞。通常表现为攻击者能够篡改程序执行的命令或命令执行的环境,从而直接或间接的控制了所执行的命令。

常见的命令执行方法

// Java
Runtime.exec
ProcessBuilder.start
GroovyShell.evaluate

审计方法

  1. 检查是否是系统命令,如果不是系统命令而是常规字符串拼接,则为误报
  2. 检查所执行的命令是否为外部可控制,如果外部不可控(例如命令拼接参数不为外部控制)则为误报
  3. 外部可控制的情况下检查命令的拼接参数是否做了安全措施,如果未做安全措施即为确认

漏洞示例

(1) 没有对外部传入的命令拼接参数做任何安全处理措施,如:

//没有对外部传入的命令参数command做任何安全处理
System.out.println("Command: ping"+ command);
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("cmd.exe /C ping "+command);
int res = proc.waitFor();
if(res !=0){
    System.out.println("process error: "+ res);
}
InputStream in = (res == 0)? proc.getInputStream() : proc.getErrorStream();
BufferedReader reader=new BufferedReader(new InputStreamReader(in));
buffer=new StringBuffer();
String line;
while((line = reader.readLine())!=null){
    buffer.append(line+"\\n");
}

再举一例:

//同样没有对外部传入的命令拼接参数input做任何安全处理
Runtime r = Runtime.getRuntime();
r.exec("/bin/sh -c some_tool" + input);

(2) 对外部传入的命令拼接参数做安全限制,如:

//对外部传入的命令拼接参数做了限制

//正则限定为合法IP地址
if (!Pattern.matches("([1-9]|[1-9]\\\\d|1\\\\d{2}|2[0-4]\\\\d|25[0-5])(\\\\.(\\\\d|[1-9]\\\\d|1\\\\d{2}|2[0-4]\\\\d|25[0-5])){3}", command)){
	//如果不是IP则匹配不成功,则为F,!F则为T,T则执行此代码块
    result.put("message", "Error!");
    return DataUtil.toJson(result);
}
System.out.println("Command: ping"+ command);
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("cmd.exe /C ping "+command);
int res = proc.waitFor();
if(res !=0){
    System.out.println("process error: "+ res);
}
InputStream in = (res == 0)? proc.getInputStream() : proc.getErrorStream();
BufferedReader reader=new BufferedReader(new InputStreamReader(in));
buffer=new StringBuffer();
String line;
while((line = reader.readLine())!=null){
    buffer.append(line+"\\n");
}

修复方案

  1. 构建白名单,只允许其中的字符出现在输入中
  2. 应有应用程序来控制命令,并使用绝对路径来执行命令
  3. 严格的权限限制,程序执行外部命令使用最小权限原则
  4. 严格的参数校验

网络安全学习资源分享:

给大家分享一份全套的网络安全学习资料,给那些想学习 网络安全的小伙伴们一点帮助!

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

因篇幅有限,仅展示部分资料,朋友们如果有需要全套《网络安全入门+进阶学习资源包》,需要点击下方链接即可前往获取 

读者福利 | CSDN大礼包:《网络安全入门&进阶学习资源包》免费分享(安全链接,放心点击)

同时每个成长路线对应的板块都有配套的视频提供: 

 大厂面试题

视频配套资料&国内外网安书籍、文档

当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料

所有资料共282G,朋友们如果有需要全套《网络安全入门+进阶学习资源包》,可以扫描下方二维码或链接免费领取~ 

读者福利 | CSDN大礼包:《网络安全入门&进阶学习资源包》免费分享(安全链接,放心点击) 

特别声明:

此教程为纯技术分享!本教程的目的决不是为那些怀有不良动机的人提供及技术支持!也不承担因为技术被滥用所产生的连带责任!本教程的目的在于最大限度地唤醒大家对网络安全的重视,并采取相应的安全措施,从而减少由网络安全而带来的经济损失。

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

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

相关文章

【Linux】权限的理解之权限掩码(umask)

目录 前言 一、利用八进制数值表示文件或目录的权限属性 二、系统默认的权限掩码和权限掩码的作用原理 三、分析权限掩码改变文件或目录的权限属性 前言 权限掩码是由4个数字组合而成的&#xff0c;默认的第一位数字是0&#xff1b;后三位数字分别由八进制位数字组成。权限…

贪心算法[1]

首先用最最最经典的部分背包问题来引入贪心的思想。 由题意可知我们需要挑选出价值最大的物品放入背包&#xff0c;价值即单位价值。 我们需要计算出每一堆金币中单位价值。金币的属性涉及两个特征&#xff0c;重量和价值。 所以我们使用结构体。 上代码。 #include <i…

安全术语 | 软件包purl详解:跨工具、数据库、API和语言之间可靠地识别和定位软件包

软件包URL&#xff08;purl&#xff0c;Package URL&#xff09;是一个URL字符串&#xff0c;用于在编程语言、包管理器、包约定、工具、API和数据库中以最通用和统一的方式识别和定位软件包。purl是对现有方法进行标准化的尝试&#xff0c;以可靠地识别和定位软件包。 有望取代…

MagicLens:新一代图像搜索技术和产品形态

MagicLens&#xff1a;Self-Supervised Image Retrieval with Open-Ended Instructions MagicLens: 自监督图像检索与开放式指令 作者&#xff1a;Kai Zhang&#xff0c; Yi Luan&#xff0c; Hexiang Hu&#xff0c; Kenton Lee&#xff0c; Siyuan Qiao&#xff0c; Wenhu …

vue组件-----路由系统

能够说出单页面概念和优缺点能够掌握vue-router路由系统能够掌握声明式导航和编程式导航能够掌握路由嵌套和守卫 一.Vue路由简介和基础使用 1.生活中的路由 目标&#xff1a;设备和ip的映射关系 2.nodejs路由 目标&#xff1a;接口和服务的映射关系 3.前端路由 目标&#…

短视频内容创意方法有哪些?成都科成博通文化传媒公司

短视频内容创意方法有哪些&#xff1f; 随着移动互联网的迅猛发展&#xff0c;短视频平台已成为人们日常生活中不可或缺的一部分。短视频以其短平快的特点&#xff0c;迅速吸引了大量用户。然而&#xff0c;面对海量的短视频内容&#xff0c;如何让自己的作品脱颖而出&#xf…

【Linux】Linux的权限_2 + Linux环境基础开发工具_1

文章目录 三、权限3. Linux权限管理修改文件的拥有者和所属组 4. 文件的类型5. 权限掩码 四、Linux环境基础开发工具1. yumyum 工具的使用 未完待续 三、权限 3. Linux权限管理 修改文件的拥有者和所属组 在上一节我们讲到如何更改文件的访问权限&#xff0c;那我们需要更改…

二十九、openlayers官网示例DeclutterGroup解析——避免矢量图层的文字重叠

官网demo地址&#xff1a; Declutter Group 这篇说的是如何设置矢量图层上多数据点文字不重叠。 主要是属性declutter &#xff0c;用于处理矢量图层上重叠的标注和符号&#xff0c;为true时启用去重叠功能。所有矢量特征的标注和符号都会被处理以避免重叠。false则与之相反。…

提升(或降低)插入的内容的位置:\raisebox

\raisebox 是 LaTeX 中的一个命令&#xff0c;用于提升&#xff08;或降低&#xff09;插入的内容&#xff08;如文本、图像等&#xff09;的位置。该命令可以用于调整垂直位置&#xff0c;使内容相对于周围内容上下移动。 语法如下&#xff1a; \raisebox{<distance>}…

宝藏网站推荐-封面图片生成器

封面图片生成器&#xff1a;封面图生成器 | 太空编程 (spacexcode.com)[https://spacexcode.com/coverview] 由来 最近爱上了写文案&#xff0c;在网上冲浪的时候发现一个宝藏网站。Spacecode&#xff0c;一个大神维护的个人网站&#xff0c;含有前端知识库、个人博客及他做…

轻松拿捏C语言——自定义类型之【结构体】

&#x1f970;欢迎关注 轻松拿捏C语言系列&#xff0c;来和 小哇 一起进步&#xff01;✊ &#x1f389;创作不易&#xff0c;请多多支持&#x1f389; &#x1f308;感谢大家的阅读、点赞、收藏和关注&#x1f495; &#x1f339;如有问题&#xff0c;欢迎指正 1. 结构体类型的…

攻击同学网络,让同学断网

技术介绍&#xff1a;ARP欺骗 ARP欺骗&#xff08;ARP spoofing&#xff09;是一种网络攻击技术&#xff0c;它通过伪造ARP&#xff08;地址解析协议&#xff09;响应包来欺骗目标设备&#xff0c;使其将网络流量发送到攻击者指定的位置。具体操作步骤如下&#xff1a; 攻击者…

C# 中 async 与 await 关键字详解

async 和 await 关键字的作用是使方法能够异步执行并等待异步操作的完成。&#xff08;最重要的一点是记住 “异步执行”与“等待异步操作完成”&#xff0c;不是等待主线程操作完成&#xff09; async 修饰符可将 方法、lambda 表达式或匿名方法指定为异步。 async 关键字用于…

MySQL:数据库基础操作

一、MySQL的机制 相信翻到这篇文章的你&#xff0c;应该也是来怀着大大的好奇&#xff0c;来学习MySQL这门语言&#xff0c;那么&#xff0c;现在&#xff0c;就让我和大家一起来学习这门语言吧&#xff01; 这此之前&#xff0c;我们先要了解一个事实&#xff0c;MySQL其实是划…

微服务架构-分支微服务设计模式

微服务架构-分支微服务设计模式 这种模式是聚合器模式的扩展&#xff0c;允许同时调用两个微服务链 分支微服务设计模式是一种用于构建大型系统的微服务架构模式&#xff0c;其核心思想是 将复杂的业务逻辑拆解为多个小的、相互独立的子系统&#xff0c;每个子系统由一个或多…

【iOS】didReceiveMemoryWarning实例方法

iPhone下每个App可用的内存是被限制的&#xff0c;如果一个App使用的内存超过20M&#xff0c;则系统会向该App发送Memory Warning&#xff08;内存警告&#xff09;消息&#xff0c;收到此消息后&#xff0c;App必须正确处理&#xff0c;否则可能出错或出现内存泄漏。 目录 流程…

代码随想录算法训练营day14|二叉树的递归遍历、二叉树的迭代遍历、二叉树的统一迭代法

二叉树的递归遍历 首先需要明确的一点是&#xff0c;前序中序和后序在二叉树的递归遍历中的区别仅在于递归函数中操作的顺序&#xff0c;前序是在遍历一个节点的左右子树前进行操作&#xff0c;中序是在遍历一个节点的左子树后进行操作再遍历右子树&#xff0c;而后序是在遍历…

3D点云焊缝提取 平面交线 投影

文章目录 1. 效果2. 思路3. 源码 1. 效果 2. 思路 计算点云法向量&#xff1b;计算点云位姿Pose;翻转Pose中的Z轴方向&#xff0c;使其一致&#xff1b;通过Pose的Z轴对点云进行方向过滤&#xff1b;对点云聚类&#xff1b;根据目标点云的高度提取目标点云&#xff1b;提取两块…

云计算-Amazon S3

亚马逊S3&#xff08;Amazon S3&#xff09; 亚马逊S3是一种云对象存储设施。我们将使用的对象将是您在个人计算机上常用的文件。亚马逊S3产品旨在可扩展到实际无限数量的对象和无限大小的对象&#xff0c;但我们在本实验室的练习中只会使用少量对象。当存储许多对象时&#xf…

微服务架构下的‘黑带’安全大师:Spring Cloud Security全攻略!

深入探讨了微服务间的安全通信、安全策略设计以及面对经典安全问题的应对策略。无论你是微服务的新手还是资深开发者&#xff0c;都能在本文中找到提升安全功力的秘籍。让我们一起成为微服务架构下的‘黑带’安全大师&#xff01; 文章目录 1. 引言微服务安全挑战与重要性Sprin…