Pergunta

Recentemente, a equipe de segurança sobre o meu projeto lançado um código de segurança de documento de diretrizes, concebido para ser utilizado como parte de nossa revisões de código.A primeira coisa que me chamou a atenção foi um item que disse: "não use Inner classes".Eu pensei que este parecia ser muito pesada e de varrição instrução.Classes internas são bons se usados corretamente, certo?, mas eu fiz um pouco de pesquisa no google e encontrei este, citado aqui por conveniência.

Regra 5:Não Use Inner Classes

Alguns linguagem Java livros dizem que classes internas só podem ser acessados por o exterior classes que encerrá-las.Isso não é verdade.Java de código de byte tem nenhum conceito de classes internas, para interior as aulas são traduzidas pelo compilador em aulas normais que acontecem ser acessível para qualquer código no mesmo pacote.E a Regra 4 diz que não dependem no pacote de escopo de proteção.

Mas espere, ele fica pior.Interior a classe tem acesso a campos do envolvente exterior de classe, mesmo se estes campos de são declarados como privados.E o classe interna é convertida em um classe separada.A fim de permitir que este classe separada de acesso aos campos de o exterior de classe, o compilador silenciosamente alterações nesses campos de privada para pacote de escopo!É ruim o suficiente que a classe interna é exposto, mas é ainda pior que o compilador é silenciosamente, reformando sua decisão fazer alguns campos privada.Não use classes internas se você pode ajudá-lo.(Ironicamente, o novo Java 2 doPrivileged() API diretrizes de uso sugerimos que você use uma classe interna para escrever o código privilegiado.Essa é uma motivo não gostamos do doPrivileged() API.)

Minhas perguntas são

  1. Será que este comportamento ainda existem no java 5 / 6?
  2. Este é realmente um risco de segurança, dado que qualquer classe, excepto o exterior e interior de classes, que tentou acessar o exterior de classe' membros privados não seria compilar?
  3. Faz pose suficiente de um risco de segurança para warant a 'orientação' 'não use inner classes"?
Foi útil?

Solução

Esta informação está cerca de uma década desatualizada. O uso generalizado de classes internas anônimas com AccessController.doPrivileged deve ser uma pista. (Se você não gosta da API, considere a proporção de try-finally blocos que estão faltando incorretamente no JDK.)

A política é que nenhuma classe de duas pessoas pode compartilhar o mesmo pacote se for carregada por diferentes carregadores de classe ou tiver certificados diferentes. Para mais proteção, marque os pacotes como selados no manifesto de seus potes. Portanto, do ponto de vista da segurança, a "regra 4" é falsa e, portanto, também esta regra.

De qualquer forma, elaborando as políticas de segurança, você deve entender o que está protegendo. Esses tipos de políticas são para lidar com o código móvel (código que se move) que podem ter diferentes níveis de confiança. A menos que você esteja lidando com o código móvel, ou seu código está entrando em uma biblioteca que pode ser necessária, há muito pouco ponto nesses tipos de precauções. No entanto, quase sempre é uma boa idéia usar um estilo de programação robusto, por exemplo, copiando e validando argumentos e valores de retorno.

Outras dicas

Esse comportamento ainda existe em Java 5/6?

Não exatamente como descrito; Eu nunca vi um compilador onde isso era verdade:

Para permitir que esse acesso de classe separado aos campos da classe externa, o compilador muda silenciosamente esses campos do escopo privado para o pacote!

Em vez disso, o IIRC Sun Java 3/4 criou um acessador em vez de modificar o campo.

Sun Java 6 (Javac 1.6.0_16) cria um acessador estático:

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

Isso é realmente um risco de segurança, dado que qualquer classe, exceto as classes externas e internas, que tentou acessar os membros privados da classe externa não iria [p]?

Estou especulando um pouco aqui, mas se você compilar a classe, isso não, mas se você adicionar o access$000 Em seguida, você pode compilar código que usa o acessador.

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

O interessante é que o acessador sintetizado tem sinalizadores modificadores 00001008 onde se você adicionar um método estático no nível do pacote, ele tem bandeiras 00000008. Não há nada na segunda edição da especificação da JVM para esse valor de bandeira, mas parece impedir que o método seja visto por Javac.

Parece que há algum recurso de segurança lá, mas não consigo encontrar nenhuma documentação sobre ele.

(Portanto, este post na CW, caso alguém saiba o que 0x1000 significa em um arquivo de classe)

  1. Sim, esse comportamento ainda existe.
  2. É um risco de segurança, porque a classe desonesta pode ser criada com outra coisa que o JAVAC padrão.
  3. Depende de quanta paranóica você é :) Se você não permitir que as aulas alienígenas sejam executadas na sua JVM, não vejo o problema. E se o fizer, você tem problemas maiores (caixas de areia e tudo)
  4. Eu sei que você só teve três perguntas, mas, como outras pessoas aqui, acho que isso é uma restrição estúpida.

Esse comportamento ainda existe em Java 5/6?

Você pode usar o javap ferramenta para determinar o que seus binários estão expondo e como.

package demo;
public class SyntheticAccessors {
  private boolean encapsulatedThing;

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

O código acima (compilado com Sun Java 6 javac) cria esses métodos em SyntheticAccessors.class:

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

Observe o novo access$0 método.

Você deve considerar que tipo de segurança seu aplicativo tem a fornecer. Um aplicativo com uma arquitetura segura não se deparar com esses problemas nomeados.

Se houver algo que um usuário não puder fazer com seu código, você deve separar essa funcionalidade e executá -la em um servidor (onde o usuário não tem acesso aos arquivos da classe).

Lembre -se de que você sempre pode descompilar os arquivos da classe Java. E não confie em "segurança pela obscuridade". Mesmo o código ofuscado pode ser analisado, entendido e modificado.

O código malicioso pode usar a reflexão do Java para obter qualquer informação na JVM, a menos que um gerente de segurança esteja em vigor que proíba isso, isso inclui a mudança de campos privados para o público e muito mais.

Minha opinião pessoal é que as razões para não, estão impressionadas com as outras possibilidades; portanto, se você precisar, faz sentido e é legível, use aulas internas.

A idéia deste tipo de segurança no código é uma espécie de bobo.Se você quiser o código de nível de segurança, use uma ferramenta de ofuscamento.Como @skaffman disse nos comentários acima, "Código de visibilidade nunca foi um recurso de segurança.Até mesmo membros privados pode ser acessado usando a reflexão.".

Se você estiver distribuindo o seu código compilado e não ofuscando-lo, em seguida, usando uma classe interna é a sua última preocupe se você está preocupado com as pessoas a mexer com seus genitais.

Se você está hospedando seu código, então por que você está preocupado com alguém bisbilhotando seu interior aulas?

Se você vai ligando alguns 3ª festa do código de você não confiar e não é possível verificar em tempo de execução, em seguida, caixa de areia-la.

Como eu disse acima, se isso realmente é uma política na sua empresa, por favor, comunique imediatamente a sua empresa thedailywtf.com

"Isso é realmente um risco de segurança, dado que qualquer classe, além das classes externas e internas, que tentou acessar os membros particulares da classe externa não compilariam?"

Mesmo que não seja compilação em circunstâncias normais, você ainda pode gerar seu próprio bytecode. Mas isso não é motivo para evitar classes internas. Tudo o que você precisa fazer é assumir que todas as suas classes internas são públicas.

Se você realmente deseja poder executar código não confiável, aprenda como configurar suas próprias caixas de areia e níveis de segurança usando A arquitetura de segurança Java, não é tão difícil. Mas, principalmente, você deve evitar a execução de código aleatório em um ambiente seguro.

Absurdo! Siga a mesma lógica, também não escreva métodos públicos, porque eles têm acesso a campos privados, Gush!

Note que as desvantagens listadas não segure para static classes internas como eles não têm implícito o acesso à sua classe envolvente (ou objeto realmente.)

Então, se essa regra é para ajudar na sua empresa, pode ser uma ideia estática de classes internas excempted como eles oferecem uma maneira para que o encapsulamento, que é útil em muitos casos.

@Tom, citando o Especificação da linguagem Java, "Membro classes podem ser estática, caso em que eles têm sem acesso para as variáveis de instância dos arredores de classe"

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