当字段类型未知时,反射改进以访问字段秘密

时间:2014-02-20 14:20:11

标签: java security reflection refactoring exploit


我正在学习安全性并着眼于明确存储机密。

当我检索私有字段的内容时,它返回一个Object。我的错误代码正确地假设并将Object转换为int,但是如果我将字段类型从int secretInt = 42;更改/解析为String secretInt = (new Integer(42).intValue()).tostring,则Mal代码会失败。

编辑:异常包装(new Integer(42).intValue()).tostring由自动解析器创建,不是由程序员编写的。

如何为Mal代码添加健壮性,以便删除返回类型的假设。这可能吗?我需要将此值用作int参数。

编辑:'字符串'是一个示例,但解析器可能选择的数据结构与byte [],char []不合适。

这是我的不合规代码。

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

这是我的恶意代码。

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

修改

而不是从readPrivateField()转换(int)。相反,我提取字符串值String.valueOf(Object)Object.toString()。然后我可以将该字符串作为带有new Integer(stringValue)的int参数传递。

HOWEVER:

如果解析器选择将secretInt表示为byte []类型,则字符串值将是疯狂的,并且将错误地输入错误代码。有人建议对此产生稳健性吗?

3 个答案:

答案 0 :(得分:0)

Field.get()的返回类型是一个Object。如果你需要知道它的类,你可以调用Field.getType(),但通常你不需要知道类型,只需要知道所包含的信息。

你可以做到

 String secret = "42";

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

不要使用Integer来比较值,因为这会比较对象,而不是它们的值。


较短的实施

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

顺便说一句:“对于那些阅读过银河系漫游指南的人来说,如果你将6乘以9,你会得到什么?”

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

打印

42

答案 1 :(得分:0)

您可以随时使用:

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

为了避免关心类型是什么,总是给你一个字符串。

答案 2 :(得分:0)

CREDIT: Peter Lawrey

如果你知道答案是不恰当的,那么在代码中一般不能这样做。您需要读取isSecretInt的字节代码以了解它是如何完成的,为此人类是最简单的解决方案;) -