Pergunta


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?

Foi útil?

Solução 3

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 ;) –

Outras dicas

The return type of Field.get() is an Object. If you need to know its class you can call Field.getType() but usually you don't need to know the type, only the information contained.

You could just do

 String secret = "42";

or

@Override
public boolean isSecretInt(int check) {
    return check / 6.0 == 7;
}

Don't use Integer to compare values, as this compare objects, not their values.


A shorter implementation

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);
     }
}

BTW: "What do you get if you multiply 6 by 9", for those who have read the Hitchhiker's Guide to the Galaxy.

System.out.println(Integer.toString(6 * 9, 13));

prints

42

;)

You can always use:

String value = String.valueOf(field.get(o));

To avoid caring what the type is and always give you a String.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top