由Fortify扫描结果而引发的java安全模型分析

最近公司在搞security audit,项目里的applet被Fortify扫描后报了一个安全隐患,具体信息如下:

Abstract:
Non-final methods that perform security checks can be overridden in ways that bypass security checks.
Explanation:
If a method is overriden by a child class, the child class can bypass security checks in the parent class.
Example: In the following code, doSecurityCheck() performs a security check and can be overriden by a child class.
public class BadSecurityCheck {
	private int id;
	public BadSecurityCheck() {
		doSecurityCheck();
		id = 1;
	}
	protected void doSecurityCheck() {
		SecurityManager sm = System.getSecurityManager();
		if (sm != null) {
			sm.checkPermission(new SomePermission("SomeAction"));
		}
	}
}

这个问题就是说我在applet类的init()方法代码里用到了AccessController.checkPermission()方法,而由于我的类是public非final的,所以hacker们可以自己写一个子类继承后重写init方法,绕过安全检查过程去干一些坏事。

首先我觉得这警告有一定道理,所以打算把类改成final的,但是我又想不通一个applet如何继承重写以及会有什么坏事可干,因为我的程序init()入口处是这样的:

//check file permission
Permission sockPerm=new SocketPermission("*","accept,connect,listen");
Permission filePerm=new FilePermission("<<ALL FILES>>","read");  // what if (in linux) the user cannot read all files
try{
	AccessController.checkPermission(sockPerm);
	AccessController.checkPermission(filePerm);	  // the applet cannot successfully run if this failed
}catch(AccessControlException ace){
	this.hintText=LocaleUtils.getResourceValue("mainpanel.hinttext.unauthorized");
	permissionAllowed=false;
}
在applet启动时先去检查自己是否有相关权限去读客户端的文件,如果没有就提示用户。所以我没想到这会有什么安全隐患,然后我查阅了java的相关资料,试着去了解java的安全机制到底是怎样的。


首先,只针对java applet,JVM安全策略是这样的:

1. 作为从网络下载到的java代码,applet默认是不受信任的,在客户端没有任何读写权限,完全运行在沙箱里。

2. 为了使applet可以和客户本地文件交互,可以为applet进行签名,签过名的applet有读写文件的权利,但是如果该签名是非信任的,也就是没有认证的,会在加载applet时弹出对话框提示用户,只有用户允许才能获得权限。

3. 如果是认证可信签名,则可以完全正常允许。


了解了applet的权限控制后,又进一步了解了java的安全机制。实际上, Java 将执行程序分成本地和远程两种,本地代码默认视为可信任的,而远程代码(如applet)则被看作是不受信的。对于授信的本地代码,可以访问一切本地资源。

这里的权限控制,是由java安全管理器(Security Manager)管理的,远程代码JVM自动启动管理,而本地默认不启动。


这里只做一个最简单和最基础的演示, 比如我们在平时写java代码文件操作时,很少考虑权限问题,以及为什么我们很少用的AccessController,因为它默认是不开启的,如:

try {
	// try to create a file at $path
	File fs = new File("foo");
	fs.createNewFile();
} catch (AccessControlException e) {
	e.printStackTrace();
}

其实是可以正常执行的, 但如果加了一条

System.setSecurityManager(new SecurityManager());
try {
	// try to create a file at $path
	File fs = new File("foo");
	fs.createNewFile();
} catch (AccessControlException e) {
	e.printStackTrace();
}

就会抛出异常, 原因就像前面说的, 本地默认安全管理器是没有开启的,所以我们的程序有所有权限,但一旦你打开了SecurityManager,你就失去了这些权限,需要重新获得才可以,需要用到权限提升方法doProvileged,整个Security Manager以及访问控制的运行机制,还是比较复杂的,一时也说不清, 请参考http://blog.jobbole.com/31940/, 更具体的还要靠自己慢慢探索了。






posted @ 2013-01-10 15:11  bus driver  阅读(1069)  评论(0编辑  收藏  举报
Hello world