¿Son realmente seguros los métodos privados?

92

En Java el private modificador de acceso se considera seguro ya que no es visible fuera de la clase. Entonces el mundo exterior tampoco conoce ese método.

Pero pensé que la reflexión de Java puede usarse para romper esta regla. Considere el siguiente caso:

public class ProtectedPrivacy{

  private String getInfo(){
     return "confidential"; 
  }

}  

Ahora de otra clase voy a obtener información:

public class BreakPrivacy{

   public static void main(String[] args) throws Exception {
       ProtectedPrivacy protectedPrivacy = new ProtectedPrivacy();
       Method method = protectedPrivacy.getClass().getDeclaredMethod("getInfo", null);
       method.setAccessible(true);
       Object result = method.invoke(protectedPrivacy);
       System.out.println(result.toString());
   }
} 

En este momento pensé que el método privado aún era seguro, ya que para hacer algo como el anterior debemos saber el nombre del método. Pero si la clase contiene un método privado escrito por otra persona, no tenemos visibilidad de ellos.

Pero mi punto se vuelve inválido desde debajo de la línea de código.

Method method[] = new ProtectedPrivacy().getClass().getDeclaredMethods();

Ahora bien, esto method[]contiene todas las cosas que hay que hacer antes. Mi pregunta es, ¿hay alguna manera de evitar este tipo de cosas usando la reflexión de Java?

Cito algún punto de la documentación de Java para aclarar mi pregunta.

Consejos para elegir un nivel de acceso:

Si otros programadores usan su clase, querrá asegurarse de que no se produzcan errores por mal uso. Los niveles de acceso pueden ayudarlo a hacer esto. Utilice el nivel de acceso más restrictivo que tenga sentido para un miembro en particular. Use privado a menos que tenga una buena razón para no hacerlo.

Ruchira Gayan Ranaweera
fuente
1
El uso de un ofuscador puede ayudar, ya getDeclaredMethodsque devolvería nombres que parecen basura.
dasblinkenlight
213
Privado, público protegido, etc. no es por seguridad, es para evitar que personas bien intencionadas cometan errores. No lo use como medida de seguridad
Richard Tingle
20
El código Java es descompilable de todos modos. Un 'atacante' podría simplemente descargar un descompilador de Java y leer su código, o cambiar 'privado' a 'público'.
11684
7
Para elaborar lo que comentó @RichardTingle (+1 por cierto). Existe una gran e importante diferencia entre seguridad y protección. Donde este último es el problema mitigado con modificadores de acceso; para no romper cosas por accidente
usuario
3
Todo esto es bastante claro para los programadores donde no existen modificadores de acceso, como en Python. En estos lenguajes, lo privado / público se distingue simplemente por una convención en los nombres (en Python, todo lo que comience con un guión bajo debe considerarse privado). Esto deja bastante claro que marcar algo como "privado" no agrega ninguna seguridad, pero es solo una forma simple de decir lo que la gente debería usar de su API. Tengo mis dudas de que tener una verificación del compilador para estas cosas ayude en absoluto, ya que es muy fácil seguir la convención sin ayuda "externa".
Bakuriu

Respuestas:

95

Depende de lo que quieras decir con "seguro". Si está ejecutando con un administrador de seguridad que permite este tipo de cosas, entonces sí, puede hacer todo tipo de cosas desagradables con reflexión. Pero luego, en ese tipo de entorno, la biblioteca probablemente pueda modificarse para hacer público el método de todos modos.

El control de acceso es efectivamente un "aviso" en un entorno como ese: está confiando efectivamente en que el código se reproducirá bien. Si no confía en el código que está ejecutando, debe usar un administrador de seguridad más restrictivo.

Jon Skeet
fuente
3
Tangencial, lo sé, pero ¿podría explicarnos un poco qué sería un gerente más restrictivo en este sentido?
Gray
12
@Gray: una instancia de SecurityManager que arroja excepciones en las check*llamadas relevantes , básicamente.
Jon Skeet
40

Los modificadores de acceso no tienen nada que ver con la seguridad. De hecho, puede y debe considerar los modificadores de acceso como lo contrario de la seguridad: no es para proteger sus datos o algoritmos, es para proteger a las personas del requisito de conocer sus datos y algoritmos. Esta es la razón por la que el modificador predeterminado es paquete: si están trabajando en el paquete, probablemente ya lo necesiten.

Junto con el conocimiento de los datos y los métodos de su código, viene la responsabilidad de saber cuándo y cómo usarlo. No pones privado en tu método inIt para evitar que alguien se entere, lo haces porque (a) no van a saber que solo lo llamas después de foo y solo si bar = 3.1415 y (b) porque no les sirve de nada saberlo.

Modificadores de acceso se pueden resumir en una simple frase "TMI, tío, por lo que no necesitaba saber eso".

jmoreno
fuente
3
Gran respuesta, pero necesitaba buscar en Google para descubrir que TMI significaba demasiada información. Supongo que tengo que pasar más tiempo en el valle :-)
mikelong
7

Al decir "seguro", te estás protegiendo a ti oa otros desarrolladores, que están usando tu API para no dañar el objeto llamando a tu método privado. Pero si usted o ellos realmente necesitan llamar a este método, pueden hacerlo con Reflection.

Arsen Alexanyan
fuente
6

La pregunta es a quién intentas salvar . En mi opinión, tal cliente de su código es el que está perdido aquí.

Cualquier fragmento de código (escrito por usted u otros) que intente acceder a un privatemiembro de la clase anterior está esencialmente cavando su propia tumba. privatelos miembros no forman parte de la API pública y están sujetos a cambios sin previo aviso. Si un cliente consume uno de esos miembros privados de la manera indicada anteriormente, se romperá si se actualiza a una versión más nueva de la API en la que se modificó el miembro privado.

hthserhs
fuente
5

Con facilidad, viene la responsabilidad. Hay cosas que no puedes hacer y cosas que puedes hacer pero no debes hacer.

El modificador privado se proporciona / utiliza como / de la manera más restringida. Los miembros que no deben ser visibles fuera de la clase se definirán como privados. Pero esto se puede romper con Reflection como vemos. Pero esto no significa que no deba usar los privados, o no son seguros. Se trata de que uses las cosas de manera juiciosa o constructiva (como la reflexión).

Raúl
fuente
5

Suponiendo que confía en el programador cliente de su API, otra forma de verlo es qué tan 'seguro' es para ellos usar esas funciones particulares.

Sus funciones disponibles públicamente deben proporcionar una interfaz clara, bien documentada y que rara vez cambia en su código. Sus funciones privadas pueden considerarse un detalle de implementación y pueden cambiar con el tiempo, por lo que no es seguro utilizarlas directamente.

Si un programador cliente se esfuerza por eludir estas abstracciones, de alguna manera está declarando que sabe lo que está haciendo. Más importante aún, comprenden que no es compatible y pueden dejar de funcionar con versiones futuras de su código.

robbie_c
fuente
5

privateno es por seguridad, es para mantener limpio el código y evitar errores. Permite a los usuarios modularizar el código (y cómo se desarrolla) sin tener que preocuparse por todos los detalles de los otros módulos.

Una vez que libera su código, la gente puede descubrir cómo funciona. No hay forma de "ocultar" la lógica si finalmente desea que el código se ejecute en una computadora. Incluso compilar en binario es sólo un nivel de ofuscación.

Por lo tanto, no hay forma de que pueda configurar su API para hacer cosas especiales que no desea que otros puedan llamar. En el caso de una API web, puede colocar los métodos que desea controlar en el lado del servidor.

Manishearth
fuente