Jalankan kode tidak tepercaya di utasnya sendiri. Ini misalnya mencegah masalah dengan loop tak terbatas dan semacamnya, dan membuat langkah selanjutnya lebih mudah. Minta utas utama menunggu utas selesai, dan jika terlalu lama, matikan dengan Thread.stop. Thread.stop tidak digunakan lagi, tetapi karena kode tidak tepercaya seharusnya tidak memiliki akses ke sumber daya apa pun, maka akan aman untuk membunuhnya.
Setel SecurityManager di Thread tersebut. Buat subclass SecurityManager yang menggantikan checkPermission (Permission perm) untuk hanya menampilkan SecurityException untuk semua izin kecuali beberapa yang dipilih. Ada daftar metode dan izin yang mereka butuhkan di sini: Izin di Java TM 6 SDK .
Gunakan ClassLoader kustom untuk memuat kode tidak tepercaya. Pemuat kelas Anda akan dipanggil untuk semua kelas yang digunakan kode tidak tepercaya, sehingga Anda dapat melakukan hal-hal seperti menonaktifkan akses ke setiap kelas JDK. Hal yang harus dilakukan adalah memiliki daftar putih kelas JDK yang diizinkan.
Anda mungkin ingin menjalankan kode tidak tepercaya di JVM terpisah. Meskipun langkah-langkah sebelumnya akan membuat kode aman, ada satu hal menjengkelkan yang masih dapat dilakukan oleh kode yang diisolasi: mengalokasikan memori sebanyak mungkin, yang menyebabkan footprint yang terlihat dari aplikasi utama bertambah.
JSR 121: Spesifikasi API Isolasi Aplikasi dirancang untuk mengatasi hal ini, tetapi sayangnya belum ada penerapannya.
Ini adalah topik yang cukup mendetail, dan saya kebanyakan menulis ini semua dari atas kepala saya.
Tapi bagaimanapun, beberapa kode yang tidak sempurna, gunakan dengan risiko Anda sendiri, mungkin buggy (pseudo):
ClassLoader
class MyClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name is white-listed JDK class) return super.loadClass(name);
return findClass(name);
}
@Override
public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String name) {
}
}
Manajer keamanan
class MySecurityManager extends SecurityManager {
private Object secret;
public MySecurityManager(Object pass) { secret = pass; }
private void disable(Object pass) {
if (pass == secret) secret = null;
}
}
Benang
class MyIsolatedThread extends Thread {
private Object pass = new Object();
private MyClassLoader loader = new MyClassLoader();
private MySecurityManager sm = new MySecurityManager(pass);
public void run() {
SecurityManager old = System.getSecurityManager();
System.setSecurityManager(sm);
runUntrustedCode();
sm.disable(pass);
System.setSecurityManager(old);
}
private void runUntrustedCode() {
try {
loader.loadClass("customclassname")
.getMethod("main", String[].class)
.invoke(null, new Object[]{...});
} catch (Throwable t) {}
}
}
Thread.stop
akan menyebabkan masalah pada kode pustaka Java. Demikian pula, kode pustaka Java akan membutuhkan izin. Jauh lebih baik untuk memungkinkanSecurityManager
penggunaanjava.security.AccessController
. Pemuat kelas mungkin juga harus mengizinkan akses ke kelas kode pengguna itu sendiri.System.setSecurityManager(…)
akan mempengaruhi seluruh JVM, tidak hanya thread yang memanggil metode tersebut, gagasan untuk membuat keputusan keamanan berdasarkan thread telah ditinggalkan ketika Java dialihkan dari 1.0 ke 1.1. Saat ini diketahui bahwa kode tidak tepercaya dapat memanggil kode tepercaya dan sebaliknya, terlepas dari utas mana yang menjalankan kode tersebut. Tidak ada pengembang yang harus mengulangi kesalahan tersebut.Jelas skema seperti itu menimbulkan segala macam masalah keamanan. Java memiliki kerangka keamanan yang ketat, tetapi tidak sepele. Kemungkinan mengacaukannya dan membiarkan pengguna yang tidak berhak mengakses komponen sistem vital tidak boleh diabaikan.
Selain peringatan itu, jika Anda mengambil input pengguna dalam bentuk kode sumber, hal pertama yang perlu Anda lakukan adalah mengompilasinya ke bytecode Java. AFIAK, ini tidak dapat dilakukan secara native, jadi Anda harus melakukan panggilan sistem ke javac, dan mengompilasi kode sumber ke bytecode pada disk. Berikut tutorial yang bisa digunakan sebagai titik awal untuk ini. Sunting : seperti yang saya pelajari di komentar, Anda sebenarnya dapat mengkompilasi kode Java dari sumber asli menggunakan javax.tools.JavaCompiler
Setelah Anda memiliki JVM bytecode, Anda dapat memuat ke dalam JVM menggunakan ClassLoader ini defineClass fungsi. Untuk mengatur konteks keamanan untuk kelas yang dimuat ini, Anda perlu menentukan ProtectionDomain . Konstruktor minimal untuk ProtectionDomain membutuhkan CodeSource dan PermissionCollection . PermissionCollection adalah objek penggunaan utama Anda di sini- Anda dapat menggunakannya untuk menentukan izin yang tepat yang dimiliki kelas yang dimuat. Izin ini pada akhirnya harus diberlakukan oleh AccessController JVM .
Ada banyak kemungkinan titik kesalahan di sini, dan Anda harus sangat berhati-hati untuk sepenuhnya memahami semuanya sebelum menerapkan apa pun.
sumber
The Java-Sandbox adalah perpustakaan untuk mengeksekusi kode Java dengan seperangkat terbatas perizinan. Ini dapat digunakan untuk mengizinkan akses hanya ke sekumpulan kelas dan sumber daya yang terdaftar dalam daftar putih. Tampaknya tidak dapat membatasi akses ke metode individu. Ini menggunakan sistem dengan pemuat kelas khusus dan pengelola keamanan untuk mencapai ini.
Saya belum pernah menggunakannya tetapi tampilannya dirancang dengan baik dan didokumentasikan dengan cukup baik.
@waqas telah memberikan jawaban yang sangat menarik yang menjelaskan bagaimana ini mungkin untuk Anda terapkan. Tetapi jauh lebih aman untuk menyerahkan kode keamanan yang kritis dan kompleks kepada para ahli.
Perhatikan bahwa proyek tersebut belum diperbarui sejak 2013 dan pembuatnya menggambarkannya sebagai "eksperimental". Halaman beranda telah menghilang tetapi entri Source Forge tetap ada.
Kode contoh diadaptasi dari situs web proyek:
SandboxService sandboxService = SandboxServiceImpl.getInstance(); // Configure context SandboxContext context = new SandboxContext(); context.addClassForApplicationLoader(getClass().getName()); context.addClassPermission(AccessType.PERMIT, "java.lang.System"); // Whithout this line we get a SandboxException when touching System.out context.addClassPermission(AccessType.PERMIT, "java.io.PrintStream"); String someValue = "Input value"; class TestEnvironment implements SandboxedEnvironment<String> { @Override public String execute() throws Exception { // This is untrusted code System.out.println(someValue); return "Output value"; } }; // Run code in sandbox. Pass arguments to generated constructor in TestEnvironment. SandboxedCallResult<String> result = sandboxService.runSandboxed(TestEnvironment.class, context, this, someValue); System.out.println(result.get());
sumber
Untuk mengatasi masalah dalam jawaban yang diterima di mana kustom
SecurityManager
akan berlaku untuk semua utas di JVM, bukan pada basis per utas, Anda dapat membuat ubahsuaianSecurityManager
yang dapat diaktifkan / dinonaktifkan untuk utas tertentu sebagai berikut:import java.security.Permission; public class SelectiveSecurityManager extends SecurityManager { private static final ToggleSecurityManagerPermission TOGGLE_PERMISSION = new ToggleSecurityManagerPermission(); ThreadLocal<Boolean> enabledFlag = null; public SelectiveSecurityManager(final boolean enabledByDefault) { enabledFlag = new ThreadLocal<Boolean>() { @Override protected Boolean initialValue() { return enabledByDefault; } @Override public void set(Boolean value) { SecurityManager securityManager = System.getSecurityManager(); if (securityManager != null) { securityManager.checkPermission(TOGGLE_PERMISSION); } super.set(value); } }; } @Override public void checkPermission(Permission permission) { if (shouldCheck(permission)) { super.checkPermission(permission); } } @Override public void checkPermission(Permission permission, Object context) { if (shouldCheck(permission)) { super.checkPermission(permission, context); } } private boolean shouldCheck(Permission permission) { return isEnabled() || permission instanceof ToggleSecurityManagerPermission; } public void enable() { enabledFlag.set(true); } public void disable() { enabledFlag.set(false); } public boolean isEnabled() { return enabledFlag.get(); } }
ToggleSecurirtyManagerPermission
hanyalah implementasi sederhanajava.security.Permission
untuk memastikan bahwa hanya kode resmi yang dapat mengaktifkan / menonaktifkan pengelola keamanan. Ini terlihat seperti ini:import java.security.Permission; public class ToggleSecurityManagerPermission extends Permission { private static final long serialVersionUID = 4812713037565136922L; private static final String NAME = "ToggleSecurityManagerPermission"; public ToggleSecurityManagerPermission() { super(NAME); } @Override public boolean implies(Permission permission) { return this.equals(permission); } @Override public boolean equals(Object obj) { if (obj instanceof ToggleSecurityManagerPermission) { return true; } return false; } @Override public int hashCode() { return NAME.hashCode(); } @Override public String getActions() { return ""; } }
sumber
Sudah sangat terlambat untuk memberikan saran atau solusi, tetapi saya masih menghadapi masalah serupa, lebih berorientasi pada penelitian. Pada dasarnya saya berusaha memberikan bekal dan evaluasi otomatis untuk tugas pemrograman mata kuliah Java di platform e-learning.
Saya tahu ini terdengar cukup rumit dan banyak tugas, tetapi Oracle Virtual Box sudah menyediakan Java API untuk membuat atau mengkloning mesin virtual secara dinamis. https://www.virtualbox.org/sdkref/index.html (Catatan, bahkan VMware juga menyediakan API untuk melakukan hal yang sama)
Dan untuk ukuran minimum dan konfigurasi distribusi Linux Anda dapat merujuk ke yang ini di sini http://www.slitaz.org/en/ ,
Jadi sekarang jika siswa mengacaukan atau mencoba melakukannya, mungkin dengan memori atau sistem file atau jaringan, soket, maksimal dia dapat merusak VM miliknya sendiri.
Juga secara internal ke dalam VM ini, Anda dapat memberikan keamanan tambahan seperti Sandbox (manajer keamanan) untuk Java atau membuat akun khusus pengguna di Linux dan dengan demikian membatasi akses.
Semoga ini membantu !!
sumber
Berikut solusi aman untuk masalah ini:
https://svn.code.sf.net/p/loggifier/code/trunk/de.unkrig.commons.lang/src/de/unkrig/commons/lang/security/Sandbox.java
package de.unkrig.commons.lang.security; import java.security.AccessControlContext; import java.security.Permission; import java.security.Permissions; import java.security.ProtectionDomain; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; import de.unkrig.commons.nullanalysis.Nullable; /** * This class establishes a security manager that confines the permissions for code executed through specific classes, * which may be specified by class, class name and/or class loader. * <p> * To 'execute through a class' means that the execution stack includes the class. E.g., if a method of class {@code A} * invokes a method of class {@code B}, which then invokes a method of class {@code C}, and all three classes were * previously {@link #confine(Class, Permissions) confined}, then for all actions that are executed by class {@code C} * the <i>intersection</i> of the three {@link Permissions} apply. * <p> * Once the permissions for a class, class name or class loader are confined, they cannot be changed; this prevents any * attempts (e.g. of the confined class itself) to release the confinement. * <p> * Code example: * <pre> * Runnable unprivileged = new Runnable() { * public void run() { * System.getProperty("user.dir"); * } * }; * * // Run without confinement. * unprivileged.run(); // Works fine. * * // Set the most strict permissions. * Sandbox.confine(unprivileged.getClass(), new Permissions()); * unprivileged.run(); // Throws a SecurityException. * * // Attempt to change the permissions. * { * Permissions permissions = new Permissions(); * permissions.add(new AllPermission()); * Sandbox.confine(unprivileged.getClass(), permissions); // Throws a SecurityException. * } * unprivileged.run(); * </pre> */ public final class Sandbox { private Sandbox() {} private static final Map<Class<?>, AccessControlContext> CHECKED_CLASSES = Collections.synchronizedMap(new WeakHashMap<Class<?>, AccessControlContext>()); private static final Map<String, AccessControlContext> CHECKED_CLASS_NAMES = Collections.synchronizedMap(new HashMap<String, AccessControlContext>()); private static final Map<ClassLoader, AccessControlContext> CHECKED_CLASS_LOADERS = Collections.synchronizedMap(new WeakHashMap<ClassLoader, AccessControlContext>()); static { // Install our custom security manager. if (System.getSecurityManager() != null) { throw new ExceptionInInitializerError("There's already a security manager set"); } System.setSecurityManager(new SecurityManager() { @Override public void checkPermission(@Nullable Permission perm) { assert perm != null; for (Class<?> clasS : this.getClassContext()) { // Check if an ACC was set for the class. { AccessControlContext acc = Sandbox.CHECKED_CLASSES.get(clasS); if (acc != null) acc.checkPermission(perm); } // Check if an ACC was set for the class name. { AccessControlContext acc = Sandbox.CHECKED_CLASS_NAMES.get(clasS.getName()); if (acc != null) acc.checkPermission(perm); } // Check if an ACC was set for the class loader. { AccessControlContext acc = Sandbox.CHECKED_CLASS_LOADERS.get(clasS.getClassLoader()); if (acc != null) acc.checkPermission(perm); } } } }); } // -------------------------- /** * All future actions that are executed through the given {@code clasS} will be checked against the given {@code * accessControlContext}. * * @throws SecurityException Permissions are already confined for the {@code clasS} */ public static void confine(Class<?> clasS, AccessControlContext accessControlContext) { if (Sandbox.CHECKED_CLASSES.containsKey(clasS)) { throw new SecurityException("Attempt to change the access control context for '" + clasS + "'"); } Sandbox.CHECKED_CLASSES.put(clasS, accessControlContext); } /** * All future actions that are executed through the given {@code clasS} will be checked against the given {@code * protectionDomain}. * * @throws SecurityException Permissions are already confined for the {@code clasS} */ public static void confine(Class<?> clasS, ProtectionDomain protectionDomain) { Sandbox.confine( clasS, new AccessControlContext(new ProtectionDomain[] { protectionDomain }) ); } /** * All future actions that are executed through the given {@code clasS} will be checked against the given {@code * permissions}. * * @throws SecurityException Permissions are already confined for the {@code clasS} */ public static void confine(Class<?> clasS, Permissions permissions) { Sandbox.confine(clasS, new ProtectionDomain(null, permissions)); } // Code for 'CHECKED_CLASS_NAMES' and 'CHECKED_CLASS_LOADERS' omitted here. }
Tolong beri komentar anda!
CU
Arno
sumber
Anda mungkin perlu menggunakan SecurityManger dan / atau AccessController kustom . Untuk detail selengkapnya, lihat Arsitektur Keamanan Java dan dokumentasi keamanan lainnya dari Sun.
sumber