Search code examples
javasecurityreflectionrefactoringexploit

Reflection improvements to access field secret, when field type is unknown



I am learning about Security and looking at storing secrets in the clear.

When I retrieve the contents of a private field, it returns an Object. My mal code correctly assumes and casts the Object as an int, however if I change/parse the field type from int secretInt = 42; to String secretInt = (new Integer(42).intValue()).tostring the Mal code fails miserably.

EDIT: The unusual wrapping (new Integer(42).intValue()).tostring is created by a automated parser, it is not written by a programmer.

how can I add robustness to Mal code so the assumption of the returned type is removed. Is this possible? I need to use this value as int param.

EDIT: 'String' is one example but the parser may choose a data-structure as suitably-inappropriate as byte[], char[].

This is my non-compliant code.

public final class SecretInClear implements Check4SecretsInClear {

    //Non-Compliant: Secret int stored in Clear.
    private final int secretInt = 42;

    @Override
    public boolean isSecretInt(int check) {
        return (check == secretInt);
    }
}

This is my mal code.

    public class ReadClearSecret implements Tester {

    //Example of running
    public static void main(String[] args) {
        String testResult = new ReadClearSecret().test(new SecretInClear());
        System.out.println(testResult);
    }

    private Object readPrivateField(Object o, String fieldName) {
        try {
            Field field = o.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(o);
        } catch(Exception e) {
            throw new IllegalArgumentExecption(e);
    }
     
    
    @Override
    public String test(final Object secretChecks) {
        final Check4SecretsInClear check4SecretsInClear = (Check4SecretsInClear)secretChecks;
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("class:").
        append(check4SecretsInClear.getClass().getSimpleName());

        boolean bSecretInt = false;
        String s = "";
        try {
            int secretInt = (Integer)readPrivateField(check4SecretsInClear,"secretInt"); //<<< HERE! It's cast as an integer!!!
                                                  
            bSecretInt = check4SecretsInClear.isSecretInt(secretInt); //<<< HERE! Param must be an int.
        } catch (ClassCastException e) {
            s = "," + e.getClass().getSimpleName();
        } finally {
            stringBuilder.append(" int:").append(bSecretInt).append(s);
            s = "";
        }
        return stringBuilder.toString();
    }
}

EDIT:

Instead of casting (int) from readPrivateField(). Instead I extract the string value String.valueOf(Object) or Object.toString(). I can then pass that string as a int param with new Integer(stringValue).

HOWEVER:

If the parser chooses to represent secretInt as type byte[] the string value will be nuts and the mal code will be pwned. Any suggest to produce robustness against this?


Solution

  • CREDIT: Peter Lawrey

    If it is suitably inappropriate you know the answer, it can't be don't generically in code. You need to read the byte code of isSecretInt to see how it is done, and for that a human is the simplest solution ;) –