2009-12-20 6 views
31

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

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

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

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

Мои вопросы

  1. все еще существует такое поведение в Java 5/6?
  2. Действительно ли это угроза безопасности, учитывая, что любой класс, кроме внешних и внутренних классов, которые пытались получить доступ к закрытым членам внешнего класса, не собирался?
  3. Означает ли он достаточный риск для безопасности, чтобы подтвердить «руководство» «Не использовать внутренние классы»?
+2

Подождите секунду? Это означает: «Я не могу использовать самый популярный способ создания обратных вызовов в Swing?» – Artyom

+8

, если это действительно политика безопасности в вашей компании во время обзора кода, незамедлительно сообщите о своей компании на ежедневный веб-сайт –

+2

@Zac Bowling: thedailywtf.com, а другой - просто дверь. – nalply

ответ

18

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

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

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

+0

Копирование аргументов не всегда поможет сделать ваш код более безопасным, например, когда вы вызываете toArray() в коллекции аргументов, которым вы доверяете реализации аргумента toArray()! – akuhn

+0

Адриан: Да, как указано в Руководстве по безопасному коду SUn для Java. –

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

Я хотел бы подчеркнуть 3. Если преступник попадает в ваш компьютер/виртуальную машину, вы уже потеряли, и никакая «безопасная кодировка» не может обойти это. – Esko

+1

Esko: Вы проиграли, если вы запускаете неподписанный апплет? Думаю, нет! –

+2

@ Esko, за исключением случаев, когда у вас есть надлежащая модель безопасности, готовая к ее обработке, и вы контролируете запуск чужой кода. – Jerome

4

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

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

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

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

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

+1

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

+3

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

+0

Вы можете в любом случае получить доступ к закрытым полям через отражение – nos

4

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

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

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

4

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

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

-1

Обратите внимание, что недостатки, перечисленные не держу для static внутренних классов, поскольку они не имеют неявный доступ к их объемлющему классу (или объекта действительно.)

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

@tom со ссылкой на Java language specification, «классы-члены могут быть статическую, в этом случае они не имеют никакого доступа к переменным экземпляра окружающего класса»

+1

Статические вложенные классы для доступа к закрывающему классу (и наоборот). –

6

Сохранено ли это по-прежнему в java 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.

9

Это поведение все еще существует в 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 

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

Я спекулировать немного здесь, но если вы собираете против класса это не делает, но если вы добавите 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 означает, в файле класса)

+0

Как насчет синтетического модификатора? –

+0

Я думаю, что это так, но не нашел ссылки на Sun, и ничего, что говорит «если у метода есть синтетический модификатор, он не может быть вызван путем отражения без предварительной установки его», что позволило бы удалить воспринимаемую безопасность риск. –

+0

Странно, что поиск Java 6 JVMS будет [перенаправлен на безнадежно устаревшее второе издание] (https://docs.oracle.com/javase/specs/jvms/se6/html/VMSpecTOC.doc.html). В нем даже отсутствуют очевидные функции Java 5, «enum's», аннотации, дженерики и т. Д.Прямой связи с третьим изданием нет. [Версия Java 7 документирует модификатор 'ACC_SYNTHETIC'] (http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6-200-A.1). Перед Java 5 для этой же цели использовался [атрибут 'Synthetic'] (https://docs.oracle.com/javase/specs/jvms/se6/html/ClassFile.doc.html#80128). – Holger

3

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

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

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

-1

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

+2

Это не проблема языка. Тот факт, что вложенные классы имеют доступ к частным лицам в окружающем классе и наоборот, не является предметом обсуждения. Проблема (non) заключается в том, что добавление вложенных классов может привести к тому, что рядовые пользователи будут доступны для любого кода, введенного в тот же пакет (если вредоносный код действительно может быть введен в пакет). –

Смежные вопросы