Casting interfaces

Interfaces

provide useful abstractability. You can have a class Foo to implement some interfaces, for example A, B and C. Some client codes can get a link of type A, others of type A, etc. Each is actually the same Foo object, but an interface showing only a narrow subset of functionality. Of course, the evil client code may try to pass the A link to Foo, then gain access to other functions. How to prevent this?

+4
source share
7 answers

This is called a "malicious action", and you can prevent it by having a shell that implements only the narrow interface that you want to open (by delegating a private link to an object that you would otherwise directly pass the client to evil).

However, if the client is not only evil, but also powerful, it can use reflection to still go to the hidden link.

+10
source

Normal inheritance will always allow this; there is nothing you can do about it. If you want to open some class as an interface, but hide other methods, use the Adapter template (google it)

+2
source

You can not. One way is to implement three proxy classes, one for implementing each interface, which redirects all calls to one instance of Foo.

+1
source

A person who commits a malicious action does this at his own peril and risk. In almost all cases, you can safely assume that the user will not use the object in accordance with the specified interface.

The only time you really need to use a proxy object is if you exposed the vulnerable security object to the vulnerable code. Otherwise, take the time to clearly document how the objects can be used and work under the assumption that this will be done.

+1
source

Hide the base object.

Say you have:

 public interface A { } public class B implements A { } 

Thus, interface A implements only a subset of the functionality of B. Effectively, it hides parts of B. Your question is how to stop the user from lowering A to B.

 B objectOfTypeB = (B)objectOfTypeA; // you don't want this 

So, do not give the user access to class B. If the user cannot import it, he cannot create an instance or refuse it. Thus, it forces you to use the interface and nothing more.

Change the above code to:

 /* Publicly accessable interface */ public interface A { } /* Class hidden inside the package. */ public class B implements A { } 

Then you can simply return function A, protected by the fact that the user cannot use B.

 /* Function that returns an A. */ public A foo() { /* ... */ return objectOfTypeB; } 
0
source

You can use the Facade class.

This class should wrap the delegate of the Foo class, and then set only the interface methods, for example A, and just send them to the delegate.

On the other hand, you can disable casting in Foo by declaring it private and have a public factory method that returns only the A interface (which is actually Foo). Thus, casting from other packages will not be possible (nevertheless, someone can play tricks with reflection).

0
source

There is no practical, non-invasive way to protect against this.

However, if your situation really requires this protection, use this utility class to create dynamic proxy classes (delegates) (adapted from Dynamic proxy classes - <50 lines of production code!).

This will ClassCastException at runtime if someone uses an attacker attempt. You can even conditionally select the code to disable it during production ( newInstance() just return the obj object as a "proxy").

DynamicProxy.java

 import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class DynamicProxy implements java.lang.reflect.InvocationHandler { private Object obj; public static Object newInstance(Object obj, Class<?>... interfaces) { if (interfaces == null || interfaces.length == 0) { throw new IllegalArgumentException("No interfaces"); } return java.lang.reflect.Proxy.newProxyInstance( obj.getClass().getClassLoader(), interfaces, new DynamicProxy(obj)); } private DynamicProxy(Object obj) { this.obj = obj; } public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { Object result; try { result = m.invoke(obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } catch (Exception e) { throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); } return result; } // ** DEMO CODE BELOW HERE ** interface A { void methodA(); } interface B { void methodB(); } static class Foo implements A, B { public void methodA() { System.out.println("A"); } public void methodB() { System.out.println("B"); } } public static void main(String[] args) { Foo foo = new Foo(); // implements both interfaces // calls foo methods, but only A methods A a = (A) DynamicProxy.newInstance(foo, A.class); // calls foo methods, but only B methods B b = (B) DynamicProxy.newInstance(foo, B.class); // calls foo methods, but only B methods A ab = (A) DynamicProxy.newInstance(foo, A.class, B.class); a.methodA(); b.methodB(); ab.methodA(); ((B) ab).methodB(); // ClassCastException: $Proxy0 cannot be cast to DynamicProxy$Foo ((Foo) a).methodA(); // ClassCastException: $Proxy1 cannot be cast to DynamicProxy$Foo ((Foo) b).methodB(); // ClassCastException: $Proxy0 cannot be cast to DynamicProxy$B ((B) a).methodB(); // ClassCastException: $DynamicProxy1 cannot be cast to DynamicProxy$A ((A) b).methodA(); } } 
0
source

Source: https://habr.com/ru/post/1306672/


All Articles