在Java策略文件中,grant codeBase
语法指定应授予哪些代码库哪些权限.例如,
grant codeBase"file:/ C:/abc.jar"{permission java.security.AllPermission; };
授予AllPermission
abc.jar中的代码
以类似的方式,有没有办法deny
获得特定语法的权限?像这样:
deny codeBase"file:/ C:/def.jar"{permission java.io.FilePermission; };
以便内部代码def.jar
获取除FilePermission之外的所有其他权限?
这甚至可能吗?
我知道这可以使用SecurityManager
类轻松完成,但我只是想通过仅使用策略文件来了解是否可行.
我不想修改我的java主目录中的任何内容,但是,我担心有时我的默认java.policy文件可能过于宽松.当我使用该-Djava.security.manager
选项运行java时,有没有办法让我使用指定的策略文件作为唯一的策略文件?
如果我添加一个-Djava.security.policy=myPolicy.policy
选项,它除了使用默认策略文件之外还使用我的策略文件 - 这很糟糕,因为看起来仍然授予了在默认策略文件中授予的所有权限.
我正在将 jdk 8 升级到 11。
我在checkPermission
方法中加载了一些类,然后安全管理器发出recursive update
异常。但使用jdk1.8.0_202
一切正常。
是什么导致了这个问题?
OS: macOS 10.15.6
JDK(Oracle): 11.0.8
IDE: Intellij 2019 3
Run Code Online (Sandbox Code Playgroud)
public class Main {
public static void main(String[] args) {
System.out.println("Hello world");
}
}
Run Code Online (Sandbox Code Playgroud)
package sm;
import java.security.Permission;
public class MySecurityManager extends SecurityManager {
@Override
public void checkPermission(Permission permission) {
// Problem occurs when load ServicePermission.class
if (permission instanceof javax.security.auth.kerberos.ServicePermission) {
// throw new SecurityException("javax.security.auth.kerberos.ServicePermission is not allowed.");
}
}
@Override
public void checkPermission(Permission …
Run Code Online (Sandbox Code Playgroud) 我有一个客户端和服务器程序,试图相互通信.在我的服务器的策略文件中,我指定了以下内容:
grant signedBy "vivin" {
permission java.io.FilePermission "-", "read, write";
permission java.net.SocketPermission "localhost:2220-2230", "accept, connect, listen, resolve", signedBy "vivin";
};
Run Code Online (Sandbox Code Playgroud)
在我的客户的政策文件中,我有:
grant signedBy "vivin" {
permission java.net.SocketPermission "localhost:2220-2230", "accept, connect, listen, resolve", signedBy "vivin";
};
Run Code Online (Sandbox Code Playgroud)
我启动我的服务器,它侦听端口2225.然后我启动我的客户端,它尝试连接到正在侦听端口2225的服务器.不幸的是,我在服务器上收到此错误:
[java] Exception in thread "main" java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:45944 accept,resolve)
[java] at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323)
[java] at java.security.AccessController.checkPermission(AccessController.java:546)
[java] at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
[java] at java.lang.SecurityManager.checkAccept(SecurityManager.java:1157)
[java] at java.net.ServerSocket.implAccept(ServerSocket.java:457)
[java] at java.net.ServerSocket.accept(ServerSocket.java:421)
Run Code Online (Sandbox Code Playgroud)
端口号不断变化; 我假设它是客户端的端口号(服务器连接回客户端的位置?).那是对的吗?对于此分配,端口号上指定了限制:
您的客户端和服务器应使用Java安全管理器,并且您的项目必须包含每个策略文件的策略文件,这些文件定义了它们运行所需的权限.允许您的服务器和客户端使用2220-2230范围内的端口在localhost上相互联系.
我怎么能遵守这个限制?或者这仅适用于服务器侦听的端口?我认为如果我给出大于2231的端口的权限accept
和resolve
权限,我可以使它工作.但我不知道这是否违反了限制.
我有一个服务,要解析的域名来自不受信任的来源.最近,它因内存不足而崩溃.我缩小了可能的原因,并得出结论,它必须与最近的DNS请求流量有关.但是,该服务在解析域名后不存储任何内容,因此这似乎不太可能,但我尝试使用导致其解析域名的请求向我的服务发送垃圾邮件,以防万一.它确实死于此.然后,在得出代表我代码中没有存储内存的结论之后,我将代码缩小到了这个范围:
import java.math.*;
import java.net.*;
class A {
static {
try {
for (BigInteger i = BigInteger.ZERO; i==i; i = i.add(BigInteger.ONE))
Inet4Address.getByName("a"+i+".dog");
} catch (Exception e) {throw new RuntimeException(e);}
}
}
Run Code Online (Sandbox Code Playgroud)
我使用此行设置dnsmasq /etc/dnsmasq.conf
以使分辨率更快:
address=/dog/127.0.0.1
Run Code Online (Sandbox Code Playgroud)
起初我跑这个时,它存活了几天,所以看起来这不是问题.但后来我用我用来启动服务的脚本运行它,这启用了安全管理器,它崩溃了:
$ javac A.java && java -Xmx80m -Djava.security.manager A
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Could not find the main class: A. Program will exit.
Run Code Online (Sandbox Code Playgroud)
安全管理器使我的程序容易受到这种拒绝服务攻击.为什么?怎么解决?
$ java -version
java version "1.6.0_27"
OpenJDK Runtime Environment (IcedTea6 1.12.6) (Gentoo build 1.6.0_27-b27)
OpenJDK 64-Bit Server …
Run Code Online (Sandbox Code Playgroud) 我有一个带有自定义安全策略的 java 应用程序,当我尝试打开 100 个 udp 套接字时,出现异常:
java.net.SocketException: maximum number of DatagramSockets reached
Run Code Online (Sandbox Code Playgroud)
测试应用程序:
import java.net.DatagramSocket;
import java.net.Inet4Address;
import java.util.ArrayList;
import java.util.List;
public class Test {
static int basePortNum = 40000;
public static void main(String[] args) {
List<DatagramSocket> socks = new ArrayList<DatagramSocket>();
try{
for(int i = 0; i<100; i++){
socks.add(new DatagramSocket(basePortNum+i, Inet4Address.getByName("127.0.0.1")) );
System.out.println(i);
}
}catch(Exception e){
e.printStackTrace();
}finally{
for(java.net.DatagramSocket soc: socks){
soc.close();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果我在没有安全管理器的情况下启动它,它会创建所有 100 个套接字:
0
1
...
98
99
Run Code Online (Sandbox Code Playgroud)
但是如果我将这一行添加到 VM 参数中
-Djava.security.manager
Run Code Online (Sandbox Code Playgroud)
即使使用默认的安全策略它也会失败: …
嗨,SecurityManager 专家们;-)
我编写了一个小型插件框架,它使用单独的隔离类加载器加载插件。为了成功取消部署插件,重要的是要确保应用程序不保留对插件类加载器加载的类的引用。
Java 中有一个称为 shutdown hook 的功能,它允许客户端代码注册一个线程,该线程在 JVM 被请求关闭时执行。这意味着 JVM 可能会持有对插件类加载器加载的类的引用。
我的第一次尝试是安装一个拒绝添加关闭挂钩的 SecurityManager。这完全有效并拒绝所有添加关闭挂钩的尝试。有趣的是,我意识到,并不是插件本身想要添加关闭挂钩。SunFontManager
该插件只是通过加载字体来触发 AWT/Swing 内部机制(准确地说:) 。反过来,它又SunFontManager
添加了 shutdown hook,以便在 JVM 退出时执行一些内部处理。我不想否认插件加载字体(因为它必须这样做),并且我不想否认 Java 内部添加它们的东西。
对我来说,我似乎必须向代码授予比通常更多的权限(如果sun.*|java.*|javax.*
包位于堆栈跟踪中..uuuhmm...丑陋)。但这打破了安全框架的约定,该约定假定客户端代码不能比调用它的代码拥有更多的特权。
我如何区分不是插件代码而是 Java 内部想要做某事?或者有没有其他方法可以确保不会因为否认某些事情而破坏内部结构?
为了让事情更清楚,以下是我的应用程序中实际发生的情况。我安装了一个自定义 SecurityManager,它应该拒绝addShutdownHook
由插件直接执行,但如果作为 Java 内部类的副作用执行,则不应拒绝这些调用。
上下文: 调用: ---------------------------------------------------------- App类加载器应用程序 | PluginClassloader PluginObject.init() | AppClassloader Font.create() | AccessController.doPrivileged(...) { Runtime.addShutdownHook(...) }
SecurityManager 是使用System.setSecurityManager()
以下命令安装的:
@Override
public void checkPermission(java.security.Permission perm) {
if (perm.getName().equals("shutdownHooks")) {
if (threadContextClassLoaderIsPluginClassLoader()) {
throw new SecurityException("Installing shutdown hooks is not allowed.");
} …
Run Code Online (Sandbox Code Playgroud) 我只想在我的Java程序中读取和写入一些文件.所以我java.security.SecurityManager
用来管理这个,但似乎并不令人满意.
该Main.java
文件如下
import java.io.*;
import java.util.*;
public class Main {
static private final String INPUT = "in.txt";
public static void main(String args[]) throws Exception {
FileInputStream instream = null;
BufferedReader reader = new BufferedReader(new FileReader(INPUT));
String tempString = null;
while ((tempString = reader.readLine()) != null) {
System.out.println(tempString);
}
}
}
Run Code Online (Sandbox Code Playgroud)
和/opt/java.policy
下面的文件
grant {
permission java.io.FilePermission "./out.txt", "write";
};
Run Code Online (Sandbox Code Playgroud)
然后我跑了
java -Xss64m -Xms16m -Xmx512m -Djava.security.manager -Djava.security.policy=/opt/java.policy Main
Run Code Online (Sandbox Code Playgroud)
但是没有错误,输出就是这样in.txt
.我尝试了其他文件并获得了相同的结果.为什么会这样?
实施Java安全管理器会导致性能下降吗?
经过大量的搜索和反复试验后,我仍然无法确定是否需要安全管理器,如果需要,如何确定它是否可以工作。
启动服务器的代码:
Registry registry;
try {
System.setProperty("java.security.policyfile", "\\\\...\\security.policy");
if (System.getSecurityManager() == null) {
RMISecurityManager securityManager = new RMISecurityManager();
System.setSecurityManager(securityManager);
}
registry = LocateRegistry.createRegistry(port);
registry.bind(serviceName, remote);
System.out.println("RMI registry created.");
} catch (RemoteException e) {
//error means registry already exists
System.out.println("RMI registry already exists.");
}
System.setProperty("java.rmi.server.hostname", hostURL);
Naming.rebind(hostURL, remote);
Run Code Online (Sandbox Code Playgroud)
服务器上的错误消息:
D:\>java -jar Server.jar
RMI server starting up
RMI registry created.
Exception in thread "main" ...Exception: Unable to start the Remote Server Server[UnicastServerRef [liveRef: [...]]
at ServiceProvider.start(ServiceProvider.java:64)
at Server.main(Server.java:76)
Caused by: java.security.AccessControlException: access …
Run Code Online (Sandbox Code Playgroud) 我试图在F#中构建一个非常小的.NET应用程序.
它只需将一个小字符串转换为另一个字符串并将结果打印到控制台,如:
convert.exe myString ==>打印类似"myConvertedString"的内容
我使用dottrace来分析性能:
每次执行的运行时间> 500ms都太慢了.我可以做些什么来改善这个吗?
如果这次只需要第一次通话就没问题.
此致,forki
我正在编写一个程序,我想循环遍历几个配置文件,并在每个文件中调用一个以该文件名作为参数的类,并等待它完成.目前我在做:
for (int i = 1; i <= 3; i++){
String[] a = new String[1];
a[0] = "data/config" + i + ".xml";
edu.cwru.sepia.Main2.class.getMethod("main", String[].class).invoke(null, (Object)a);
}
Run Code Online (Sandbox Code Playgroud)
然而,发生的情况是该类只被调用一次,然后整个程序停止.我认为类中有一个退出行,但由于它是一个JAR文件,我无法确定,我无法编辑它.
我们假设是这样的; 我该如何解决这个问题呢?也就是说,在调用以exiting结束之后,我的外部循环方法继续,并再次使用下一个参数调用该类.
securitymanager ×12
java ×11
performance ×2
policy ×2
security ×2
.net ×1
dns ×1
f# ×1
java-11 ×1
java-io ×1
policyfiles ×1
rmi ×1
runtime ×1
sockets ×1
systemexit ×1