I recently stumbled over some problem of not being able to pass data the way I am used to.
Let's asume we create a provider class, that is instantiated and called by another consumer class which we can not modify. The provider provides the consumer with some instance of an object, that requires sensitive data. Clearly it is a bad practice to hard-code this data into our provider class. And in my case this sensitive data is generated at runtime and can not be hard-coded.
My idea was to give that provider class a private static field, a setter for that field and no getter. Now even if an instance of that provider class is created, we do not have access to that private static field, only the provider class itself can read it.
Let's provide some code. Asume we have the following Consumer class and Provider interface:
Consumer
public class Consumer {
private final Class<? extends ProviderInterface> clazz;
public Consumer(Class<? extends ProviderInterface> clazz) {
this.clazz = clazz;
}
public void providerToSystemOut() throws IllegalAccessException, InstantiationException {
System.out.println(clazz.newInstance().call().toString());
}
}
ProviderInterface
public interface ProviderInterface {
public Object call();
}
The Consumer only accepts the class of the consumer as parameter. So we do not can create that class ourselves to provide the sensitive data.
To pass our sensitive data we create the following provider and main:
Provider
public class Provider implements ProviderInterface {
private static Object data = null;
public static void setData(Object data) {
Provider.data = data;
}
public Object call() {
String str;
if (data != null && (str = data.toString()).length() > 3) {
Object object = "successfully received/processed sensitive data: "
+ str.substring(0, 3)
+ str.substring(3).replaceAll(".", "*");
data = null;
return object;
} else {
data = null;
return "not enough data provided";
}
}
}
Main
public class Main {
public static void main(String[] args) {
Provider.setData("sensitive data");
try {
new Consumer(Provider.class).providerToSystemOut();
} catch (Exception e) {
e.printStackTrace();
}
}
}
My Question
This code works totally fine and seems to be secure. But I want to be sure if this is the best way to deal with this problem. Is the way I used a good practice? Is it secure? Is there some easy way for someone to get the sensitive data? If it may not be the best way, what would be better to do?
Some background
I faced this problem when dealing with selenide. Normally selenide creates its WebDriver instances itself. To provide it with a custom WebDriver, a Provider class is needed. Selenide than has a system property for the class name of that provider and uses this String to create an instance of the custom provider and to call the method which provides selenide with the WebDriver.