|
最近公司在搞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()入口处是这样的:
- [java] view plaincopyprint?
- //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,因为它默认是不开启的,如:
- [java] view plaincopyprint?
- try {
- // try to create a file at $path
- File fs = new File("foo");
- fs.createNewFile();
- } catch (AccessControlException e) {
- e.printStackTrace();
- }
复制代码
其实是可以正常执行的, 但如果加了一条
- [java] view plaincopyprint?
- 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以及访问控制的运行机制,还是比较复杂的,一时也说不清, 更具体的还要靠自己慢慢
探索了。
|
|