原代码审计笔记-质量缺陷

2023-11-02 15:18

本文主要是介绍原代码审计笔记-质量缺陷,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原代码审计笔记-质量缺陷

目录

原代码审计笔记-质量缺陷

可能返回值、变量空指针引用:

密码管理(配置文件存密码):

System.out或System.err打印调试信息:

忽略返回值:

新建对象被忽略:

冗余的IF表达式-空代码:

不良的异常处理(在finally块中抛弃异常):

不良的异常处理(多个Catch块):

不良的异常处理(多个throws块):

不良的异常处理(空Catch块):

低效字符串比较:

遗留的调试代码-main方法:


可能返回值空指针引用、不良的异常处理(系统不会空指针异常):

问题示例:

Reader getReader(String configurationPath) throws IOException {File file = null;if (file.exists()) {return new BufferedReader(new FileReader(file));}return null;
}static void printPoint(Point p) {if (p == null) {System.err.println("p is null");}
}

 


原因分析:

如果尝试取消引用 null 值,将引发 NullPointerException。取消引用可以是函数调用、字段读取或写入,或阵列访问。当在某个路径上来自某个方法调用的值返回空值时,取消引用方法调用将导致报告此缺陷。

如果尝试取消引用 null 值,将引发 NullPointerException。取消引用可以是函数调用、字段读取或写入,或阵列访问。如果之前对某个本地变量进行了空值检查,并且经检查确认其值可能为空,则对其取消引用就会报缺陷。

解决方案:

建议:使用对象应对对象进行滤空判断,使用其中属性时应对其属性进行滤空处理,防止空指针异常。


 


密码管理(配置文件存密码):

问题示例:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close"p:driverClassName="oracle.jdbc.driver.OracleDriver"p:url="jdbc:oracle:thin:@127.0.0.1:1523:orcl"p:username="cyb"p:password="cyb@123" />

原因分析:

在配置文件中存储明文密码会使所有能够访问该文件的人都能访问那些用密码保护的资源。程序员有时候认为,他们不可能阻止应用程序被那些能够访问配置文件的攻击者入侵,但是这种想法会导致攻击者发动攻击变得更加容易。健全的 password management 方针从来不会允许以明文形式存储密码。

在配置文件中存储明文密码,可能会危及系统安全。

解决方案:

建议:在配置文件中存储明文密码,很容易会被攻击者利用导致造成系统敏感信息泄露。配置文件中的密码加密存储。


 


System.out或System.err打印调试信息:

问题示例:

public int internalCalculateSum(int x, int y) {if (x ﹤ 0 || y ﹤ 0) {System.out.println("XXX: got strange arguments!");}return x + y;
}

原因分析:

调试打印(比如 System.out.println() 和 System.err.println())也可能是多余的。当有调用 System.out 流的打印方法时,会显示警告。 在成熟的应用程序中,这种调用应限制在一个记录模块和功能控制台输出中;否则它将导致滥用诊断,这一问题应当进行修复。

 

解决方案:

建议:应该用日志模块调用来替换打印到 sysout 的调用。用日志调用或特定方法(比如 printRawToUser())的调用来替换打印到 stdout 的调用。


 


忽略返回值:

问题示例:

public String bad() {		String filePath = "C:" + File.separator + "test" ;File f = new File(filePath);f.mkdir(); return "ok";
}

原因分析:

Java 程序员常常会误解包含在许多 java.io 类中的 read() 及相关方法。在 Java 结果中,将大部分错误和异常事件都作为异常抛出。(这是 Java 相对于 C 语言等编程语言的优势:各种异常更加便于程序员考虑是哪里出现了问题。)但是,如果只有少量的数据可用,stream 和 reader 类并不认为这是异常的情况。这些类只是将这些少量的数据添加到返回值缓冲区,并且将返回值设置为读取的字节或字符数。所以,并不能保证返回的数据量一定等于请求的数据量。
这样,程序员就需要检查 read() 和其他 IO 方法的返回值,以确保接收到期望的数据量。

 

解决方案:

建议:忽略方法的返回值会导致程序无法发现意外状况和情况。


 


新建对象被忽略:

问题示例:

public void runMyProcessing() {Runnable myRunnable = new Runnable() {public void run() {// do actual processing...}};new Thread(myRunnable); // ignored!
}

原因分析:

当调用构造函数方法,而该方法调用的结果被忽略时,将出现此警告。在某些情况下,这可能导致错误(例如,线程类,因为用户应在初始化后启动线程)。 对方法行为的误解将导致应用程序逻辑中存在缺陷。也是JVM存储资源的浪费。

 

解决方案:

建议:应该存储方法所返回的值并加以运用。


 


冗余的IF表达式-空代码:

问题示例:

        if (url == null) {
//            return DiaowenProperty.DEFAULT_HTTP_BASEURL_UPLOAD;}

原因分析:

当 if 语句仅含有空 then 分支时,给出警告。可能是未完成的代码。

程序员可能遗忘了这项检查,其原本想返回并在代码中添加一些内容,但却忘记了。什么也没做的 if 会影响性能,特别是涉及调用方法时。

 

解决方案:

建议:更改代码,使 if 包含非空分支或全部移除 if。


 


不良的异常处理(从finally块中返回):

问题示例:

public void bad(){	try{throw new IllegalArgumentException();}catch(IllegalArgumentException iae){log.info("preventing incidental issues");}finally{return; }}

原因分析:

覆盖try代码中的return返回值。finally 块中的返回指令会导致从 try 块中抛出的异常丢失。

 

解决方案:

建议:将返回指令移到  finally 块之外。如果必须要  finally 块返回一个值,可以简单地将该返回值赋给一个本地变量,然后在  finally 块执行完毕后返回该变量。  


 


不良的异常处理(在finally块中抛弃异常):

问题示例:

        if (url == null) {
//            return DiaowenProperty.DEFAULT_HTTP_BASEURL_UPLOAD;}

原因分析:

在 Java 中, finally 块通常在其相应的 try-catch 块之后执行,该块通常用于自由分配的资源,例如文件句柄或数据库指针。由于破坏了正常的程序执行,在 finally 块中抛出异常会绕过关键的清除代码。
使用 finally 块中的 throw 语句会通过 try-catch-finally 破坏逻辑进度。

 

解决方案:

建议:请勿从  finally 块中主动或被动抛出异常。如果您必须重新抛出异常,请在  catch 块中执行该操作,这样不会影响到  finally 块的正常执行。



不良的异常处理(多个Catch块):

问题示例:

catch (Exception e) {e.printStackTrace();
}catch(Exception e){ log.info("Exception");
}

原因分析:

多个 catch 块看上去既难看又繁琐,但使用一个“简约”的 catch 块捕获高级别的异常类(如 Exception),可能会混淆那些需要特殊处理的异常,或是捕获了不应在程序中这一点捕获的异常。本质上,捕获范围过大的异常与“Java 分类定义异常”这一目的是相违背的。随着程序的增加而抛出新异常时,这种做法会十分危险。而新发生的异常类型也不会被注意到。

catch 块可以处理的异常种类很多,但往往会由于过多的考虑不应该在此位置处理的各种问题或故障而困扰不已。

 

解决方案:

建议:对自己当前捕获的异常要定位精准,处理得当。不要捕获范围过大的异常类,比如  Exception、Throwable、 Error 或 ,除非是级别非常高的程序或线程。


 


不良的异常处理(多个throws块):

问题示例:

public ModelAndView answerSurveyEdit(HttpServletRequest request,String answerId) throws Exception {
}

原因分析:

声明一种可以抛出 Exception 或 Throwable 异常的方法,从而使调用者很难处理和修复发生的错误。Java 异常机制的设置是:调用者可以方便地预计有可能发生的各种错误,并为每种异常情况编写处理代码。同时声明:一个方法抛出一个过于笼统的异常违反该系统。

该方法抛出了一个过于笼统异常,从而使调用者很难处理和修复发生的错误。

 

解决方案:

建议:不要声明抛出  Exception 或  Throwable 异常的方法。
 如果方法抛出的异常无法恢复,或者通常不能被调用者捕获,
 那么可以考虑抛出未检查的异常,而不是已检查的异常。
 这可以通过实现一个继承自  RuntimeException 或 Error 的类来代替  Exception,
 或者还可以在方法中加入 try/catch 块将已检查的异常转换为未检查异常。 


 


不良的异常处理(空Catch块):

问题示例:

public ModelAndView answerSurveyEdit(HttpServletRequest request,String answerId) throws Exception {
}

原因分析:

几乎每一个对软件系统的严重攻击都是从违反程序员的假设开始的。攻击后,程序员的假设看起来既脆弱又拙劣,但攻击前,许多程序员会在午休时间为自己的种种假设做很好的辩护。
在代码中,很容易发现两个令人怀疑的假设:“一是这个方法调用不可能出错;二是即使出错了,也不会对系统造成什么重要影响。”因此当程序员忽略异常时,这其实就表明了他们是基于上述假设进行的操作。

 

解决方案:

建议:应在catch模块中对异常处理,否则程序出现异常将很难定位异常所在。 


 


低效字符串比较:

问题示例:

if ("".equals(path) || path == null)continue;

原因分析:

不需要调用 equals() 将字符串与空字符串进行比较。s.length() 的速度快两倍。以下表达式:s.equals("") 或 "".equals(s) 可由 (s.length() == 0) 和 (s != null && s.length() == 0) 轻松替代。性能测量值(使用 Java 2 Runtime Environment、Standard Edition,内部版本 1.4.1_02-b06 完成)显示,含“equals”的代码以 147 个时间单位执行,而含“length”的相同代码以 71 个时间单位执行。

 

解决方案:

建议:

if ( null == path || path.length)
       continue; 


 

 


遗留的调试代码-main方法:

问题示例:

public static void main(String[] args) {System.out.println(randomWord(5, 12));;System.out.println(randomStr(5,12));;for (int i = 0; i < 1000; i++) {chineseName.getName();String names=chineseName.getNames();String pids=chineseName.getPid();System.out.println(names+":"+pids);System.out.println(randomNum(2,4));}

原因分析:

当在 Web 应用程序、J2EE 应用程序以及小型应用程序中检测到主方法时,将发生该错误。

在 Web 应用程序后面留下 main() 方法使得很容易通过后门来访问应用程序。Web 应用程序中的安全性设计趋向于不考虑主方法访问,因此这存在风险。

 

解决方案:

建议:在产品代码中移除所有非项目入口的main方法。


 

这篇关于原代码审计笔记-质量缺陷的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/331499

相关文章

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

论文阅读笔记: Segment Anything

文章目录 Segment Anything摘要引言任务模型数据引擎数据集负责任的人工智能 Segment Anything Model图像编码器提示编码器mask解码器解决歧义损失和训练 Segment Anything 论文地址: https://arxiv.org/abs/2304.02643 代码地址:https://github.com/facebookresear

数学建模笔记—— 非线性规划

数学建模笔记—— 非线性规划 非线性规划1. 模型原理1.1 非线性规划的标准型1.2 非线性规划求解的Matlab函数 2. 典型例题3. matlab代码求解3.1 例1 一个简单示例3.2 例2 选址问题1. 第一问 线性规划2. 第二问 非线性规划 非线性规划 非线性规划是一种求解目标函数或约束条件中有一个或几个非线性函数的最优化问题的方法。运筹学的一个重要分支。2

【C++学习笔记 20】C++中的智能指针

智能指针的功能 在上一篇笔记提到了在栈和堆上创建变量的区别,使用new关键字创建变量时,需要搭配delete关键字销毁变量。而智能指针的作用就是调用new分配内存时,不必自己去调用delete,甚至不用调用new。 智能指针实际上就是对原始指针的包装。 unique_ptr 最简单的智能指针,是一种作用域指针,意思是当指针超出该作用域时,会自动调用delete。它名为unique的原因是这个

查看提交历史 —— Git 学习笔记 11

查看提交历史 查看提交历史 不带任何选项的git log-p选项--stat 选项--pretty=oneline选项--pretty=format选项git log常用选项列表参考资料 在提交了若干更新,又或者克隆了某个项目之后,你也许想回顾下提交历史。 完成这个任务最简单而又有效的 工具是 git log 命令。 接下来的例子会用一个用于演示的 simplegit

记录每次更新到仓库 —— Git 学习笔记 10

记录每次更新到仓库 文章目录 文件的状态三个区域检查当前文件状态跟踪新文件取消跟踪(un-tracking)文件重新跟踪(re-tracking)文件暂存已修改文件忽略某些文件查看已暂存和未暂存的修改提交更新跳过暂存区删除文件移动文件参考资料 咱们接着很多天以前的 取得Git仓库 这篇文章继续说。 文件的状态 不管是通过哪种方法,现在我们已经有了一个仓库,并从这个仓

忽略某些文件 —— Git 学习笔记 05

忽略某些文件 忽略某些文件 通过.gitignore文件其他规则源如何选择规则源参考资料 对于某些文件,我们不希望把它们纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。通常它们都是些自动生成的文件,比如日志文件、编译过程中创建的临时文件等。 通过.gitignore文件 假设我们要忽略 lib.a 文件,那我们可以在 lib.a 所在目录下创建一个名为 .gi

取得 Git 仓库 —— Git 学习笔记 04

取得 Git 仓库 —— Git 学习笔记 04 我认为, Git 的学习分为两大块:一是工作区、索引、本地版本库之间的交互;二是本地版本库和远程版本库之间的交互。第一块是基础,第二块是难点。 下面,我们就围绕着第一部分内容来学习,先不考虑远程仓库,只考虑本地仓库。 怎样取得项目的 Git 仓库? 有两种取得 Git 项目仓库的方法。第一种是在本地创建一个新的仓库,第二种是把其他地方的某个

Git 的特点—— Git 学习笔记 02

文章目录 Git 简史Git 的特点直接记录快照,而非差异比较近乎所有操作都是本地执行保证完整性一般只添加数据 参考资料 Git 简史 众所周知,Linux 内核开源项目有着为数众多的参与者。这么多人在世界各地为 Linux 编写代码,那Linux 的代码是如何管理的呢?事实是在 2002 年以前,世界各地的开发者把源代码通过 diff 的方式发给 Linus,然后由 Linus