部分Fortify代码扫描高风险解决方案

2023-05-16

部分Fortify代码扫描高风险解决方案

一、Category: Access Control: Database

问题描述:

​ Database access control 错误在以下情况下发生:
​ 1.数据从一个不可信赖的数据源进入程序。
​ 2.这个数据用来指定 SQL 查询中主键的值。

官方案例:
示例 1:
	以下代码使用可转义元字符并防止出现 SQL 注入漏洞的参数化语句,以构建和执行用于搜索与指定标识符
相匹配的清单的 SQL 查询。您可以从与当前被授权用户有关的所有清单中选择这些标识符。
	id = Integer.decode(request.getParameter("invoiceID")); String query = "SELECT * FROM invoices WHERE id = ?";
	PreparedStatement stmt = conn.prepareStatement(query); stmt.setInt(1, id); 			ResultSet results = stmt.execute();
问题在于开发者没有考虑到所有可能出现的 id 值。虽然接口生成了一个当前用户的标识符清单,但是攻击者可以绕过
这个接口,从而获取所需的任何清单。因为此例中的代码没有执行检查,确保用户有权访问需要的清单,所以代码会
显示所有清单,即使这些清单并不属于当前用户。
有些人认为在移动世界中,典型的 Web 应用程序漏洞(如 Database access control 错误)是无意义的 -- 为什么用户要攻
击自己?但是,谨记移动平台的本质是从各种来源下载并在相同设备上运行的应用程序。恶意软件在银行应用程序附
近运行的可能性很高,它们会强制扩展移动应用程序的攻击面(包括跨进程通信)。

示例 2:
	以下代码对示例 1 进行调整,使其适用于 Android 平台。
	String id = this.getIntent().getExtras().getString("invoiceID"); String query = "SELECT * FROM invoices WHERE id = ?";
	SQLiteDatabase db = this.openOrCreateDatabase("DB", MODE_PRIVATE, null); Cursor c = db.rawQuery(query, newObject[]{id});
	许多现代 Web 框架都提供对用户输入执行验证的机制。其中包括 Struts 和 Spring MVC。为了突出显示未经验证的输入源,该规则包会降低 HPE Security Fortify Static Code Analyzer(HPE Security Fortify 静态代码分析器)报告的问题被利用的可能性,并在使用框架验证机制时提供相应的依据,以动态重新调整问题优先级。我们将这种功能称之为上下文敏感排序。为了进一步帮助 HPE Security Fortify 用户执行审计过程,HPE Security Fortify 软件安全研究团队提供了数据验证项目模板,该模板会根据应用于输入源的验证机制,将问题分组到多个文件夹中。
	
例 3:
	以下代码实施了与例 1 相同的功能,但是附加了一个限制,即为当前被授权的用户指定某一特定的获取清单的方
式。
	userName = ctx.getAuthenticatedUserName();
	id = Integer.decode(request.getParameter("invoiceID"));
	String query ="SELECT * FROM invoices WHERE id = ? AND user = ?";
	PreparedStatement stmt = conn.prepareStatement(query);
	stmt.setInt(1, id);
	stmt.setString(2, userName);
	ResultSet results = stmt.execute();
	
Recommendations:
	与其靠表示层来限制用户输入的值,还不如在应用程序和数据库层上进行 access control。任何情况下都不允许用户在没有取得相应权限的情况下获取或修改数据库中的记录。每个涉及数据库的查询都必须遵守这个原则,这可以通过把当前被授权的用户名作为查询语句的一部分来实现。
实际解决方案:

​ 这个问题出现的地方大多数是数据返回值上,其实在返回值return的时候判空返回相应的基本类型就OK了

​ 或者是出现在不明所以的地方,简单粗暴直接删除问题代码行。

	例如:
		return grayanologdao.getGrayAnoLogList(map);
		改为:
			if(map != null){
                return map;
			}

二、Category: Null Dereference

问题描述:

​ Category: Null Dereference:
​ 当违反程序员的一个或多个假设时,通常会出现 null 指针异常。如果程序明确将对象设置为 null,但稍后却间接引用该对象,则将出现 dereference-after-store 错误。此错误通常是因为程序员在声明变量时将变量初始化为 null。
​ 大部分空指针问题只会引起一般的软件可靠性问题,但如果攻击者能够故意触发空指针间接引用,攻击者就有可能利用引发的异常绕过安全逻辑,或致使应用程序泄漏调试信息,这些信息对于规划随后的攻击十分有用。

官方案例:
示例:
	在下列代码中,程序员将变量 foo 明确设置为 null。稍后,程序员间接引用 foo,而未检查对象是否为 null 值。
	Foo foo = null;
		...
	foo.setBar(val);
		...
}

Recommendations:
	在间接引用可能为 null 值的对象之前,请务必仔细检查。如有可能,在处理资源的代码周围的包装器中纳入 null 检查,确保在所有情况下均会执行 null 检查,并最大限度地减少出错的地方。
实际解决方案:

​ 错误多发生在流关闭等地方,程序员没有判空就关闭流,就引起了这个错误,解决起来也蛮方便,就是在流关闭的时候增加判空条件就ok了。

例如:
		} finally {
		try {
			pstmt.close();
		} catch (SQLException e) {
			e.printStackTrace();
			}
		}
	}
	改为:
		} finally {
		if(pstmt != null){
           	try {
				pstmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
				}
			} 
		}
	}

三、Category: Password Management: Password in Configuration File

问题描述:

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

官方案例:
Recommendations:
	绝不能采用明文的形式存储密码。相反,应在系统启动时,由管理员输入密码。如果这种方法不切实际,一个安全性较差、但通常都比较恰当的解决办法是将密码模糊化,并把这些去模糊化的资源分散到系统各处,因此,要破译密码,攻击者就必须取得并正确合并多个系统资源。
有些第三方产品宣称可以采用更加安全的方式管理密码。例如,WebSphere Application Server 4.x 用简单的异或加密算法加密数值,但是请不要对诸如此类的加密方式给予完全的信任。WebSphere 以及其他一些应用服务器通常都只提供过期的且相对较弱的加密机制,这对于安全性敏感的环境来说是远远不够的。较为安全的解决方法是由用户自己创建一个新机制,而这也是如今唯一可行的方法。
Tips:
	1. HPE Security Fortify Static Code Analyzer(HPE Security Fortify 静态代码分析器)会从配置文件中搜索那些用于密码属性的常用名称。当发现密码条目中包含明文时,就会将其标记为问题。
	2. 如果配置文件中包含一个默认密码条目,除了需要在配置文件中将其模糊化以外,还需要对其进行修改。
实际解决方案:

​ 尝试过对password进行加密操作,但是还是会被扫描出来,扫描好像不能出现 password=XXXX 不能出现等号情况,因此最简单粗暴的方法就是把这行错误删掉。

四、Category: Unreleased Resource: Database

问题描述:

​ 程序可能无法释放某个数据库连接。
​ 资源泄露至少有两种常见的原因:
​ - 错误状况及其他异常情况。
​ - 未明确程序的哪一部份负责释放资源。
​ 大部分 Unreleased Resource 问题只会导致一般的软件可靠性问题,但如果攻击者能够故意触发资源泄漏,该攻击者就有可能通过耗尽资源池的方式发起 denial of service 攻击。

官方案例:
示例:
	在正常条件下,以下代码会执行数据库查询指令,处理数据库返回的结果,并关闭已分配的指令对象。但如果
在执行 SQL 或是处理结果时发生异常,指令对象将不会关闭。如果这种情况频繁出现,数据库将用完所有可用的指针,且不能再执行任何 SQL 查询。
	Statement stmt = conn.createStatement();
	ResultSet rs = stmt.executeQuery(CXN_SQL);
	harvestResults(rs);
	stmt.close();
	Recommendations:
	
	1. 请不要依赖 finalize() 回收资源。为了使对象的 finalize() 方法能被调用,垃圾收集器必须确认对象符合垃圾回收的条件。但是垃圾收集器只有在 JVM 内存过小时才会使用。因此,无法保证何时能够调用该对象的 finalize() 方法。垃圾收集器最终运行时,可能出现这样的情况,即在短时间内回收大量的资源,这种情况会导致“突发”性能,并降低总体系统通过量。随着系统负载的增加,这种影响会越来越明显。最后,如果某一资源回收操作被挂起(例如该操作需要通过网络访问数据库),那么执行 finalize() 方法的线程也将被挂起。

	2. 在 finally 代码段中释放资源。示例中的代码可按以下方式改写:
           public void execCxnSql(Connection conn) {
            Statement stmt;
           try {
            stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(CXN_SQL);
            ...
            }
            finally {
            if (stmt != null) {
            safeClose(stmt);
            		}
            	}
            }
           public static void safeClose(Statement stmt) {
            if (stmt != null) {
           try {
            stmt.close();
            } catch (SQLException e) {
            log(e);
            }
           }
          }
	以上方案使用了一个助手函数,用以记录在尝试关闭指令时可能产生的异常。该助手函数大约会在需要关闭指令时重新使用。同样,execCxnSql 方法不会将 stmt 对象初始化为 null。而是进行检查,以确保调用 safeClose() 之前,stmt 不是 null。如果没有检查 null,Java 编译器会报告 stmt 可能没有进行初始化。编译器做出这一判断源于 Java 可以检测未初始化的变量。如果用一种更加复杂的方法将 stmt 初始化为 null,那么编译器就无法检测 stmt 未经初始化便使用的情况。

Tips:
	请注意,关闭数据库连接可能会自动释放与连接对象关联的其他资源,也可能不会自动释放。如果应用程序使用连接池,则最好在关闭连接后,明确关闭其他资源。如果应用程序未使用连接池,则数据库连接关闭后,其他资源也将自动关闭。在这种情况下,此漏洞无效。
实际解决方案:

​ 就是对将数据库连接对象先进行判空再关闭就ok,但是注意可能还需要再进行try/catch一下

例如:
	rs = st.executeQuery(sql);
		在finally中添加finally{
		try{
		if(rs != null){
	        rs.close;
			}
		}catch(Exception e){
	        e.printStackTrace();
		}
		}

五、Category: Unreleased Resource: Streams

问题描述:

​ 程序可能无法成功释放某一项系统资源。
​ 资源泄露至少有两种常见的原因:
​ - 错误状况及其他异常情况。
​ - 未明确程序的哪一部份负责释放资源。
​ 大部分 Unreleased Resource 问题只会导致一般的软件可靠性问题,但如果攻击者能够故意触发资源泄漏,该攻击者就有可能通过耗尽资源池的方式发起 denial of service 攻击。

官方案例:
示例:
	下面的方法绝不会关闭它所打开的文件句柄。FileInputStream 中的 finalize() 方法最终会调用 close(),但是不能确定何时会调用 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 = fis.read(byteArray)) != -1) {
	processBytes(byteArray, sz);
		}
	}

Recommendations:
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 = fis.read(byteArray)) != -1) {
		processBytes(byteArray, sz);
		}
	}
		finally {
		if (fis != null) {
		safeClose(fis);
				}
			}
		}
	public static void safeClose(FileInputStream fis) {
		if (fis != null) {
	try {
		fis.close();
		} catch (IOException e) {
			log(e);
			}
		}
	}
	以上方案使用了一个助手函数,用以记录在尝试关闭流时可能发生的异常。该助手函数大约会在需要关闭流时重新使用。同样,processFile 方法不会将 fis 对象初始化为 null。而是进行检查,以确保调用 safeClose() 之前,fis 不是 null。如果没有检查 null,Java 编译器会报告 fis 可能没有进行初始化。编译器做出这一判断源于 Java 可以检测未初始化的变量。如果用一种更加复杂的方法将 fis 初始化为 null,那么编译器就无法检测 fis 未经初始化便使用的情况。
实际解决方案:

​ 1.和上面问题的解决方案相似,单纯的判空关闭就ok。
​ 2.值得注意的是,有时候关闭对象也会报错,这时候就要考虑 先将流对象放在全局变量中,再进行关闭操作。

----------------------------------------wb对象-------------------------------------- 
@RequestMapping("uploadImportQueryFile")
    @ResponseBody
    public Map<String, Object> uploadImportQueryFile(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) {
        Map<String, Object> result = new HashMap<String, Object>();
        Workbook wb = null;
        try {
            int index = file.getOriginalFilename().lastIndexOf(".");
            if (index > -1 && "xlsx".equalsIgnoreCase(file.getOriginalFilename().substring(index + 1))) {
                wb = new XSSFWorkbook(file.getInputStream());
                Sheet sheet = wb.getSheetAt(0);
                int rows = sheet.getLastRowNum();

                List<String> numberList = new ArrayList<String>();
                for (int i = 1; i <= rows; i++) {
                    Cell cell = sheet.getRow(i).getCell(0);
                    cell.setCellType(Cell.CELL_TYPE_STRING);
                    String number = cell.getStringCellValue();
                    if (StringUtils.isNotBlank(number)) {
                        number = number.trim();
                        if (StringUtils.isNotBlank(number)) {
                            numberList.add(number);
                        }
                    }
                }
                file.getInputStream().close();
                request.getSession().setAttribute(IMPORT_QUERY_SESSION_KEY, numberList);
                request.getSession().removeAttribute(IMPORT_QUERY_RESULT_SESSION_KEY);
                result.put("success", true);
                result.put("message", "导入成功");
                result.put("data", numberList);
            } else {
                result.put("success", false);
                result.put("message", "文件格式有误");
            }
        } catch (IOException e) {
            e.printStackTrace();
            result.put("success", false);
            result.put("message", "程序异常:" + e.getMessage());
        } finally {
			if (wb!=null) {
				try {
					wb.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
        return result;
    }

六、Category: SQL Injection

问题描述:

SQL injection 错误在以下情况下发生:
​ 1.数据从一个不可信赖的数据源进入程序。
​ 2.数据用于动态地构造一个 SQL 查询。

官方案例:
例 1:
	以下代码动态地构造并执行了一个 SQL 查询,该查询可以搜索与指定名称相匹配的项。该查询仅会显示条目所有
者与被授予权限的当前用户一致的条目。
	...
	String userName = ctx.getAuthenticatedUserName();
	String itemName = request.getParameter("itemName");
	String query = "SELECT * FROM items WHERE owner = '"
	+ userName + "' AND itemname = '"
	+ itemName + "'";
	ResultSet rs = stmt.execute(query);
	...
这一代码所执行的查询遵循如下方式:
	SELECT * FROM items
	WHERE owner = <userName>
	AND itemname = <itemName>;
但是,由于这个查询是动态构造的,由一个不变的基查询字符串和一个用户输入字符串连接而成,因此只有在
itemName 不包含单引号字符时,才会正确执行这一查询。如果一个用户名为 wiley 的攻击者为 itemName 输入字符串“name' OR 'a'='a”,那么查询就会变成:
	SELECT * FROM items
	WHERE owner = 'wiley'
	AND itemname = 'name' OR 'a'='a';
附加条件 OR 'a'='a' 会使 where 从句永远评估为 true,因此该查询在逻辑上将等同于一个更为简化的查询:SELECT * FROM items;
这种查询的简化会使攻击者绕过查询只返回经过验证的用户所拥有的条目的要求;而现在的查询则会直接返回所有储
存在 items 表中的条目,不论它们的所有者是谁。

例 2:
	这个例子指出了将不同的恶意数值传递给在例 1 中构造和执行的查询时所带来的各种影响。如果一个用户名为
wiley 在 itemName 中输入字符串“name'; DELETE FROM items; --”,则该查询将会变为以下两个:
	SELECT * FROM items
	WHERE owner = 'wiley'
	AND itemname = 'name';
	DELETE FROM items;
	--'
众多数据库服务器,其中包括 Microsoft(R) SQL Server 2000,都可以一次性执行多条用分号分隔的 SQL 指令。对于那些不允许运行用分号分隔的批量指令的数据库服务器,比如 Oracle 和其他数据库服务器,攻击者输入的这个字符串只会导致错误;但是在那些支持这种操作的数据库服务器上,攻击者可能会通过执行多条指令而在数据库上执行任意命令。注意成对的连字符 (--);这在大多数数据库服务器上都表示下面的语句将作为注释使用,而不能加以执行 [4]。在这种情况下,注释字符的作用就是删除修改的查询指令中遗留的最后一个单引号。而在那些不允许这样加注注释的数据库中,通常攻击者可以如例 1 那样来攻击。如果攻击者输入字符串“name'); 
	DELETE FROM items; SELECT * FROM items
	WHERE 'a'='a”就会创建如下三个有效指令:
	SELECT * FROM items
	WHERE owner = 'wiley'
	AND itemname = 'name';
	DELETE FROM items;
	SELECT * FROM items WHERE 'a'='a';
有些人认为在移动世界中,典型的 Web 应用程序漏洞(如 SQL injection)是无意义的 -- 为什么用户要攻击自己?但是,谨记移动平台的本质是从各种来源下载并在相同设备上运行的应用程序。恶意软件在银行应用程序附近运行的可能性很高,它们会强制扩展移动应用程序的攻击面(包括跨进程通信)。

示例 3:以下代码对示例 1 进行调整,使其适用于 Android 平台。
	...
	PasswordAuthentication pa = authenticator.getPasswordAuthentication();
	String userName = pa.getUserName();
	String itemName = this.getIntent().getExtras().getString("itemName");
	String query = "SELECT * FROM items WHERE owner = '"
	+ userName + "' AND itemname = '"
	+ itemName + "'";
	SQLiteDatabase db = this.openOrCreateDatabase("DB", MODE_PRIVATE, null);
	Cursor c = db.rawQuery(query, null);
	...
避免 SQL injection 攻击的传统方法之一是,把它作为一个输入合法性检查的问题来处理,只接受列在白名单中的字符,或者识别并避免那些列在黑名单中的恶意数据。白名单方法是一种非常有效方法,它可以强制执行严格的输入检查规则,但是参数化的 SQL 指令所需维护更少,而且能提供更好的安全保障。而对于通常采用的列黑名单方式,由于总是存在一些小漏洞,所以并不能有效地防止 SQL injection 威胁。例如,攻击者可以:
	— 把没有被黑名单引用的值作为目标
	— 寻找方法以绕过对某一转义序列元字符的需要
	— 使用存储过程来隐藏注入的元字符
手动去除 SQL 查询中的元字符有一定的帮助,但是并不能完全保护您的应用程序免受 SQL injection 攻击。
防范 SQL injection 攻击的另外一种常用方式是使用存储过程。虽然存储过程可以阻止某些类型的 SQL injection 攻击,但
是对于绝大多数攻击仍无能为力。存储过程有助于避免 SQL injection 的常用方式是限制可作为参数传入的指令类型。但是,有许多方法都可以绕过这一限制,许多危险的表达式仍可以传入存储过程。所以再次强调,存储过程在某些情况下可以避免这种攻击,但是并不能完全保护您的应用系统抵御 SQL injection 的攻击。

Recommendations:
	造成 SQL injection 攻击的根本原因在于攻击者可以改变 SQL 查询的上下文,使程序员原本要作为数据解析的数值,被篡改为命令了。当构造一个 SQL 查询时,程序员应当清楚,哪些输入的数据将会成为命令的一部分,而哪些仅仅是作为数据。参数化 SQL 指令可以防止直接窜改上下文,避免几乎所有的 SQL injection 攻击。参数化 SQL 指令是用常规的SQL 字符串构造的,但是当需要加入用户输入的数据时,它们就需要使用捆绑参数,这些捆绑参数是一些占位符,用来存放随后插入的数据。换言之,捆绑参数可以使程序员清楚地分辨数据库中的数据,即其中有哪些输入可以看作命令的一部分,哪些输入可以看作数据。这样,当程序准备执行某个指令时,它可以详细地告知数据库,每一个捆绑参数所使用的运行时的值,而不会被解析成对该命令的修改。
PreparedStatement stmt = conn.prepareStatement(query);
stmt.setString(1, itemName);
stmt.setString(2, userName);
ResultSet results = stmt.execute();
...
下面是 Android 的等同内容:
...
PasswordAuthentication pa = authenticator.getPasswordAuthentication();
String userName = pa.getUserName();
String itemName = this.getIntent().getExtras().getString("itemName");
String query = "SELECT * FROM items WHERE itemname=? AND owner=?";
SQLiteDatabase db = this.openOrCreateDatabase("DB", MODE_PRIVATE, null);
Cursor c = db.rawQuery(query, new Object[]{itemName, userName});
...
	更加复杂的情况常常出现在报表生成代码中,因为这时需要通过用户输入来改变 SQL 指令的命令结构,比如在
WHERE 条件子句中加入动态的约束条件。不要因为这一需求,就无条件地接受连续的用户输入,从而创建查询语句字
符串。当必须要根据用户输入来改变命令结构时,可以使用间接的方法来防止 SQL injection 攻击:创建一个合法的字符串集合,使其对应于可能要加入到 SQL 指令中的不同元素。在构造一个指令时,可使用来自用户的输入,以便从应用程序控制的值集合中进行选择。

Tips:
	1. 使用参数化 SQL 指令的一个常见错误是使用由用户控制的字符串来构造 SQL 指令。这显然背离了使用参数化 SQL 指令的初衷。如果不能确定用来构造参数化指令的字符串是否由应用程序控制,请不要因为它们不会直接作为 SQL 指令执行,就假定它们是安全的。务必彻底地检查 SQL 指令中使用的所有由用户控制的字符串,确保它们不会修改查询的含意。

	2. 许多现代 Web 框架都提供对用户输入执行验证的机制。其中包括 Struts 和 Spring MVC。为了突出显示未经验证的输入源,HPE Security Fortify 安全编码规则包会降低 HPE Security Fortify Static Code Analyzer(HPE Security Fortify 静态代码分析器)报告的问题被利用的可能性,并在使用框架验证机制时提供相应的依据,以动态重新调整问题优先级。我们将这种功能称之为上下文敏感排序。为了进一步帮助 HPE Security Fortify 用户执行审计过程,HPE Security Fortify 软件安全研究团队提供了数据验证项目模板,该模板会根据应用于输入源的验证机制,将问题分组到多个文件夹中。
实际解决方案:

​ 说白了就是攻击者可以用SQL语句可以操作数据库,这个问题我查了资料也没解决,不知道问题是出在错误这行还是在SQL那里添加什么限制,总之没有解决,所有就直接将这句扫描出错误的代码给删除掉了,再扫描也没有出现这个问题。

七、Category: Privacy Violation: Autocomplete

问题描述:

​ 启用自动完成功能后,某些浏览器会保留会话中的用户输入,以便随后使用该计算机的用户查看之前提交的信息。

官方案例:
Recommendations:
	对于表单或敏感输入,显式禁用自动完成功能。通过禁用自动完成功能,之前输入的信息不会在用户输入时以明文形式显示。这也会禁用大多数主要浏览器的“记住密码”功能。
例 1:
	在 HTML 表单中,通过在 form 标签上将 autocomplete 属性的值显式设置为 off,禁用所有输入字段的自动完成功能。
	<form method="post" autocomplete="off">
	Address: <input name="address" />
	Password: <input name="password" type="password" />
	</form>
	
例 2:
	通过在相应的标签上将 autocomplete 属性的值显式设置为 off,禁用特定输入字段的自动完成功能。
	<form method="post">
	Address: <input name="address" />
	Password: <input name="password" type="password" autocomplete="off"/>
	</form>
	
请注意,autocomplete 属性的默认值为 on。因此,处理敏感输入时请不要忽略该属性。	
实际解决方案:

​ 官方给出的2种解决方案我读试过,就是在表单上标签上添加 autocomplete=“off” 属性,但是第二次扫描依然会扫描出来这个错误,所以也是简单粗暴的直接将这个表单删除了。

八、Category: Mass Assignment: Insecure Binder Configuration

问题描述:

​ 为便于开发和提高生产率,现代框架允许自动实例化一个对象,并使用名称与要绑定的类的属性相匹配的 HTTP 请求参数填充该对象。对象的自动实例化和填充加快了开发速度,但如果不谨慎实施,会导致严重的问题。绑定类或嵌套类中的任何属性都将自动绑定到 HTTP 请求参数。因此,恶意用户能够将值分配给绑定类或嵌套类中的任意属性,即使这些属性未通过 Web 表单或 API 合约暴露给客户端也是如此。

官方案例:
例 1:
	只需使用 Spring MVC 而无需进行额外配置,以下控制器方法即可将 HTTP 请求参数绑定到 User 或 Details 类中的任何属性:
@RequestMapping(method = RequestMethod.POST)
	public String registerUser(@ModelAttribute("user") User user, BindingResult result, SessionStatus status) {
	if (db.save(user).hasErrors()) {
		return "CustomerForm";
	} else {
		status.setComplete();
		return "CustomerSuccess";
	}
	}
	其中,User 类定义为:
	public class User {
		private String name;
		private String lastname;
		private int age;
		private Details details;
		// Public Getters and Setters
		...
	}
	Details 类定义为:
		public class Details {
		private boolean is_admin;
		private int id;
		private Date login_date;
		// Public Getters and Setters
		...
	}
	
Recommendations:
	当使用提供自动模型绑定功能的框架时,最佳做法是控制要绑定到模型对象的属性,这样,即使攻击者能够确定该模型或嵌套类的其他未暴露属性,他们也无法绑定 HTTP 请求参数的任意值。
根据所使用的框架,可以采用不同的方法控制模型绑定过程:
Spring MVC:可以控制绑定过程中要使用和忽略的 HTTP 请求参数。

例 2:
	在使用注释的 Spring 应用程序上,可以对方法进行 @InitBinder 注释,以便框架注入对 Spring 模型绑定器的引用。
Spring 模型绑定器可以配置 setAllowedFields 和 setDisallowedFields 以控制要绑定的属性:
	final String[] DISALLOWED_FIELDS = new String[]{"details.role", "details.age", "is_admin"};
	@InitBinder
	public void initBinder(WebDataBinder binder) {
		binder.setDisallowedFields(DISALLOWED_FIELDS);
	}
	
例 3:
	扩展 BaseCommandController 的 Spring 应用程序可以替代 initBinder(HttpServletRequest request,ServletRequestDataBinder binder) 方法,以获取对 Spring 模型绑定器的引用:
	@Override
	protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
	binder.setDisallowedFields(new String[]{"details.role", "details.age", "is_admin"});
	}
Apache Struts:Struts 1 和 2 仅将 HTTP 请求参数绑定到具有公共 setter 访问器的 Actions 或 ActionForms 属性。如果某个属性不应绑定到请求,则应将其 setter 设置为私有。

例 4:
	配置私有 setter 以便 Struts 框架不会自动绑定任何 HTTP 请求参数:
	private String role;
	private void setRole(String role) {
		this.role = role;
	}
REST 框架:
	大多数 REST 框架不会自动将内容类型为 JSON 或 XML 的 HTTP 请求正文绑定到模型对象。根据用于 JSON和 XML 处理的库,可以采用不同的方法控制绑定过程。
	以下是 JAXB (XML) 和 Jackson (JSON) 的一些示例:

例 5:
	使用 Oracle 的 JAXB 库从 XML 文档绑定的模型可以通过不同的注释控制绑定过程,例如 @XmlAccessorType、@XmlAttribute、@XmlElement 和 @XmlTransient。可以告诉绑定器默认不绑定任何属性,具体方法为:使用值为XmlAccessType.NONE 的 @XmlAccessorType 注释对模型进行注释,然后使用 @XmlAttribute 和 @XmlElement 注释选择应绑定的字段:@XmlRootElement@XmlAccessorType(XmlAccessType.NONE)
	public class User {
		private String role;
		private String name;
	@XmlAttribute
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
	
例 6:
	使用 FastXML 的 Jackson 库从 JSON 文档绑定的模型可以通过不同的注释控制绑定过程,例如 @JsonIgnore、@JsonIgnoreProperties、@JsonIgnoreType 和 @JsonInclude。可以通过对某些属性进行 @JsonIgnore 注释,告诉绑定器忽略这些属性。
	public class User {
	@JsonIgnore
		private String role;
		private String name;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
防止出现批量分配漏洞的另一方法是使用将 HTTP 请求参数绑定到 DTO 对象的分层体系结构。DTO 对象仅用于该目的,仅暴露 Web 表单或 API 合约中定义的属性,然后将这些 DTO 对象映射到域对象,在这里,可以定义剩余的私有属性。

Tips:
	此漏洞类别可以归类为设计缺陷,因为准确查找这些问题需要了解应用程序体系结构,这超出了静态分析的功能范
围。因此,如果将应用程序设计为使用特定 DTO 对象进行 HTTP 请求绑定,则可能根本不需要将绑定器配置为排除任何属性。
实际解决方案:

​ 实际没有解决,因为这个错误出现的并不多,高风险也允许有万分之三的存在,所以,哪位大佬解决了这个问题还请麻烦评论一下,大家交流交流。

九、Category: Password Management: Hardcoded Password

问题描述:

​ 使用硬编码方式处理密码绝非好方法。这不仅是因为所有项目开发人员都可以使用通过硬编码方式处理的密码,而且还会使解决这一问题变得极其困难。一旦代码投入使用,除非对软件进行修补,否则您再也不能改变密码了。如果帐户中的密码保护减弱,系统所有者将被迫在安全性和可行性之间做出选择。

官方案例:

例 1:
以下代码用 hardcoded password 来连接数据库:
	...
	DriverManager.getConnection(url, "scott", "tiger");
	...
该代码可以正常运行,但是任何有该代码权限的人都能得到这个密码。一旦程序发布,将无法更改数据库用户“scott”
和密码“tiger”,除非是要修补该程序。雇员可以利用手中掌握的信息访问权限入侵系统。更糟的是,如果攻击者能够
访问应用程序的字节代码,那么他们就可以利用 javap -c 命令访问已经过反汇编的代码,而在这些代码中恰恰包含着用户使用过的密码值。我们可以从以下看到上述例子的执行结果:
javap -c ConnMngr.class
22: ldc #36; //String jdbc:mysql://ixne.com/rxsql 24: ldc #38; //String scott 26: ldc #17; //String tiger
在移动世界中,由于设备丢失的几率较高,因此密码管理是一个非常棘手的问题。

例 2:
以下代码可使用硬编码的用户名和密码设置身份验证,从而使用 Android WebView 查看受保护页面。
	...
	webview.setWebViewClient(new WebViewClient() { 
		public void onReceivedHttpAuthRequest(WebView view,
	HttpAuthHandler handler, String host, String realm) { handler.proceed("guest", "allow"); } });
	...
与例 1 相似,该代码可以正常运行,但是任何有该代码权限的人都能得到这个密码。

Recommendations:
	绝不能对密码进行硬编码。通常情况下,应对密码加以模糊化,并在外部资源文件中进行管理。在系统中采用明文的形式存储密码,会造成任何有充分权限的人读取和无意中误用密码。至少,密码要先经过 hash 处理再存储。
有些第三方产品宣称可以采用更加安全的方式管理密码。例如,WebSphere Application Server 4.x 用简单的异或加密算法加密数值,但是请不要对诸如此类的加密方式给予完全的信任。WebSphere 以及其他一些应用服务器通常都只提供过期的且相对较弱的加密机制,这对于安全性敏感的环境来说是远远不够的。一般较为安全的解决方法是采用由用户创建的所有者机制,而这似乎也是目前最好的方法。
	对于 Android 以及其他任何使用 SQLite 数据库的平台来说,SQLCipher 是一个好选择 -- 对 SQLite 数据库的扩展为数据库文件提供了透明的 256 位 AES 加密。因此,凭证可以存储在加密的数据库中。

例 3:
	以下代码演示了在将所需的二进制码和存储凭证下载到数据库文件后,将 SQLCipher 集成到 Android 应用程序中的方法。
	import net.sqlcipher.database.SQLiteDatabase;
	...
	SQLiteDatabase.loadLibs(this); 
	File dbFile = getDatabasePath("credentials.db");
    dbFile.mkdirs(); dbFile.delete(); 
    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbFile, "credentials", null); 
    db.execSQL("create table credentials(u, p)");
	db.execSQL("insert into credentials(u, p) values(?, ?)", new Object[]{username, password});
	...
请注意,对 android.database.sqlite.SQLiteDatabase 的引用可以使用 net.sqlcipher.database.SQLiteDatabase 代替。
要在 WebView 存储上启用加密,需要使用 sqlcipher.so 库重新编译 WebKit。

Tips:
	1. 可使用 Fortify Java Annotations、FortifyPassword 和 FortifyNotPassword 来指示哪些字段和变量代表密码。
	2. 识别 null password、empty password 和 hardcoded password 时,默认规则只会考虑包含 password 字符的字段和变量。但是,HPE Security Fortify Custom Rules Editor(HPE Security Fortify 自定义规则编辑器)会提供 Password Management 向导,让您轻松创建能够从自定义名称的字段和变量中检测出 password management 问题的规则。
实际解决方案:

​ 如果有条件再写加密算法,加密类的话,写了调用是最好的,但是有时候调用加密之后还是会扫描出来。
​ 其次当然了,也可以直接删掉扫描出问题的代码行。

十、Category: Password Management: Empty Password in Configuration File

问题描述:

​ 在任何时候使用空字符串作为密码都是不恰当的。因为它太容易被猜中了。

官方案例:
Recommendations:
	必须使用非常难以猜测的密码来保护所有的帐户和系统资源。参照以下内容来帮助建立适当密码管理方针。
Tips:
	HPE Security Fortify Static Code Analyzer(HPE Security Fortify 静态代码分析器)会从配置文件中搜索那些用于密码属性的常用名称。当发现这样的密码条目时,就会将其标记为问题。
实际解决方案:

​ 和上面的解决方案一样,写加密类或者直接删除问题代码行。

十一、Category: Insecure Randomness

问题描述:

​ 在对安全性要求较高的环境中,使用一个能产生可预测数值的函数作为随机数据源,会产生 Insecure Randomness 错误。电脑是一种具有确定性的机器,因此不可能产生真正的随机性。伪随机数生成器 (PRNG) 近似于随机算法,始于一个能计算后续数值的种子。
​ PRNG 包括两种类型:统计学的 PRNG 和密码学的 PRNG。
​ 统计学的 PRNG 可提供有用的统计资料,但其输出结果很容易预测,因此数据流容易复制。若安全性取决于生成数值的不可预测性,则此类型不适用。
​ 密码学的 PRNG 通过可产生较难预测的输出结果来应对这一问题。为了使加密数值更为安全,必须使攻击者根本无法、或极不可能将它与真实的随机数加以区分。
​ 通常情况下,如果并未声明 PRNG 算法带有加密保护,那么它有可能就是一个统计学的 PRNG,不应在对安全性要求较高的环境中使用,其中随着它的使用可能会导致严重的漏洞(如易于猜测的密码、可预测的加密密钥、会话劫持攻击和 DNS 欺骗)。

官方案例:
示例: 
	下面的代码可利用统计学的 PRNG 为购买产品后仍在有效期内的收据创建一个 URL。
		function genReceiptURL (baseURL){
			var randNum = Math.random();
			var receiptURL = baseURL + randNum + ".html";
			return receiptURL;
		}
	这段代码使用 Math.random() 函数为它所生成的收据页面生成独特的标识符。因为 Math.random() 是一个统计学的PRNG,攻击者很容易猜到由它所生成的字符串。尽管收据系统的底层设计也存在错误,但如果使用了一个不生成可预测收据标识符的随机数生成器(如密码学的 PRNG),会更安全一些。

Recommendations:
	当不可预测性至关重要时,如大多数对安全性要求较高的环境都采用随机性,这时可以使用密码学的 PRNG。不管选择了哪一种 PRNG,都要始终使用带有充足熵的数值作为该算法的种子。(诸如当前时间之类的数值只提供很小的熵,因此不应该使用。)在 JavaScript 中,常规的建议是使用 Mozilla API 中的window.crypto.random() 函数。但这种方法在多种浏览器中都不起作用,包括 Mozilla Firefox 的最新版本。目前没有适用于功能强大的密码学 PRNG 的跨浏览器解决方案。此时应考虑在JavaScript 之外处理任意 PRNG 功能。
实际解决方案:

​ 在网上看过几篇文章,说是将 Math.random().toString().substring(2) 的相关数值扩大NNN倍;亦或是将random改成SorcreRandom
​ 但是我这是采用自定义random的方法来替换常规的random,在第二次扫描之后,问题就解决了。

以js为例添加自定义的random方法:
 function  randnum() {
     var seed = (new Date()).getTime();
     seed = (seed*9301+49297)%233280;
     return seed/(233280.0);
 }
 
将其替换
return Math.random().toString().substring(2)  -->   randnum().toString().substring(2)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

部分Fortify代码扫描高风险解决方案 的相关文章

  • Abort message: ‘FORTIFY: FD_SET: file descriptor 1070 >= FD_SETSIZE 128‘

    问题现象 压力测试骁龙相机 xff0c 发现camera provicer 进程崩溃 无法正常打开相机 xff0c 只有重新启动设备 相关的log xff1a 03 23 08 17 08 592 15634 15634 F DEBUG s
  • 部分Fortify代码扫描高风险解决方案

    部分Fortify代码扫描高风险解决方案 一 Category Access Control Database 问题描述 xff1a Database access control 错误在以下情况下发生 xff1a 1 数据从一个不可信赖的
  • fortify代码扫描使用教程

    配置信息 HP Fortify SCA and Applications 4 10 WIN7 64位家庭版 打开fortify的工作台 选择Advanced Scan 如果你知道源代码是java的可以选择Scan Java C 可以选择Sc
  • fortify 漏洞扫描的几种解决方式

    1 关于Log的问题 Log Forging 整个系统中 对于Log的问题最多 可以采用以下方式进行解决 解决方案如下 1 只输出必要的日志 功能上线前屏蔽大多数的调试日志 2 过滤掉非法字符 2 关于创建File Path Manipul
  • 如何查看 Fortify 安全编码规则的所有规则?

    我想查看 Fortify 安全编码规则的具体规则 Fortify 默认使用的规则 因为我想编写一份有关 Fortify 使用的所有规则的报告 我试图看到他们C Program Files Fortify Software HP Fortif
  • HP Fortify——注释方法参数

    我正在尝试消除 Java 应用程序的 HP Fortify 扫描中的误报 此方法会导致 侵犯隐私 问题 PrintWriter 是 servlet 响应 private void writeOutput String passwordRul
  • 如何纠正 fortify 给出的路径操作错误?

    我需要读取保存在 user home 文件夹中的属性文件 PropsFile System getProperty user home System getProperty file separator x properties Forti
  • 将字段设置为 null 时 Java Null Dereference - Fortify

    当我将字段设置为 null 时 Fortify 抱怨 Null 取消引用 String sortName null if lastName null lastName length gt 0 sortName lastName sortOp
  • ASP.NET 不良实践:会话中存储不可序列化的对象

    我有一个类似的代码 Session key value 但根据 Fortify SCA 由于 会话中存储了不可序列化的对象 这被认为是一种不好的做法 Screenshot as below 解决这个问题的最佳方法是什么 如何使字符串 val
  • 如何使用Fortify Scan 16.11通过project.Json扫描dotnet core

    我创建了一个默认的 Net Core 1 0 1 类库 并更改了 project json 中的 buildOptions 以包含 debugType Full 我使用 16 11 的集成 VS 2015 Fortify Scan 并收到以
  • EnableHeaderChecking=true 是否足以防止 Http 标头注入攻击?

    拥有 就足够了吗 System Web Configuration HttpRuntimeSection EnableHeaderChecking http msdn microsoft com en us library system w
  • Fortify 源分析器和 Apache Lenya

    我正在尝试将 Fortify 源代码分析器用于我学校的一个研究项目 以测试开源 Java Web 应用程序的安全性 我目前正在研究 Apache Lenya 我正在使用最新的稳定版本 Lenya v2 0 2 根目录下有一个文件名为buil
  • 如何强制 cmake 使用没有完整路径的 cl.exe?

    我正在构建一个使用 CMake 的开源项目 kst v2 0 8 我使用 CMake v2 8 12 2 和 MSVC 2008 作为编译器 并生成 NMake makefile 以在命令行上构建它 我可以通过此设置成功构建它 这些版本是强
  • HP Fortify 路径操作验证规则

    我正在通过 Hp Fortify 运行代码 并有一些路径操纵的发现 我了解它的背景并试图解决 我没有遍历从数据库查询某些路径值来存储输出文件 日志 导出数据等 的所有位置 而是尝试将其集中化 因此 我不想让 File WriteAllTex
  • 如何生成包含所有问题的报告?

    我有一个在 AWB 中打开的 Fortify FPR 扫描文件 我想生成一份报告 其中包含发现问题的所有实例 当我生成报告时 它会生成按类型及其计数列出问题的报告 并且在类型下方我还会获得以下名称和代码片段some发现问题的文件 我想生成一
  • 无法解决原木锻造强化问题

    我在修复 Fortify 中的日志锻造问题时遇到问题 getLongFromTimestamp 方法中的两个日志记录调用都引发了 将未经验证的用户输入写入日志 的问题 public long getLongFromTimestamp fin
  • Java 中 JSON 注入的 Fortify 错误

    我正进入 状态SUBSCRIPTION JSON来自客户端 我将其转换为字符串 然后使用 gson 库将其设置为模型对象 在 Fortify security 上运行代码时 下面的代码出现 Json 注入错误 并显示以下消息 这是错误 On
  • HP 强化 XML 外部实体注入

    Hp fortify 通过以下代码向我展示了 XML 外部实体注入 StringBuilder sb new StringBuilder StringWriter stringWriter new StringWriter sb xmlSe
  • 强化修复经常被误用的身份验证

    当我使用 Fortify 进行扫描时 我在下面的代码中遇到了诸如 经常被误用 身份验证 之类的漏洞 这个问题有解决办法吗 我看过相关帖子 但没能找到解决方案 使用 ESAPI 我提供了主机名和 ipadress 的正则表达式 但它不起作用
  • (Fortify) 类别:Android 不良做法:缺少 Google Play 服务更新的安全提供程序(1 期)

    我们正在使用 Fortify 扫描我的 Android 源代码 但我无法摆脱这个问题 类别 Android 不良做法 缺少 Google Play 服务更新的安全提供程序 1 期 Fortify指向这行代码 工具 替换 android al

随机推荐

  • “-1” 文件删除

    无法删除以短连接符开头 1 的文件 rm rf 1 或 rm rf 34 1 34 问题原因 xff1a 短连接符会被当作选项解析 解决方式有两种 xff1a 一种加前缀使用相对或绝对路径 xff1b 一种使用 标识选项解析结束 xff08
  • 01 梯度下降、学习率、损失函数

    概念引入 基于一个自变量x xff0c 比如时间 xff0c 我们可以得到其对应的观测值y xff0c 比如温度值 不停的观测 xff0c 我们可以得到一系列的真实对应关系 xff1a 时间 xff0c 温度的真实值 xff0c 即 x1
  • 02 LinerRegression

    问题引入 xff1a 这就是个简单的线性回归函数的计算问题 现在我们已知一次函数 y 61 4x 43 9 xff0c bias为一个服从标准正态分布的随机随机数值 那么通过 y 61 4x 43 9 43 bias xff0c 当我们给定
  • Mysql 5.1.70 及 Navicat 安装教程

    为了避免安装后期出现Bug xff0c 首先必须明确电脑中从未安装过Mysql xff0c 或者安装过Mysql并且卸载干净 xff0c 否则二次安装会出错 此外 xff0c 安装过Mysql xff0c 并且进行过卸载 xff0c 需要进
  • jdk的配置与eclipse的使用

    首先自然是安装包从哪里获得这个问题 xff1a jdk历史版本 xff1a https www oracle com java technologies oracle java archive downloads html eclipse历
  • 01 原生JDBC的使用缺陷与基础环境配置

    开发环境 jdk1 7 0 72 eclipse eclipse 3 7 indigo mysql mysql5 1 相关安装教程 jdk的配置与eclipse的使用 与 Mysql 5 1 70 及 Navicat 安装教程 工程目录 创
  • 02 Mybatis结构配置

    文章目录 01 mybatis介绍 02 mybatis框架工作流程 03 ecplice项目jar包导入方法 04 在项目中导入mybitis框架的依赖包 05 项目下创建config文件夹 06 xml配置文件的设置 07 pojo数据
  • 03 Mybatis入门程序

    1 配置SqlMapConfig 配置数据库连接相关信息 span class token prolog lt xml version 1 0 encoding UTF 8 gt span span class token doctype
  • 04 Mybatis的增删改查

    1 mybatis中sql语句的占位符与parameterType 与 parameterType 表示一个占位符 向占位符输入参数 mybatis自动进行java类型和jdbc类型的转换 程序员不需要考虑参数的类型 比如传入字符串 myb
  • C++链表的各种操作

    题目描述 代码 include lt iostream gt include lt algorithm gt using namespace std struct sqList int data sqList next sqList Lis
  • HJ001 字符串最后一个单词的长度

    目录 题目描述 输入描述 输出描述 输入 输出 做题思路 AC代码 题目描述 计算字符串最后一个单词的长度 xff0c 单词以空格隔开 输入描述 输入一行 xff0c 代表要计算的字符串 xff0c 非空 xff0c 长度小于5000 输出
  • 盲签名 blind signature 简介

    转 https blog csdn net zhang hui cs article details 8728776 盲签名 Blind Signature 定义 是一种数字签名的方式 在消息内容被签名之前 对于签名者来说消息内容是不可见的
  • VMware 虚拟机安装 OpenWrt 作旁路由 单臂路由 img 镜像转 vmdk 旁路由无法上网 没网络

    重要注意事项 由于布线原因笔记本只能采用无线的方式连接路由器 xff0c 在Windows10的环境下使用无线网卡桥接 xff0c 结果软路由无法上网 xff0c 翻阅了各种帖子最终发现跟系统底层的协议栈有关系 xff0c 随即放弃使用有线
  • HJ002 计算某字母出现的次数

    目录 题目描述 输入描述 输出描述 输入 输出 做题思路 1 AC代码 1 做题思路 2 AC代码 2 题目描述 写出一个程序 xff0c 接受一个由字母 数字和空格组成的字符串 xff0c 和一个字母 xff0c 然后输出输入字符串中该字
  • HJ003 明明的随机数

    目录 题目描述 输入描述 输出描述 输入 输出 说明 做题思路 AC代码 题目描述 明明想在学校中请一些同学一起做一项问卷调查 xff0c 为了实验的客观性 xff0c 他先用计算机生成了N个1到1000之间的随机整数 xff08 N 10
  • new,delete使用详解(动态多维数组空间申请)

    C语言中利用库函数malloc和free来分配和撤销空间的 C 43 43 中的new与delete是运算符 xff0c 不是函数 xff0c 所以执行效率更高 但C 43 43 中也是可以使用malloc和free的 但是一来不方便 xf
  • 局部,全局(外部),static等变量详解

    首先 xff0c 必须明白一个程序是包含若干个源文件 xff0c 每个源文件又是包含若干个函数 xff0c 每个源文件 函数中又定义了若干个变量 但是每个变量都有自己的作用范围 xff0c 也就是自己的作用域 只有在作用域内才可以访问变量
  • 函数的可变参数的实现

    stdarg h stdarg h是C语言中C标准函数库的头文件 xff0c stdarg是由standard xff08 标准 xff09 arguments xff08 参数 xff09 简化而来 xff0c 主要目的为让函数能够接收可
  • 常见的注入方式

    设计模式中常见的注入方式 依赖注入 最近在求职 xff0c 耽搁了 xff0c 对于应届生来讲想找个大数据相关的工作何其困难 所以在填充一些自己不足之处 xff0c 希望与君共勉 一 依赖注入DI 开发过程中 xff0c 如果发现客户程序依
  • 部分Fortify代码扫描高风险解决方案

    部分Fortify代码扫描高风险解决方案 一 Category Access Control Database 问题描述 xff1a Database access control 错误在以下情况下发生 xff1a 1 数据从一个不可信赖的