一、不安全的自动完成
描述
借助表单的自动完成功能,某些浏览器可以在历史记录中保留敏感信息。
举例
启用自动完成功能后,某些浏览器会保留会话中的用户输入,以便随后使用该计算机的用户查看之前提交的信息。
解决方案
对于表单或敏感输入,显式禁用自动完成功能。通过禁用自动完成功能,之前输入的信息不会在用户输入时以明文形 式显示。这也会禁用大多数主要浏览器的“记住密码”功能。
例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未经初始化便使用的情况。