Использование менеджера безопасности с отражением при доступе к файлу jar
После реализации моей платформы, позволяющей динамически загружать jar-файлы с помощью рефлексии, я столкнулся с проблемой безопасности. Файл jar может быть "опасным" и содержать код, который может на что-то повлиять, поэтому я сталкиваюсь на SO с использованием SecurityManager
,
Я загружаю файл jar следующим образом (пример файла с жестким кодом):
URLClassLoader clsLoader = URLClassLoader
.newInstance(new URL[] { new URL("file:/C://Temp/SettingsApp.jar") });
Class<?> cls = clsLoader.loadClass("iezon.app.SettingsApp");
JPanel settingsApp = (JPanel) cls.newInstance();
Я пытался использовать SecurityManager
вот так:
try {
SecurityManager sm = new SecurityManager();
Object context = sm.getSecurityContext();
sm.checkPermission(new AllPermission(), context);
settingsAppPanel = (JPanel) cls.newInstance();
} catch (AccessControlException e) {
e.printStackTrace();
}
Тест с AllPermission()
работает и дает мне это исключение:
java.security.AccessControlException: доступ запрещен ("java.security.AllPermission" "" "")
Однако я не могу найти какую-либо информацию о том, как связать файл jar с этим менеджером безопасности, а не с текущей платформой. Я просто не хочу, чтобы файл jar мог открывать сокеты и т. Д. Без предварительного запроса разрешений, которые затем может принять пользователь.
Я наткнулся через BasicPermission
однако это абстрактный класс, и его нельзя создавать как AllPermission
и также я не могу найти какую-либо информацию о приближении к этому. Любая помощь будет оценена!
1 ответ
Как Holger в комментариях, единственный способ реализовать использование диспетчера безопасности - это динамически создавать политики. Поэтому, когда разработчик загружает новое приложение в магазин приложений, ему предоставляется набор политик для объявления того, что его приложение использует. В приложении это передается пользователю, который просит его подтвердить эту политику (на свой страх и риск, если он включает сокеты и т. Д.), А затем создается политика, и приложение может работать:
if (!app.policyIsAgreedTo()) {
if(readPolicy(app).get(0).equalsIgnoreCase("grant {")) {
app.setPolicy(true);
} else {
throw new Exception("App policy has not been agreed to.");
}
}
if (app.policyIsAgreedTo()) {
System.setProperty("java.security.policy", "file:/C:/Temp/" + app.getName() + ".policy");
System.setSecurityManager(new SecurityManager());
JPanel panel = (JPanel) app.getObject().newInstance();
System.setSecurityManager(null);
return panel;
}
throw new Exception("App policy has not been agreed to.");
Политика создается так:
public static void createPolicy(ArrayList<String> policies, App app) {
try {
FileWriter fileWriter =
new FileWriter("C:/Temp/" + app.getName() + ".policy");
BufferedWriter bufferedWriter =
new BufferedWriter(fileWriter);
bufferedWriter.write("grant {");
bufferedWriter.newLine();
for(String policy : policies) {
bufferedWriter.write(" permission java.lang.RuntimePermission \"" + policy + "\";");
bufferedWriter.newLine();
}
bufferedWriter.write("};");
bufferedWriter.close();
} catch(IOException ex) {
ex.printStackTrace();
}
}
Приложение выполняет API-вызов в магазине приложений, собирая разрешения, необходимые приложению, а затем просто createPolicy()
вызывается с разрешениями в ArrayList, т.е.
new ArrayList<String>() {{ add("setSecurityManager"); }}; // Etc...