0%

java安全管理器应用

[toc]

Java安全类库常见问题#

Q:有几种方式可以启动安全管理器?#

A:两种方式
隐式启动: 启动命令里加-Djava.security.manager, 即可开启安全管理器。
显示启动: 代码里自己new一个SecurityManager或者继承一个新子类, 然后用System.setSecurityManager(xxxSecurityManager)来设置


看以下代码:

1
2
3
4
5
public class SecurityManagerTest {    
public static void main(String[] args) throws FileNotFoundException {
System.out.println(System.getProperty("file.encoding"));
}
}

Q:如果我不设置安全管理器,直接跑System.getProperty,会报权限错误吗?#

A:
不会报错误。 如果隐式和显示启动都没做,那么System里的SecurityManager就是null,那么就不会进行检查。
可以看下System.getProperty里的源码:
492830d481c84ff56c99dec832d0939d6616b824


Q: 隐式启动中,如果只配了-Djava.security.manager ,但没有配-Djava.security.policy, 那么上面的文件以及系统配置是都允许读,还是都不允许读?#

A:
都不允许读。 即开启后,不在policy允许范围内的,都默认不允许读。


  • 如果要允许读文件以及读file.encoding那个系统配置, 需要加上-Djava.security.policy=xxx.policy , 指明policy文件。

  • 文件里大概长这样
    9fe292ac9397f17154eb131f2b7ac65ae6bbfa7a
    注意policy是拼在-Djava.security.manager的后面
    5ef1de92e4ef3956fc00c8830f82479b77213629


显示启动,就是自己new一个SecurityManager,并set进去。

Q:如果我之前有隐式启动,此时new了一个新的SecurityManager放进去,此时是否还有该属性的read权限?#

eb6b0119d97e6e30fd93f610fde5a8e5dc4ecd6b

A:没有了,之前由启动参数配进去的安全管理器已经被你覆盖掉了

对于隐式启动和显示启动, 都是默认没有任何可用权限!

都是白名单机制, 无黑名单机制。


常见的java 安全权限#

都是能从名字就知道什么作用的,瞄一眼有个印象就行,大概知道java里这些功能可能都会有权限。

  • java.security.AllPermission 所有权限的集合

  • java.util.PropertyPermission 系统/环境属性权限
    就是System.getProperty(xxx.xxx.xxx)的权限

  • java.lang.RuntimePermission 运行时权限
    这个安卓用的很多,

  • java.net.SocketPermission Socket权限

  • java.io.FilePermission 文件权限,包括读写,删除,执行

  • java.io.SerializablePermission 序列化权限

  • java.lang.reflect.ReflectPermission 反射权限

  • java.security.UnresolvedPermission 未解析的权限

  • java.net.NetPermission 网络权限

  • java.awt.AWTPermission AWT权限

  • java.sql.SQLPermission 数据库sql权限

  • java.security.SecurityPermission 安全控制方面的权限

  • java.util.logging.LoggingPermission 日志控制权限

  • javax.net.ssl.SSLPermission 安全连接权限

  • javax.security.auth.AuthPermission 认证权限

  • javax.sound.sampled.AudioPermission 音频系统资源的访问权限


关于上面的permission权限,有一个重要的应用,就是在ClassLoader中。
如果JVM开启了SecurityManager, ClasserLoader就会在加载类的时候调用Policy.getPermissions来获取代码权限集, 并将代码来源和权限集封装到保护域。

1
2
3
4
5
6
7
8
9
public class MyClassLoader extends URLClassLoader {
@Override
protect PermissionCollection getPermissions(CodeSource cs) {
PermissionCollection pc = super.getPermissions(cs);
// 添加权限
pc.add(new XXXPersion());
return pc;
}
}

Q: 详细讲讲安全管理器的应用场景?#

A:

  • 如果你是某个平台开发者,提供了某个SDK给其他人使用, 这里面涉及了某个文件读取或者文件写入操作。
    但是你只希望他用这个sdk去操作平台下特定目录的文件,而不是去动其他的位置(比如根目录之类的)
    于是你就可以给sdk代码封装上一层权限, 在这个代码块中只能读特定目录(就像上面的filePermission)
  • 或者你通过的公开类中有个高危方法deleteXXX, 你希望拥有管理员权限的人才能调用,其他人不能调用, 于是可以在高危方法中加一层权限, 下面的例子来自安全编码规范, removeEncryt就是高危方法, 调用前会检查一下是否具有这个自定义的权限类型
1
2
3
4
5
6
7
8
9
10
11
12
public class SensitiveHash {
void removeEntry(Object key) {
check("removeKeyPerssion");
ht.remove(key);
}
private void check(String dire) {
SecurityManager sm = System.getSecurityManager();
if (sm!=null) {
sm.checkSecurityAccess(dire)
}
}
}

Q: 上面这个例子中, 如果恶意调用者自己在安全管理器中增加这种权限的处理怎么办?#

A: setSecurityManager方法API也是需要权限的。 作为客户端程序一般没有权限去设置SDK的安全管理器。 java默认的policy配置文件也没有放开这个权限。需要支持在policy里setSecurityManager才行。


Q: 假设某服务实现了一个自定义classLoader, 支持从网络获取信任客户传来的jar包并在自己的服务中执行, 那么应该如何防止加载不可信的jar包呢?#

A :

  1. 取出jar包中的证书资源
  2. 获取服务自身的密钥
  3. 校验证书是否是这些密钥的受信任签名(即我要识别你的这个证书是不是从我这里签发出去的)

注意,不要使用URLClassLoaer和java.util.jar里的自动签名校验机制,他只是检查jar包中的签名和公钥是否匹配,这仅仅是完整性校验, 这2者是可以被全部替换的


Q:不加盐值的哈希口令哈希有什么缺陷?#

A:

生日判定,可以快速找到一个口令

可以利用事先计算好的哈希列表几秒钟破解。


Q:对口令做哈希加盐值时有什么要求?#

A:

盐值至少应该包含8字节而且必须是由安全随机数产生。( 例如如果问你,sha256+4字节盐值,那肯定就是错误的!)

应使用强哈希函数,推荐使用SHA-256或者更加安全的哈希函数。

迭代次数默认推荐10000次,对于性能有特殊要求(比如嵌入式系统)的产品低可迭代1000次。

对于单向哈希时,其输出长度应该不小于256比特