Os métodos privados são realmente seguros?

92

Em Java, o privatemodificador de acesso é considerado seguro, pois não é visível fora da classe. Então, o mundo exterior também não conhece esse método.

Mas eu pensei que a reflexão Java pode ser usada para quebrar essa regra. Considere o seguinte caso:

public class ProtectedPrivacy{

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

}  

Agora de outra aula vou obter informações:

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

Neste momento eu apenas pensei que o método privado ainda era seguro, pois para fazer algo como acima, devemos saber o nome do método. Mas se a classe contém método privado escrito por outra pessoa, não temos visibilidade deles.

Mas meu ponto se tornou inválido por estar abaixo da linha de código.

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

Agora, isso method[]contém todas as coisas que você precisa fazer acima. Minha pergunta é: há uma maneira de evitar esse tipo de coisa usando o reflexo Java?

Estou citando algum ponto da documentação Java para esclarecer minha dúvida.

Dicas para escolher um nível de acesso:

Se outros programadores usam sua classe, você deseja garantir que erros de uso indevido não aconteçam. Os níveis de acesso podem ajudá-lo a fazer isso. Use o nível de acesso mais restritivo que faça sentido para um determinado membro. Use privado, a menos que você tenha um bom motivo para não o fazer.

Ruchira Gayan Ranaweera
fonte
1
Usar um ofuscador pode ajudar, porque getDeclaredMethodsretornaria nomes que parecem lixo.
dasblinkenlight
213
Privado, público protegido etc. não é para segurança, é para evitar que pessoas bem-intencionadas cometam erros. Não use como medida de segurança
Richard Tingle
20
O código Java é descompilável de qualquer maneira. Um 'invasor' pode simplesmente baixar um descompilador Java e ler seu código, ou alterar de 'privado' para 'público'.
11684
7
Para elaborar o que @RichardTingle comentou (+1 btw). Existe uma grande e importante diferença entre segurança e proteção. Onde o último é o problema mitigado com modificadores de acesso; para não quebrar as coisas por acidente
usuário
3
Tudo isso é bastante claro para os programadores, onde modificadores de acesso não existem, como em Python. Nessas linguagens, privado / público são simplesmente distinguidos por uma convenção nos nomes (em python, qualquer coisa que comece com um único sublinhado deve ser considerada privada). Isso deixa bem claro que marcar algo como "privado" não adiciona nenhuma segurança, mas é apenas uma maneira simples de dizer o que as pessoas devem usar de sua API. Tenho minhas dúvidas de que ter uma verificação do compilador para essas coisas ajude em tudo, já que é muito fácil seguir a convenção sem ajuda "externa".
Bakuriu

Respostas:

95

Depende do que você entende por "seguro". Se você estiver trabalhando com um gerenciador de segurança que permite esse tipo de coisa, então sim, você pode fazer todos os tipos de coisas desagradáveis ​​com reflexão. Mas nesse tipo de ambiente, a biblioteca provavelmente pode ser modificada para tornar o método público de qualquer maneira.

O controle de acesso é efetivamente "consultivo" em um ambiente como esse - você está efetivamente confiando que o código funcionará bem. Se você não confia no código que está executando, deve usar um gerenciador de segurança mais restritivo.

Jon Skeet
fonte
3
Tangencial, eu sei, mas você poderia elaborar um pouco sobre o que um gerente mais restritivo seria nesse sentido?
Gray
12
@Gray: Uma instância de SecurityManager que lança exceções nas check*chamadas relevantes , basicamente.
Jon Skeet
40

Os modificadores de acesso não têm nada a ver com segurança. Na verdade, você pode e deve considerar os modificadores de acesso como o reverso da segurança - não é para proteger seus dados ou algoritmos, é para proteger as pessoas da necessidade de saber sobre seus dados e algoritmos. É por isso que o modificador padrão é pacote - se eles estão trabalhando no pacote, provavelmente já precisam saber.

Junto com o conhecimento dos dados e dos métodos de seu código, vem a responsabilidade de saber quando e como usá-lo. Você não coloca private em seu método inIt para evitar que alguém descubra sobre ele, você faz isso porque (a) eles não vão saber que você só chama isso depois de foo e somente se bar = 3,1415 e (b) porque não adianta nada saber disso.

Modificadores de acesso pode ser resumido em uma frase simples "TMI, cara, eu então não precisa saber disso."

Jmoreno
fonte
3
Ótima resposta, mas eu precisava pesquisar no Google para descobrir que TMI significava muita informação. Acho que preciso passar mais tempo no vale :-)
mikelong
7

Ao dizer 'seguro', você está protegendo você ou outros desenvolvedores, que estão usando sua API para não danificar o objeto chamando seu método privado. Mas se você ou eles realmente precisarem chamar esse método, eles podem fazer isso com o Reflection.

Arsen Alexanyan
fonte
6

A questão é de quem você está tentando salvá- lo. Em minha opinião, esse cliente de seu código é o que perde aqui.

Qualquer código (escrito por você ou outros) que tenta acessar um privatemembro da classe acima está essencialmente cavando sua própria cova. privateos membros não fazem parte da API pública e estão sujeitos a alterações sem aviso prévio. Se por acaso um cliente consumir um de tais membros privados da maneira dada acima, ele irá falhar se for atualizado para uma versão mais recente da API na qual o membro privado foi modificado.

hthserhs
fonte
5

Com facilidade, vem a responsabilidade. Existem coisas que você não pode fazer e coisas que você pode fazer, mas não deve fazer.

O modificador privado é fornecido / usado como / da maneira mais restrita. Membros que não deveriam ser visíveis fora da classe devem ser definidos como privados. Mas isso pode ser quebrado com a Reflexão como vemos. Mas isso não significa que você não deva usar private - ou eles não são seguros. É sobre você usar as coisas de forma criteriosa ou construtiva (como reflexão).

Raúl
fonte
5

Supondo que você confie no programador cliente de sua API, outra maneira de ver é o quão 'seguro' é para eles usarem essas funções específicas.

Suas funções publicamente disponíveis devem fornecer uma interface clara, bem documentada e que raramente muda em seu código. Suas funções privadas podem ser consideradas um detalhe de implementação e podem mudar com o tempo, portanto, não são seguras para uso direto.

Se um programador cliente se esforça para contornar essas abstrações, ele está de certa forma declarando que sabe o que está fazendo. Mais importante, eles entendem que não há suporte e podem parar de funcionar com versões futuras de seu código.

robbie_c
fonte
5

privatenão é para segurança, é para manter o código limpo e evitar erros. Ele permite aos usuários modularizar o código (e como ele é desenvolvido) sem ter que se preocupar com todos os detalhes dos outros módulos

Depois de liberar seu código, as pessoas podem descobrir como ele funciona. Não há como "ocultar" a lógica se você quiser que o código seja executado em um computador. Mesmo a compilação para binário é apenas um nível de ofuscação.

Portanto, não há como configurar sua API para fazer coisas especiais que você não deseja que outras pessoas possam chamar. No caso de uma API da web, você pode colocar os métodos que deseja controlar no lado do servidor.

Manishearth
fonte