Внутренние классы Java излагают угрозу безопасности?

Недавно служба безопасности на моем проекте выпустила документ инструкций по безопасному коду, разработанный, чтобы использоваться в качестве части наших обзоров кода. Первой вещью, которая ударила меня, был объект, который сказал, "Не используют Внутренние классы". Я думал, что это походило на очень жестокий и широкий оператор. Внутренние классы хороши, если используется правильно правильные?, но я сделал немного поиска с помощью Google и нашел это, заключенное в кавычки здесь для удобства.

Правило 5: не используйте внутренние классы

В некоторых книгах языка Java говорится, что к внутренним классам могут только получить доступ внешние классы, которые включают их. Это не верно. Байт-код Java не имеет никакого понятия внутренних классов, таким образом, внутренние классы переводятся компилятором в обычные классы, которые, оказывается, доступны для любого кода в том же пакете. И в Правиле 4 говорится для не зависимости от объема пакета для защиты.

Но ожидайте, это ухудшается. Внутренний класс получает доступ к полям включающего внешнего класса, даже если эти поля объявляются частные. И внутренний класс переводится в отдельный класс. Для предоставления этого отдельного доступа класса к полям внешнего класса компилятор тихо изменяет эти поля от частного для упаковки объема! Это достаточно плохо, что внутренний класс выставляется, но это еще хуже, что компилятор тихо отвергает Ваше решение сделать некоторые поля частными. Не используйте внутренние классы, если можно помочь ему. (Как ни странно, новый Java 2 doPrivileged () инструкции по использованию API предлагают, чтобы Вы использовали внутренний класс записи привилегированный код. Это - одна причина, нам не нравится doPrivileged () API.)

Мои вопросы

  1. Это поведение все еще существует в java 5 / 6?
  2. Это - на самом деле угроза безопасности, учитывая, что какой-либо класс, кроме внешних и внутренних классов, которые пытались получить доступ к членам парламента, не занимающим официального поста внешнего класса, не скомпилирует?
  3. Это излагает действительно угрозу безопасности, чтобы гарантировать, что 'инструкция' 'Не использует внутренние классы'?

31
задан Brian Tompsett - 汤莱恩 26 March 2016 в 17:30
поделиться

10 ответов

Эта информация устарела примерно на десятилетие. Подсказкой должно служить широкое использование анонимных внутренних классов с AccessController.doPrivileged. (Если вам не нравится API, обратите внимание на пропорцию --- блоков, которые неправильно пропущены в JDK.)

Политика заключается в том, что ни один из двух классов не может использовать один и тот же пакет, если они загружены разными загрузчиками классов или имеют разные сертификаты. Для большей защиты, пометьте пакеты как запечатанные в манифесте ваших банок. Таким образом, с точки зрения безопасности, "правило 4" является фальшивым, а, следовательно, и это правило.

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

18
ответ дан 27 November 2019 в 22:17
поделиться

«Действительно ли это угроза безопасности, учитывая, что любой класс, кроме внешнего и внутреннего классов , который пытался получить доступ к закрытым членам внешнего класса, не компилировался? "

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

Если вы действительно хотите иметь возможность запускать ненадежный код, узнайте, как настраивать свои собственные песочницы и уровни безопасности с помощью Архитектуры безопасности Java , это не так уж сложно. Но в большинстве случаев вам следует избегать запуска случайного кода в безопасной среде.

3
ответ дан 27 November 2019 в 22:17
поделиться

ерунда! следуйте той же логике, не пишите и публичные методы, потому что у них есть доступ к приватным полям, gush!

-1
ответ дан 27 November 2019 в 22:17
поделиться

Существует ли такое поведение до сих пор в java 5 / 6?

Не совсем так, как описано; я никогда не видел компилятора, где это было бы правдой:

Чтобы разрешить этому отдельному классу доступ к полям внешнего класса, компилятор молча изменяет эти поля с приватного на пакетный!

Вместо того, чтобы IIRC Sun Java 3/4 создал аксессуар, а не модифицировал поле.

Sun Java 6 (javac 1.6. 0_16 ) создает статический аксессуар:

public class InnerExample {
    private int field = 42; 

    private class InnerClass {
        public int getField () { return field; };
    }

    private InnerClass getInner () { 
        return new InnerClass();
    }

    public static void main (String...args) {
        System.out.println(new InnerExample().getInner().getField());
    }
}


$ javap -classpath bin -private InnerExample
Compiled from "InnerExample.java"
public class InnerExample extends java.lang.Object{
    private int field;
    public InnerExample();
    private InnerExample$InnerClass getInner();
    public static void main(java.lang.String[]);
    static int access$000(InnerExample);
}


$ javap -classpath bin -c -private InnerExample
static int access$000(InnerExample);
  Code:
   0:   aload_0
   1:   getfield    #1; //Field field:I
   4:   ireturn

Является ли это на самом деле риском для безопасности, учитывая, что любой класс, кроме классов внешнего и внутреннего, который пытался получить доступ к закрытым членам класса, не будет com[p]ile?

Я тут немного размышляю, но если вы скомпилируете против класса, то это не так, но если вы добавите access$000, то вы сможете скомпилировать код, который использует аксессуар.

import java.lang.reflect.*;

public class InnerThief {
    public static void main (String...args) throws Exception {
        for (Method me : InnerExample.class.getDeclaredMethods()){
            System.out.println(me);
            System.out.printf("%08x\n",me.getModifiers());
        }

        System.out.println(InnerExample.access$000(new InnerExample()));
    }
}

Интересным является то, что синтезируемый аксессуар имеет флаги модификаторов 00001008, где при добавлении статического метода пакетного уровня он имеет флаги 00000008. Во втором выпуске спецификации JVM для этого флага ничего нет, но, похоже, это мешает методу быть замеченным javac.

Похоже, что там есть какая-то функция безопасности, но я не могу найти никакой документации по этому методу.

(отсюда и этот пост в CW, в случае, если кто-то знает, что означает 0x1000 в файле класса)

.
9
ответ дан 27 November 2019 в 22:17
поделиться
  1. Да, такое поведение все еще существует.
  2. Это риск для безопасности, потому что класс мошенников может быть создан с чем-то другим, чем стандартный явак.
  3. Это зависит от того, насколько вы параноик :) Если вы не разрешаете инопланетным классам работать в вашем JVM, я не вижу проблемы. И если вы это сделаете, то у вас будут проблемы побольше (песочницы и все такое)
  4. Я знаю, что у вас было только 3 вопроса, но как и у других людей здесь, я думаю, что это глупое ограничение.
9
ответ дан 27 November 2019 в 22:17
поделиться

Существует ли такое поведение до сих пор в яве 5 / 6?

Вы можете использовать инструмент javap для определения того, что и как раскрывается в Ваших двоичных файлах.

package demo;
public class SyntheticAccessors {
  private boolean encapsulatedThing;

  class Inner {
    void doSomething() {
      encapsulatedThing = true;
    }
  }
}

Код выше (скомпилированный с помощью Sun Java 6 javac) создает эти методы в SyntheticAccessors.class:

Compiled from "SyntheticAccessors.java"
public class demo.SyntheticAccessors extends java.lang.Object{
    public demo.SyntheticAccessors();
    static void access$0(demo.SyntheticAccessors, boolean);
}

Обратите внимание на новый метод access$0.

.
6
ответ дан 27 November 2019 в 22:17
поделиться

Вам следует подумать о том, какую безопасность должно обеспечивать ваше приложение. Приложение с защищенной архитектурой не столкнется с этими названными проблемами.

Если есть что-то, что пользователь не имеет права делать с Вашим кодом, Вы должны отделить эту функциональность и запустить ее на сервере (где у пользователя нет доступа к файлам классов).

Помните, что Вы всегда можете декомпилировать файлы классов java. И не полагайтесь на "безопасность по неясности". Даже обфусцированный код можно анализировать, понимать и модифицировать

.
4
ответ дан 27 November 2019 в 22:17
поделиться

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

Мое личное мнение заключается в том, что причины этого не делать, перегружены другими возможностями, поэтому, если вам это нужно, это имеет смысл, и это читабельно, используйте внутренние классы.

.
4
ответ дан 27 November 2019 в 22:17
поделиться

Идея такой безопасности в коде довольно глупая. Если вам нужна безопасность на уровне кода, используйте инструмент обфускации. Как сказал @skaffman в комментариях выше: "Видимость кода никогда не была функцией безопасности". Даже к приватным членам можно получить доступ с помощью рефлексии".

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

Если вы распространяете свой код, то почему вы беспокоитесь о том, что кто-то будет копаться в ваших внутренних классах?

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

Как я уже говорил выше, если это действительно политика вашей компании, пожалуйста, немедленно сообщите о своей компании на thedailywtf.com

4
ответ дан 27 November 2019 в 22:17
поделиться

Обратите внимание, что перечисленные недостатки не относятся к внутренним классам static, так как они не имеют неявного доступа к своему классу инкапсуляции (или объекту на самом деле.)

Поэтому, если это правило поможет в вашей компании, то, возможно, будет неплохой идеей получить преувеличенные статические внутренние классы, так как они предлагают способ инкапсуляции, который полезен во многих случаях.

@Tom, цитируя спецификацию языка Java Java, "Классы-члены могут быть статическими , и в этом случае они не имеют никакого доступа к переменным экземпляра окружающего класса"

.
-1
ответ дан 27 November 2019 в 22:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: