Java 防止在 class 之外调用私有或受保护的方法
Java prevent calling private or protected methods outside of class
假设我创建了一个名为 Foo
的 Java 库,并且我在该库中有一个名为 Bar
的 class。让我们进一步假设在 Bar
class 中我有一个私有方法,称为 fooBar
.
public class Bar {
//...
private Object fooBar() {
//Do something
}
//...
}
一个人可以运行这个方法没有任何困难用class写的代码,像这样:
public static Object runMethod(Object object, String methodName) {
Method method = object.getClass().getDeclaredMethod(methodName);
method.setAccessible(true);
return method.invoke(object);
}
但是,让我们假设我们打算为 fooBar
阻止这种习惯。我们怎么能做那样的事情呢?我们是否应该从某个地方获取堆栈跟踪并检查调用它的位置?还是我们应该做点别的?
您需要一名安全管理员...
https://docs.oracle.com/javase/tutorial/essential/environment/security.html
A security manager is an object that defines a security policy for an
application. This policy specifies actions that are unsafe or
sensitive. Any actions not allowed by the security policy cause a
SecurityException to be thrown. An application can also query its
security manager to discover which actions are allowed.
它支持禁止setAccessible()
通过反射调用私有和受保护的方法。
我想如果你想走极端,你可以像这样获得堆栈跟踪:
public class Bar {
//...
private Object fooBar() {
try {
throw new CheckIfCalledFromMethodException();
} catch(CheckIfCalledFromMethodException e) {
//here you have access to stack trace in your exception
}
//Do something
}
//...
}
我整理了一个简单的场景,它检查调用 class 的 second
实例是同一个对象还是其他对象。
public class StackTraceTest {
private void execute() {
try {
throw new Exception();
} catch (Exception e) {
/*for(int i = 0; i < e.getStackTrace().length; i++) {
StackTraceElement stackTraceElement = e.getStackTrace()[i];
System.out.println(stackTraceElement.getFileName());
}
System.out.println("");
e.printStackTrace();*/
if(!e.getStackTrace()[1].getFileName().equals(StackTraceTest.class.getSimpleName() + ".java")) {
throw new IllegalAccessError("Illegal Access.");
}
}
}
public void executeExternal() {
this.execute();
}
}
和
public class AccsessorTest {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
StackTraceTest stackTraceTest = new StackTraceTest();
stackTraceTest.executeExternal();
System.out.println("Accessed from within other method in class.");
System.out.println("");
Class<?> clazz = StackTraceTest.class;
Method method = clazz.getDeclaredMethod("execute");
method.setAccessible(true);
System.out.println("Accessing through reflection...");
method.invoke(stackTraceTest);
}
}
然后我得到
Accessed from within other method in class.
Reflection test start.
Accessing through reflection...
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at stacktracetest.another.AccsessorTest.main(AccsessorTest.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: java.lang.IllegalAccessError: Illegal Access.
at stacktracetest.StackTraceTest.execute(StackTraceTest.java:18)
... 10 more
所以我想可以用堆栈跟踪元素魔法来检查,但你应该检查这是否真的有效,这非常粗糙,我刚刚把它放在一起。
假设我创建了一个名为 Foo
的 Java 库,并且我在该库中有一个名为 Bar
的 class。让我们进一步假设在 Bar
class 中我有一个私有方法,称为 fooBar
.
public class Bar {
//...
private Object fooBar() {
//Do something
}
//...
}
一个人可以运行这个方法没有任何困难用class写的代码,像这样:
public static Object runMethod(Object object, String methodName) {
Method method = object.getClass().getDeclaredMethod(methodName);
method.setAccessible(true);
return method.invoke(object);
}
但是,让我们假设我们打算为 fooBar
阻止这种习惯。我们怎么能做那样的事情呢?我们是否应该从某个地方获取堆栈跟踪并检查调用它的位置?还是我们应该做点别的?
您需要一名安全管理员...
https://docs.oracle.com/javase/tutorial/essential/environment/security.html
A security manager is an object that defines a security policy for an application. This policy specifies actions that are unsafe or sensitive. Any actions not allowed by the security policy cause a SecurityException to be thrown. An application can also query its security manager to discover which actions are allowed.
它支持禁止setAccessible()
通过反射调用私有和受保护的方法。
我想如果你想走极端,你可以像这样获得堆栈跟踪:
public class Bar {
//...
private Object fooBar() {
try {
throw new CheckIfCalledFromMethodException();
} catch(CheckIfCalledFromMethodException e) {
//here you have access to stack trace in your exception
}
//Do something
}
//...
}
我整理了一个简单的场景,它检查调用 class 的 second
实例是同一个对象还是其他对象。
public class StackTraceTest {
private void execute() {
try {
throw new Exception();
} catch (Exception e) {
/*for(int i = 0; i < e.getStackTrace().length; i++) {
StackTraceElement stackTraceElement = e.getStackTrace()[i];
System.out.println(stackTraceElement.getFileName());
}
System.out.println("");
e.printStackTrace();*/
if(!e.getStackTrace()[1].getFileName().equals(StackTraceTest.class.getSimpleName() + ".java")) {
throw new IllegalAccessError("Illegal Access.");
}
}
}
public void executeExternal() {
this.execute();
}
}
和
public class AccsessorTest {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
StackTraceTest stackTraceTest = new StackTraceTest();
stackTraceTest.executeExternal();
System.out.println("Accessed from within other method in class.");
System.out.println("");
Class<?> clazz = StackTraceTest.class;
Method method = clazz.getDeclaredMethod("execute");
method.setAccessible(true);
System.out.println("Accessing through reflection...");
method.invoke(stackTraceTest);
}
}
然后我得到
Accessed from within other method in class.
Reflection test start.
Accessing through reflection...
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at stacktracetest.another.AccsessorTest.main(AccsessorTest.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: java.lang.IllegalAccessError: Illegal Access.
at stacktracetest.StackTraceTest.execute(StackTraceTest.java:18)
... 10 more
所以我想可以用堆栈跟踪元素魔法来检查,但你应该检查这是否真的有效,这非常粗糙,我刚刚把它放在一起。