Есть ли способ получить доступ к частному методу во внутреннем классе с отражением или без него?

Я пытаюсь сделать простой пример пользовательской и банковской программы, где вы должны гарантировать, что деньги не могут быть обмануты кем-то, кто может добавлять, наследовать, реализовывать текущие существующие классы, но не может редактировать первоначальные. Вот и спрашиваю, можно ли как-то установить баланс чьего-то счета без предусмотренной функции перевода денег.

Я пытался использовать отражение, но у вас должны быть общедоступные конструкторы, чтобы создать объект, для которого вы вызываете частные методы, но, поскольку все является частным, я не могу его вызвать.

public class Bank {
    private static Bank ourInstance = new Bank();
    public static Bank getInstance() {
        return ourInstance;
    }

    private Bank() {}

    public boolean requestTransfer(User user1, User user2, double amount) {
        BankAccount ba1 = (BankAccount) user1.getBankAccount();
        BankAccount ba2 = (BankAccount) user2.getBankAccount();
        if (!(hasAccount(ba1) && hasAccount(ba2)))
            return false;

        if (ba1.getBalance() >= amount)
        {
            ba1.setBalance(ba1.getBalance() - amount);
            ba2.setBalance(ba2.getBalance() + amount);
            return true;
        }
        return false;
    }

    private class BankAccount implements BankAccountInterface {
        private double balance;
        private User user;

        private BankAccount(double balance) {
            this.balance = balance;
        }

        @Override
        public double getBalance() {
            return balance;
        }

        @Override
        public User getUser() {
            return user;
        }

        public void setUser(User user) {
            this.user = user;
        }

        private void setBalance(double balance) {
            this.balance = balance;
        }
    }
}

public interface BankAccountInterface {
    double getBalance();
    User getUser();
}

public class User {
    private String username;
    private String password;
    private Date created_at;
    private BankAccountInterface bankAccount;
    //constructor getters and setters etc..
}

Если вы можете добавить свои собственные классы, наследующие текущие, использовать отражение или что-то еще в вашем распоряжении, вы можете незаконно дать пользователю деньги.


person The Cat    schedule 23.10.2019    source источник
comment
вы можете немного усложнить отражение, используя SecurityManager, но, вероятно, никогда не сделаете это невозможным (поскольку @curiosa только что тоже ответила, но удалила (и восстановила))   -  person user85421    schedule 23.10.2019
comment
Зависит от доступа к приложению, если вы будете блокировать ВСЕ отражения и небезопасный код с помощью менеджера безопасности, и, возможно, использовать java-модули для ограничения доступа между модулями, и такой человек не имеет доступа к самой машине - тогда это должно быть безопасно. Но вы также очень ограничены библиотеками, и они тоже не могут использовать отражения. (в противном случае очень сложно ограничить отражения, так как какая-то библиотека может также предоставить доступ к отражениям). Но с доступом к самому приложению вы всегда можете отключить всю защиту с помощью нескольких аргументов, добавленных в стартовую строку.   -  person GotoFinal    schedule 23.10.2019
comment
Банковские настройки всегда имеют максимальный уровень паранойи, трудно себе представить, они позволяют вводить такие аргументы jvm где угодно.   -  person Nikolai Dmitriev    schedule 28.10.2019


Ответы (3)


Это секретный вопрос. Вы можете использовать настройки диспетчера безопасности, предотвращающие отражение, см. это и это, интерфейс изменяется по байтам после загрузки класса не может быть и речи о манипулировании кодом, см. во время выполнения">это. Однако есть и другие уязвимости в системе безопасности, вот официальный список с печально известным уязвимость десериализации изначально присутствует по замыслу. Это известные проблемы без учета эксплойтов нулевого дня. Вот более подробное обсуждение тонкостей диспетчера безопасности и некоторые API, связанные с этой уязвимостью.

person Nikolai Dmitriev    schedule 23.10.2019
comment
Можно редактировать байт-код после загрузки класса, но вам необходимо иметь доступ либо к отражениям, либо к начальным аргументам приложения, поскольку предоставленные ссылки как бы предполагают, что байт-код неизменен после загрузки класса. - person GotoFinal; 23.10.2019
comment
Можете ли вы привести пример или ссылку на иск? - person Nikolai Dmitriev; 23.10.2019
comment
Самый простой способ - использовать библиотеку ByteBuddyAgent для получения экземпляра Instrumentation во время выполнения, а API Instrumentation позволяет вам изменять классы Java во время выполнения, если вы не добавляете/удаляете/редактируете поля/метод/подпись класса. Но код внутри каждого метода можно редактировать. (до загрузки класса все можно редактировать, вы даже можете перемещать целые библиотеки во время выполнения, как вы можете найти в одном из моих ответов). Вы также можете увидеть мой метод на jvm 8, который позволяет вам прикреплять агент к себе, используя только отражения на JVM без JDK github.com/raphw/byte-buddy/issues/374#issuecomment-343786107 - person GotoFinal; 23.10.2019
comment
API инструментовки docs.oracle.com/javase/ 7/docs/api/java/язык/инструмент/ - person GotoFinal; 23.10.2019

Вот код отражения для предоставления известному пользователю 1 000 000 долларов:

User user = /*assigned elsewhere*/;

// Get users bank account
Field bankAccountField = user.getClass().getDeclaredField("bankAccount");
bankAccountField.setAccessible(true); // Bypass 'private'
Object bankAccount = bankAccountField.get(user);

// Get bank account balance
Field balanceField = bankAccount.getClass().getDeclaredField("balance");
balanceField.setAccessible(true); // Bypass 'private'
double balance = (Double) balanceField.get(bankAccount);

// Add $1,000,000 to bank account
balance += 1_000_000;
balanceField.set(bankAccount, balance);
person Andreas    schedule 23.10.2019

Когда у вас есть экземпляр внутреннего объекта, вы можете использовать отражение для вызова самого метода:

Method someMethod = innerObject.getClass().getDeclaredMethod("someMethod", Integer.class);
someMethod.setAccessible(true);
someMethod.invoke(innerObject, 5);

в этом примере вы все еще можете использовать отражение для получения методов в пользовательском классе.

Если вы можете добавить свои собственные классы, наследующие текущие, использовать отражение или что-либо в вашем распоряжении, можете ли вы незаконно дать пользователю деньги? Да, возможно, если методы реализованы без ограничений доступа для внешнего класса, речь идет о безопасности, а не о коде Java.

person sivaramakrishnan    schedule 23.10.2019
comment
Действительно, но внутренний класс является закрытым, поэтому экземпляр может существовать только внутри внешнего класса, который нельзя редактировать, потому что это часть правил. - person The Cat; 23.10.2019
comment
проверьте этот ответ, это поможет вам понять. отражение"> stackoverflow.com/questions/14112166/ - person sivaramakrishnan; 23.10.2019