Tuesday, May 29, 2018

Java SecurityManager - how to ensure a method is run only by another method?

Leave a Comment

I want B to be run only by the private method A#getSensitiveData() that uses or does some processing on sensitive data (example: cryptographic keys, national id, whatever).

public final class A{     private transient final B sensitiveHolder; //set at Constructor     public A(B sensitiveHolder){         this.sensitiveHolder = sensitiveHolder;     }     private final byte[] getSensitiveData(){         return sensitiveHolder.getSensitiveData();     } }  public final class B{     private transient final byte[] sensitiveData;//encrypt and set at Constructor     public final byte[] getSensitiveData(){         //check if it is run by A#getSensitiveData(); if it is, decrypt by DEK and give plaintext.     } } 

Please take into account that the code would be obfuscated, so please refrain from putting in any package names as String.

What must I write with SecurityManager#checkPrivilege() and AccessController.doPrivileged() before I can achieve such an effect?

EDIT: Obviously this is different because the so called "answer" does not contain any CODE. WORKING CODE is worth infinitely more than "oh, just do this and that".

2 Answers

Answers 1

You could do something like this:

private boolean verify(final StackTraceElement e[]) {     boolean doNext = false;     for (final StackTraceElement s : e) {         if (doNext && s.getClassName().equals("A") && s.getMethodName().equals("getSensitiveData"))             return true;         doNext = s.getMethodName().equals("getStackTrace");     }     return false; } 

And to call the method:

public final byte[] getSensitiveData(StackTraceElement e[]){     if (verify(e)) {         // Do something good     } } 

In your A class call your B class like this:

return sensitiveHolder.getSensitiveData(Thread.currentThread().getStackTrace()); 

I don't know if this is what you need or it is near that. You could play around the values in the equals section of the if. I got and modified the example from this site.

Answers 2

If you're able to use JDK 9+, which introduces StackWalker, this sort of thing might work for you. This technique seems to supersede use of sun.reflect.Reflection#getCallerClass(int). (I hope you weren't counting on a SecurityManager-related answer.)

package asdf;  import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test;  import java.util.EnumSet; import java.util.List; import java.util.stream.Collectors;  public class Asdf {      @Test     public void what() {         get();     }      void get() {         StackWalker.StackFrame stackFrame =                 StackWalker.getInstance(EnumSet.of(StackWalker.Option.RETAIN_CLASS_REFERENCE))                         .walk(stream -> {                             List<StackWalker.StackFrame> stackFrames = stream.collect(Collectors.toList());                             return stackFrames.get(1);                         });         Assertions.assertEquals(Asdf.class, stackFrame.getDeclaringClass());         Assertions.assertEquals("what", stackFrame.getMethodName());         Assertions.assertEquals(0, stackFrame.getMethodType().parameterCount());     } } 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment