2009-12-20 11 views
31

Recientemente, el equipo de seguridad de mi proyecto publicó un documento de pautas de código seguro, diseñado para ser utilizado como parte de las revisiones de nuestro código. Lo primero que me llamó la atención fue un artículo que decía "No use clases internas". Pensé que esto parecía una declaración muy arriesgada y arrolladora. Las clases internas son buenas si se usan correctamente ¿cierto ?, pero hice un poco de búsqueda en Google y encontré this, aquí citado para mayor comodidad.¿Las clases internas de Java representan un riesgo de seguridad?

Regla 5: No utilice clases internas

Algunos libros de lenguaje Java dicen que clases internas sólo se puede acceder por las clases externas que les rodean. Esto no es verdad. El código de bytes Java tiene sin concepto de clases internas, por lo que las clases internas son traducidas por el compilador en las clases ordinarias que pasan a ser accesibles a cualquier código en el mismo paquete . Y la Regla 4 dice que no se debe depender de en el alcance del paquete para la protección.

Pero espera, empeora. Una clase interna obtiene acceso a los campos de la clase externa , incluso si estos campos se declaran privados. Y la clase interna se traduce en una clase separada . Para permitir este acceso de clase por separado a los campos de la clase externa, el compilador cambia silenciosamente estos campos del ámbito del paquete privado al . Ya es suficientemente malo que la clase interna esté expuesta, pero es peor que el compilador que anula silenciosamente su decisión de hacer que algunos campos sean privados. No use las clases internas si puede evitarlo. (Irónicamente, el nuevo Java 2 directrices doPrivileged() uso de la API sugerimos que utilice una clase interna a escribir código privilegiado. Esa es una razón por la que no nos gusta la API doPrivileged()).

Mis preguntas son

  1. ¿existe todavía este comportamiento en java 5/6?
  2. ¿Es esto realmente un riesgo de seguridad, dado que cualquier clase, aparte de las clases externas e internas, que intentó acceder a los miembros privados de la clase externa no compilaría?
  3. ¿Representa un riesgo de seguridad suficiente como para justificar la 'guía' 'No utilizar clases internas'?
+2

Espera un segundo? ¿Significa esto que "no puedo usar la forma más popular de crear devoluciones de llamada en Swing"? – Artyom

+8

si esto es realmente una política de seguridad en su empresa durante la revisión del código, informe inmediatamente a su empresa a dailywtf.com –

+2

@Zac Bowling: thedailywtf.com, la otra es solo una página de entrada. – nalply

Respuesta

18

Esta información es alrededor de una década a cabo de la fecha. El uso generalizado de clases internas anónimas con AccessController.doPrivileged debería ser una pista. (Si no te gusta la API, tenga en cuenta la proporción de try -. finally bloques que están incorrectamente faltan en el JDK)

La política es que hay dos clases pueden compartir el mismo paquete si están cargados por diferentes clases cargadores o tienen diferentes certificados. Para mayor protección, marque los paquetes como sellados en el manifiesto de sus jarras. Entonces, desde el punto de vista de la seguridad, la "Regla 4" es falsa y, por lo tanto, también esta regla.

En cualquier caso, al elaborar las políticas de seguridad, debe comprender aquello contra lo que está protegiendo.Este tipo de políticas son para manejar el código móvil (código que se mueve) que puede tener diferentes niveles de confianza. A menos que esté manejando un código móvil, o su código vaya a una biblioteca a la que pueda ser necesario, no tiene mucho sentido este tipo de precauciones. Sin embargo, casi siempre es una buena idea utilizar un estilo de programación robusto, por ejemplo copiar y validar argumentos y devolver valores.

+0

Copiar argumentos no siempre ayudará a que su código sea más seguro, por ejemplo, cuando llama a Array() en una colección de argumentos, confía en la implementación de Array() del argumento. – akuhn

+0

Adrian: Sí, como se indica en las Pautas de código seguro de SUn para Java. –

9
  1. Sí, este comportamiento todavía existe.
  2. Es un riesgo de seguridad porque la clase de delincuentes podría diseñarse con algo más que el javac estándar.
  3. Depende de cuán paranoico sea :) Si no permite que se ejecuten clases extraterrestres en su JVM, no veo el problema. Y si lo haces, tienes problemas más grandes (cajas de arena y todo)
  4. Sé que solo tienes 3 preguntas, pero al igual que otras personas aquí, creo que es una restricción estúpida.
+7

Destacaría el 3. Si el perpetrador entra en su máquina/VM, ya ha perdido y ninguna cantidad de "codificación segura" puede evitarlo. – Esko

+1

Esko: ¿Has perdido si ejecutas un applet sin firmar? ¡Yo creo que no! –

+2

@Esko, excepto si tiene un modelo de seguridad adecuado listo para manejarlo, y usted controla la forma en que se inicia el código extraterrestre. – Jerome

4

La idea de este tipo de seguridad en el código es algo tonto. Si desea seguridad a nivel de código, use una herramienta de ofuscación. Como dijo @skaffman en los comentarios anteriores, "la visibilidad del código nunca ha sido una característica de seguridad. Incluso se puede acceder a los miembros privados mediante la reflexión".

Si está distribuyendo su código compilado y no lo ofusca, usar una clase interna es su última preocupación si le preocupa que las personas jueguen con sus partes privadas.

Si está alojando su código, ¿por qué le preocupa que alguien hurgue en sus clases internas?

Si va a vincular un código de terceros en el que no confía y no puede verificar en el tiempo de ejecución, sandbox.

como he dicho anteriormente, si esto es realmente una política en su empresa, por favor informar de inmediato a su empresa a thedailywtf.com

+1

No entiendo su comentario: los chicos de seguridad en la empresa de mR_fr0g no quieren que los campos privados se hagan públicos, cualquiera sea el camino, sea realista o no. Una herramienta de ofuscación no cambiará ningún nivel de seguridad, y todos los métodos para obtener acceso a un campo privado seguirán funcionando después de la ofuscación. – Jerome

+3

Sí, este es un consejo terrible. La ofuscación no hará nada más seguro, solo significará que los hackers necesitan hacer mucho más trabajo. Pero, finalmente, cualquier cosa que puedan hacer antes de que puedan hacerlo. –

+0

Puede acceder de todos modos a los campos privados a través de la reflexión – nos

4

Debe tener en cuenta qué tipo de seguridad que su aplicación tiene que ofrecer. Una aplicación con una arquitectura segura no se ejecutará en estos problemas nombrados.

Si hay algo que un usuario no puede hacer con su código, debe separar esta funcionalidad y ejecutarla en un servidor (donde el usuario no tiene acceso a los archivos de clase).

Recuerde que siempre puede descompilar los archivos de la clase java. Y no confíe en la "seguridad por oscuridad". Incluso el código ofuscado se puede analizar, comprender y modificar.

4

El código malintencionado puede usar el reflejo de java para acceder a cualquier información en la JVM a menos que haya un administrador de seguridad que lo prohíba, esto incluye el cambio de campos privados a público y mucho más.

Mi opinión personal es que las razones para no hacerlo, son abrumadas por las otras posibilidades, por lo que si lo necesita, tiene sentido, y es legible, use clases internas.

-1

Tenga en cuenta que los inconvenientes mencionados no se aplican a static clases internas, ya que no tienen acceso implícito a su clase envolvente (u objeto realmente.)

Así que si esta regla va a ayudar en su empresa, podría ser una idea obtener clases internas estáticas excedidas ya que ofrecen una forma de encapsulación que es útil en muchos casos.

@ Tom, citando el Java language specification, "clases pueden ser miembros estática, en cuyo caso tienen ningún acceso a las variables de instancia de la clase que rodea"

+1

Clases anidadas estáticas para tener acceso privado a la clase adjunta (y viceversa). –

6

¿Este comportamiento todavía existe en java 5/6?

Puede usar la herramienta javap para determinar qué exponen sus binarios y cómo.

package demo; 
public class SyntheticAccessors { 
    private boolean encapsulatedThing; 

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

El código anterior (recopilada con Sun Java 6 javac) crea estos métodos en SyntheticAccessors.class:

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

Nota access$0 el nuevo método.

9

¿Este comportamiento todavía existe en java 5/6?

No exactamente como se describe; Nunca he visto un compilador donde esto era cierto:

Para permitir este acceso de clase separado a los campos de la clase externa, el compilador cambia silenciosamente estos campos del ámbito privado al del paquete.

En lugar de IIRC Sun Java 3/4 creó un acceso en lugar de modificar el campo.

Sun Java 6 (javac 1.6.0_16) crea un descriptor de acceso estática:

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 

¿Es esto realmente un riesgo de seguridad, dado que cualquier clase, con excepción de las clases externas e internas, que intentó acceder a los miembros privados de la clase externa ¿no com [p] ile?

Estoy especulando un poco aquí, pero si compila contra la clase no lo hace, pero si se agrega el access$000 entonces se puede compilar código que utiliza el descriptor de acceso.

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

Lo interesante es que el descriptor de acceso sintetizado tiene banderas modificadoras 00001008 donde si se agrega un método estático nivel de paquete que tiene banderas 00000008. No hay nada en la segunda edición de la especificación de JVM para ese valor de indicador, pero parece evitar que javac vea el método.

Parece que hay alguna función de seguridad allí, pero no encuentro ninguna documentación sobre la misma.

(de ahí este blog en CW, en caso de que alguien sabe lo 0x1000 significa en un archivo de clase)

+0

¿Qué pasa con el modificador sintético? –

+0

Creo que sí, pero no encontré ninguna referencia de Sun, ni nada que diga 'si un método tiene un modificador sintético, no se puede llamar a través de la reflexión sin antes establecerlo accesible', lo que eliminaría la seguridad percibida riesgo. –

+0

Es extraño que la búsqueda de Java 6 JVMS sea [redirigida a la segunda edición irremediablemente desactualizada] (https://docs.oracle.com/javase/specs/jvms/se6/html/VMSpecTOC.doc.html). Incluso carece de las características obvias de Java 5, 'enum's, anotaciones, genéricos, etc.No hay ningún enlace directo a la 3ª edición en absoluto. La [Java 7 edition documenta el modificador 'ACC_SYNTHETIC'] (http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6-200-A.1). Antes de Java 5, [el atributo 'Sintético'] (https://docs.oracle.com/javase/specs/jvms/se6/html/ClassFile.doc.html#80128) se utilizaba con el mismo propósito. – Holger

3

"¿Es esto realmente un riesgo de seguridad, dado que cualquier clase, con excepción de las clases externas e internas, que ¿Intentó acceder a la clase externa que los miembros privados no compilarían?"

Incluso si no se compilará en circunstancias normales, todavía se puede generar su propio código de bytes. Pero eso no es razón para evitar las clases internas. Todo lo que tendría que hacer es asumir todas sus clases internas son públicos.

Si realmente quiere ser capaz de ejecutar código no confiable, aprender cómo configurar sus propias cajas de arena y niveles de seguridad utilizando The Java Security Architecture, no es tan difícil. Pero sobre todo, se debe evitar la ejecución de código al azar en un entorno seguro.

-1

disparate ! siga la misma lógica, tampoco escriba métodos públicos, ya que tienen acceso a campos privados, gush!

+2

Esto no es un problema de idioma. El hecho de que las clases anidadas tengan acceso a partes privadas en la clase adjunta y viceversa no es el tema en discusión. El (no) problema es que la adición de clases anidadas puede hacer que las partes privadas sean accesibles a cualquier código inyectado en el mismo paquete (si el código malicioso puede ser inyectado en el paquete). –

Cuestiones relacionadas