一、不安全的自动完成
描述

借助表单的自动完成功能,某些浏览器可以在历史记录中保留敏感信息。

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

解决方案
对于表单或敏感输入,显式禁用自动完成功能。通过禁用自动完成功能,之前输入的信息不会在用户输入时以明文形 式显示。这也会禁用大多数主要浏览器的“记住密码”功能。

例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。因此,处理敏感输入时请不要忽略该属性。




二、未释放的资源
描述

程序可能无法成功释放某一项系统资源。



举例

程序可能无法成功释放某一项系统资源。


资源泄露至少有两种常见的原因:


- 错误状况及其他异常情况。


- 未明确程序的哪一部份负责释放资源。



大部分资源未释放问题只会导致一般的软件可靠性问题,但如果攻击者能够故意触发资源泄漏,该攻击者就有 可能通过耗尽资源池的方式发起“拒绝服务(denial of service,俗称Dos)”攻击。



示例:下面的方法绝不会关闭它所打开的文件句柄。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); 
}


解决方案

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未经初始化便使用的情况。