Fortify代码扫描解决方案

更新时间:2023-07-12 22:24:39 阅读: 评论:0

Fortify代码扫描解决⽅案
Fortify扫描漏洞解决⽅案:
Log Forging漏洞:
1.数据从⼀个不可信赖的数据源进⼊应⽤程序。 在这种情况下,数据经由getParameter()到后台。
2. 数据写⼊到应⽤程序或系统⽇志⽂件中。 这种情况下,数据通过info() 记录下来。为了便于以后的审阅、统计数据收集或调试,应⽤程序通常使⽤⽇志⽂件来储存事件或事务的历史记录。根据应⽤程序⾃⾝的特性,审阅⽇志⽂件可在必要时⼿动执⾏,也可以⾃动执⾏,即利⽤⼯具⾃动挑选⽇志中的重要事件或带有某种倾向性的信息。如果攻击者可以向随后会被逐字记录到⽇志⽂件的应⽤程序提供数据,则可能会妨碍或误导⽇志⽂件的解读。最理想的情况是,攻击者可能通过向应⽤程序提供包括适当字符的输⼊,在⽇志⽂件中插⼊错误的条⽬。如果⽇志⽂件是⾃动处理的,那么攻击者可以破坏⽂件格式或注⼊意外的字符,从⽽使⽂件⽆法使⽤。更阴险的攻击可能会导致⽇志⽂件中的统计信息发⽣偏差。通过伪造或其他⽅式,受到破坏的⽇志⽂件可⽤于掩护攻击者的跟踪轨迹,甚⾄还可以牵连第三⽅来执⾏恶意⾏为。最糟糕的情况是,攻击者可能向⽇志⽂件注⼊代码或者其他命令,利⽤⽇志处理实⽤程序中的漏洞。
例 1: 下列 Web 应⽤程序代码会尝试从⼀个请求对象中读取整数值。如果数值未被解析为整数,输⼊就会被记录到⽇志中,附带⼀条提⽰相关情况的错误消息。
String val = Parameter("val");
try {
int value = Integer.parInt(val);
} catch (NumberFormatException nfe) {
log.info("Failed to par val = " + val);
}
如果⽤户为“val”提交字符串“twenty-one”,则⽇志中会记录以下条⽬:
INFO: Failed to par val=twenty-one
然⽽,如果攻击者提交字符串
“twenty-one%0a%0aINFO:+Ur+logged+out%3dbadguy”,
则⽇志中会记录以下条⽬:
INFO: Failed to par val=twenty-one
INFO: Ur logged out=badguy
显然,攻击者可以使⽤同样的机制插⼊任意⽇志条⽬。
有些⼈认为在移动世界中,典型的 Web 应⽤程序漏洞(如 Log Forging)是⽆意义的 -- 为什么⽤户要攻击⾃⼰?但是,谨记移动平台的本质是从各种来源下载并在相同设备上运⾏的应⽤程序。恶意软件在银⾏应⽤程序附近运⾏的可能性很⾼,它们会强制扩展移动应⽤程序的攻击⾯(包括跨进程通信)。
例 2:以下代码将例 1 改编为适⽤于 Android 平台。豆浆机能榨果汁吗
String val = Intent().getExtras().getString("val");
try {
int value = Integer.parInt();
}
catch (NumberFormatException nfe) {
Log.e(TAG, "Failed to par val = " + val);
}
使⽤间接⽅法防⽌ Log Forging 攻击:创建⼀组与不同事件⼀⼀对应的合法⽇志条⽬,这些条⽬必须记录在⽇志中,并且仅记录该组条⽬。要捕获动态内容(如⽤户注销系统),请务必使⽤由服务器控制的数值,⽽⾮由⽤户提供的数据。这就确保了⽇志条⽬中绝不会直接使⽤由⽤户提供的输⼊。
可以按以下⽅式将例 1 重写为与NumberFormatException 对应的预定义⽇志条⽬:
public static final String NFE = "Failed to par val. The input is required to be an integer value."
String val = Parameter("val"); try { int value = Integer.parInt(val); } catch (NumberFormatException nfe) { log.info(NFE); }
下⾯是 Android 的等同内容:
public static final String NFE = "Failed to par val. The input is required to be an integer value."
String val = Intent().getExtras().getString("val"); try { int value = Integer.parInt(); } catch (NumberFormatException nfe) { Log.e(TAG, NFE); }
画可爱的小女孩在某些情况下,这个⽅法有些不切实际,因为这样⼀组合法的⽇志条⽬实在太⼤或是太复杂了。这种情况下,开发者往往⼜会退⽽采⽤⿊名单⽅法。在输⼊之前,⿊名单会有选择地拒绝或避免潜在的危险字符。然⽽,不安全字符列表很快就会不完善或过时。更好的⽅法是创建⼀份⽩名单,允许其中的字符出现在⽇志条⽬中,并且只接受完全由这些经认可的字符组成的输⼊。在⼤多数 Log Forging 攻击中,最关键的字符是“\n”(换⾏符),该字符决不能出现在⽇志条⽬⽩名单中。
Tips:
1. 许多⽇志功能只是为了在开发和测试过程中调试程序⽽创建的。根据我们的经验,当⽣产的某⼀阶段,会随机或出于某⼀⽬的进⾏调试。不要仅仅因为程序员说“我没有计划在⽣产中启动调试功能”,就容忍 Log Forging 漏洞。
2. 许多现代 Web 框架都提供对⽤户输⼊执⾏验证的机制。其中包括 Struts 和 Spring MVC。为了突出显⽰未经验证的输⼊源,HPE Security Fortify 安全编码规则包会降低 HPE Security Fortify Static Cod
e Analyzer(HPE Security Fortify 静态代码分析器)报告的问题被利⽤的可能性,并在使⽤框架验证机制时提供相应的依据,以动态重新调整问题优先级。我们将这种功能称之为上下⽂敏感排序。为了进⼀步帮助 HPE Security Fortify ⽤户执⾏审计过程,HPE Security Fortify 软件安全研究团队提供了数据验证项⽬模板,该模板会根据应⽤于输⼊源的验证机制,将问题分组到多个⽂件夹中。
Null Dereference
1、当违反程序员的⼀个或多个假设时,通常会出现 null 指针异常。如果程序明确将对象设置为 null,但稍后却间接引⽤该对象,则将出现dereference-after-store 错误。此错误通常是因为程序员在声明变量时将变量初始化为 null。在这种情况下,在第 443 ⾏间接引⽤该变量时,变量有可能为 null,从⽽引起 null 指针异常。⼤部分空指针问题只会引起⼀般的软件可靠性问题,但如果攻击者能够故意触发空指针间接引⽤,攻击者就有可能利⽤引发的异常绕过安全逻辑,或致使应⽤程序泄漏调试信息,这些信息对于规划随后的攻击⼗分有⽤。
⽰例:在下列代码中,程序员将变量foo 明确设置为 null。稍后,程序员间接引⽤ foo,⽽未检查对象是否为 null 值。
Foo foo = null;...
foo.tBar(val);
}
在间接引⽤可能为 null 值的对象之前,请务必仔细检查。如有可能,在处理资源的代码周围的包装器中纳⼊ null 检查,确保在所有情况下均会执⾏ null 检查,并最⼤限度地减少出错的地⽅。
Unrelead Resource: Streams
程序可能⽆法成功释放某⼀项系统资源。这种情况下,尽管程序没有释放RuleUtils.java ⽂件第 91 ⾏所分配的资源,但执⾏这⼀操作程序路径依然存在。资源泄露⾄少有两种常见的原因:
-错误状况及其他异常情况。
-未明确程序的哪⼀部份负责释放资源。
⼤部分 Unrelead Resource 问题只会导致⼀般的软件可靠性问题,但如果攻击者能够故意触发资源泄漏,该攻击者就有可能通过耗尽资源池的⽅式发起 denial of rvice 攻击。
⽰例:下⾯的⽅法绝不会关闭它所打开的⽂件句柄。FileInputStream 中的 finalize() ⽅法最终会调⽤clo(),但是不能确定何时会调⽤finalize() ⽅法。在繁忙的环境中,这会导致 JVM ⽤尽它所有的⽂件句柄。
private void processFile(String fName) throws FileNotFoundException, IOException {
  FileInputStream fis = new FileInputStream(fName);
  int sz;
  byte[] byteArray = new byte[BLOCK_SIZE];
  while ((sz = ad(byteArray)) != -1) {
    processBytes(byteArray, sz);
  }
}
1. 请不要依赖 finalize() 回收资源。为了使对象的 finalize() ⽅法能被调⽤,垃圾收集器必须确认对象符合垃圾回收的条件。但是垃圾收集器只有在 JVM 内存过⼩时才会使⽤。因此,⽆法保证何时能够调⽤该对象的 finalize() ⽅法。垃圾收集器最终运⾏时,可能出现这样的情况,即在短时间内回收⼤量的资源,这种情况会导致“突发”性能,并降低总体系统通过量。随着系统负载的增加,这种影响会越来越明显。
最后,如果某⼀资源回收操作被挂起(例如该操作需要通过⽹络访问数据库),那么执⾏ finalize() ⽅法的线程也将被挂起。
2. 在 finally 代码段中释放资源。⽰例中的代码可按以下⽅式改写:
public void processFile(String fName) throws FileNotFoundException, IOException {
FileInputStream fis;
try {
fis = new FileInputStream(fName);
野菊杨万里int sz;
byte[] byteArray = new byte[BLOCK_SIZE];
while ((sz = ad(byteArray)) != -1) {
processBytes(byteArray, sz);
}
} finally {
if (fis != null) {
safeClo(fis);
}
}
}
public static void safeClo(FileInputStream fis) {
if (fis != null) {
try {
fis.clo();
} catch (IOException e) {
log(e);
}
}
}
以上⽅案使⽤了⼀个助⼿函数,⽤以记录在尝试关闭流时可能发⽣的异常。该助⼿函数⼤约会在需要关闭流时重新使⽤。
同样,processFile ⽅法不会将 fis 对象初始化为 null。⽽是进⾏检查,以确保调⽤ safeClo() 之前,fis 不是null。如果没有检
查 null,Java 编译器会报告 fis 可能没有进⾏初始化。编译器做出这⼀判断源于 Java 可以检测未初始化的变量。如果⽤⼀种更加复杂的⽅法将 fis 初始化为null,那么编译器就⽆法检测 fis 未经初始化便使⽤的情况。
Portability Flaw: File Separator
不同的操作系统使⽤不同的字符作为⽂件分隔符。例如,Microsoft Windows 系统使⽤“\”,⽽ UNIX 系统则使⽤“/”。应⽤程序需要在不同的平台上运⾏时,使⽤硬编码⽂件分隔符会导致应⽤程序逻辑执⾏错误,并有可能导致 denial of rvice。在这种情况下,在 FileUtil.java 中第 254⾏的 File() 调⽤中使⽤了硬编码⽂件分隔符。
例 1:以下代码使⽤硬编码⽂件分隔符来打开⽂件:
File file = new File(directoryName + "\\" + fileName);
为编写可移植代码,不应使⽤硬编码⽂件分隔符,⽽应使⽤语⾔库提供的独⽴于平台的 API。
例 2:下列代码执⾏与例 1 相同的功能,但使⽤独⽴于平台的 API 来指定⽂件分隔符:
File file = new File(directoryName + File.parator + fileName);
Portability Flaw: Locale Dependent Comparison
对可能与区域设置相关的数据进⾏⽐较时,应指定相应的区域设置。
⽰例 1:以下⽰例尝试执⾏验证,以确定⽤户输⼊是否包含 <script> 标签。
public String tagProcessor(String tag){
if (UpperCa().equals("SCRIPT")){
return null;
}
//does not contain SCRIPT tag, keep
}
关于上述代码的问题是:在使⽤不带区域设置的 java.UpperCa()时,其将使⽤默认的区域设置规则。使⽤⼟⽿其区域设
置 "title".toUpperCa()时将返回 "T\u0130TLE",其中 "\u0130" 是 "LATIN CAPITAL LETTER I WITH DOT ABOVE" 字符。这会导致⽣成意外结果,例如,在⽰例 1 中,会导致此验证⽆法捕获 "script" ⼀词,从⽽可能造成跨站脚本攻击漏洞。
为了防⽌出现此问题,请始终确保指定默认区域设置,或者指定可以接受这些字符(如 toUpperCa())并带有 API 的区域设置。
⽰例 2:以下⽰例通过⼿动⽅式将区域设置指定为 toUpperCa() 的参数。
import java.util.Locale;
public String tagProcessor(String tag){
if (UpperCa(Locale.ENGLISH).equals("SCRIPT")){
return null;
}
//does not contain SCRIPT tag, keep processing input
...}
英语到底怎么学⽰例 3:以下⽰例使⽤了函数java.lang.String.equalsIgnoreCa()API 以防⽌出现此问题。
public String tagProcessor(String tag){
if (tag.equalsIgnoreCa("SCRIPT")){谷口治郎
return null;
}
//does not contain SCRIPT tag, keep processing input
...
}
因为 equalsIgnoreCa() 会更改与LowerCa() 和UpperCa() 类似的内容,所以可以防⽌此问题。这涉及到使⽤来⾃ UnicodeData ⽂件(由 Unicode 联盟维护的 Unicode 字符数据库的⼀部分)的信息创建这两种字符串的临时标准格式。即使这可能会导致这些字符在被读取时以不可读的⽅式呈现出来,但却能够在独⽴于区域设置的情况下进⾏⽐较。
Tips:
1. 如果 SCA 识别到java.util.Locale.tDefault() 可在应⽤程序中的任意位置进⾏调⽤,其会假定已执⾏了相应的区域设置,并且这些问题也不会出现。
披甲龙龟Access Specifier Manipulation
AccessibleObject API 允许程序员绕过由 Java 访问说明符提供的 access control 检查。特别是它让程序员能够允许反映对象绕过 Java access control,并反过来更改私有字段或调⽤私有⽅法、⾏为,这些通常情况下都是不允许的。
在此情况下,您正在使⽤的危险⽅法是BaTestCa.java 的第 45 ⾏中的tAccessible()。
只能使⽤攻击者⽆法设置的参数,通过有权限的类更改访问说明符。所有出现的访问说明符都应仔细检查。
J2EE Bad Practices: Non-Serializable Object Stored in Session
⼀个 J2EE 应⽤程序可以利⽤多个 JVM,以提⾼应⽤程序的可靠性和性能。为了在最终⽤户中将多个 JVM 显⽰为单个的应⽤程序,J2EE 容器可以在多个 JVM 之间复制 HttpSession 对象,所以当⼀个 JVM 不可⽤时,另⼀个 JVM 可以在不中断应⽤程序流程的情况下接替步骤的执⾏。
为了使会话复制能够正常运⾏,作为应⽤程序属性存储在会话中的数值必须实现 Serializable 接⼝。
例 1:下⾯这个类把⾃⼰添加到会话中,但由于它不是可序列化的,因此该会话就再也不能被复制了。
public class DataGlob {
String globName;
String globValue;
public void addToSession(HttpSession ssion) {
ssion.tAttribute("glob", this);
}
}
很多情况下,要修复这⼀问题,最简单的⽅法是让这个违反规则的对象实现 Serializable 接⼝。
例 2:例 1 中的代码应该⽤以下⽅式重写:
public class DataGlob implements java.io.Serializable {
String globName;
String globValue;
public void addToSession(HttpSession ssion) {
ssion.tAttribute("glob", this);
收敛造句
}
}包子的制作方法
注意,对复杂的对象来说,存储在会话中的对象,其传递闭包必须是可序列化的。如果对象 A 引⽤对象 B,且对象 A 存储在会话中,那么 A 和 B 都必须实现 Serializable 接⼝。
虽然实现 Serializable 接⼝通常都很简单(因为该接⼝不要求类定义任何⽅法),但是某些类型的对象实现会引发⼀些相关问题。应密切注意引⽤外部资源⽂件的对象。例如,数据流和 JNI 都可能会引发⼀些相关问题。
例 3:使⽤类型检测调⽤可序列化对象。⽽不是使⽤:
public static void addToSession(HttpServletRequest req,String attrib, Object obj){
  HttpSession ss = Session(true);
ss.tAttribute(attrib, obj);
}
采⽤如下⽅法编写:
public static void addToSession(HttpServletRequest req,String attrib, Serializable r) {
  HttpSession ss = Session(true);
  ss.tAttribute(attrib, r);
}
Incure Randomness
在对安全性要求较⾼的环境中,使⽤⼀个能产⽣可预测数值的函数作为随机数据源,会产⽣ Incure Randomness 错误。在这种情况下,⽣成弱随机数的函数是 random(),它位于DataFormatUtils.java ⽂件的第 577⾏。电脑是⼀种具有确定性的机器,因此不可能产⽣真正的随机性。伪随机数⽣成器 (PRNG) 近似于随机算法,始于⼀个能计算后续数值的种⼦。PRNG 包括两种类型:统计学的 PRNG
和密码学的PRNG。统计学的 PRNG 可提供有⽤的统计资料,但其输出结果很容易预测,因此数据流容易复制。若安全性取决于⽣成数值的不可预测性,则此类型不适⽤。密码学的 PRNG 通过可产⽣较难预测的输出结果来应对这⼀问题。为了使加密数值更为安全,必须使攻击者根本⽆法、或极不可能将它与真实的随机数加以区分。通常情况下,如果并未声明 PRNG 算法带有加密保护,那么它有可能就是⼀个统计学的PRNG,不应在对安全性要求较⾼的环境中使⽤,其中随着它的使⽤可能会导致严重的漏洞(如易于猜测的密码、可预测的加密密钥、会话劫持攻击和 DNS 欺骗)。
⽰例:下⾯的代码可利⽤统计学的 PRNG 为购买产品后仍在有效期内的收据创建⼀个 URL。

本文发布于:2023-07-12 22:24:39,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/1093239.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:可能   程序   情况   问题   对象   资源   攻击者   代码
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图