Introdução ao Java SecurityManager

Introdução ao Java SecurityManager

1. Visão geral

Neste tutorial, daremos uma olhada na infraestrutura de segurança integrada do Java, que é desabilitada por padrão. Especificamente, examinaremos seus principais componentes, pontos de extensão e configurações.

2. SecurityManager em ação

Pode ser uma surpresa, masdefault SecurityManager settings disallowmany standard operations:

System.setSecurityManager(new SecurityManager());
new URL("http://www.google.com").openConnection().connect();

Aqui, habilitamos programaticamente a supervisão de segurança com as configurações padrão e tentamos conectar-se ao google.com.

Então temos a seguinte exceção:

java.security.AccessControlException: access denied ("java.net.SocketPermission"
  "www.google.com:80" "connect,resolve")

Existem vários outros casos de uso na biblioteca padrão - por exemplo, lendo propriedades do sistema, lendo variáveis ​​de ambiente, abrindo um arquivo, refletindo e alterando o código do idioma, para citar alguns.

3. Caso de Uso

Essa infraestrutura de segurança está disponível desde o Java 1.0. Era uma época em que os applets - aplicativos Java incorporados ao navegador - eram bastante comuns. Naturalmente, era necessário restringir seu acesso aos recursos do sistema.

Atualmente, os applets estão obsoletos. No entanto,security enforcement is still an actual concept when there is a situation in which third-party code executes in a protected environment.

Por exemplo, considere que temos uma instância do Tomcat em que clientes de terceiros podem hospedar seus aplicativos da web. Não queremos permitir que eles executem operações comoSystem.exit() porque isso afetaria outros aplicativos e possivelmente todo o ambiente.

4. Projeto

4.1. Gerente de segurança

Um dos principais componentes da infraestrutura de segurança integrada éjava.lang SecurityManager. Ele tem vários métodoscheckXxx comocheckConnect, que autorizava nossa tentativa de conexão com o Google no teste acima. Todos eles delegam ao métodocheckPermission(java.security.Permission).

4.2. Permissão

java.security.Permission instâncias representam solicitações de autorização. As classes JDK padrão os criam para todas as operações potencialmente perigosas (como ler / gravar um arquivo, abrir um soquete, etc.) e os entrega aSecurityManager para autorização apropriada.

4.3. Configuração

Definimos permissões em um formato de política especial. Essas permissões assumem a forma de entradasgrant:

grant codeBase "file:${{java.ext.dirs}}/*" {
    permission java.security.AllPermission;
};

A regracodeBase acima é opcional. Podemos não especificar nenhum campo ou usarsignedBy (integrado aos certificados correspondentes no armazenamento de chaves) ouprincipal (java.security.Principal anexado ao encadeamento atual por meio dejavax.security.auth.Subject). We can use any combination of those rules.

Por padrão, a JVM carrega o arquivo de política de sistema comum localizado em <java.home>/lib/security/java.policy. Se tivermos definido qualquer política local do usuário em<user.home>/.java.policy, a JVM a anexa à política do sistema.

Também é possível especificar o arquivo de política via linha de comando: -Djava.security.policy=/my/policy-file. Dessa forma, podemos anexar políticas ao sistema e às políticas de usuário carregadas anteriormente.

Há uma sintaxe especial para substituir todas as políticas do sistema e do usuário (se houver) - sinal de igual duplo: -Djava.security.policy==/my/policy-file

5. Exemplo

Vamos definir uma permissão personalizada:

public class CustomPermission extends BasicPermission {
    public CustomPermission(String name) {
        super(name);
    }

    public CustomPermission(String name, String actions) {
        super(name, actions);
    }
}

e um serviço compartilhado que deve ser protegido:

public class Service {

    public static final String OPERATION = "my-operation";

    public void operation() {
        SecurityManager securityManager = System.getSecurityManager();
        if (securityManager != null) {
            securityManager.checkPermission(new CustomPermission(OPERATION));
        }
        System.out.println("Operation is executed");
    }
}

Se tentarmos executá-lo com um gerenciador de segurança ativado, uma exceção será lançada:

java.security.AccessControlException: access denied
  ("com.example.security.manager.CustomPermission" "my-operation")

    at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
    at java.security.AccessController.checkPermission(AccessController.java:884)
    at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
    at com.example.security.manager.Service.operation(Service.java:10)

Podemos criar nosso arquivo<user.home>/.java.policy com o seguinte conteúdo e tentar executar novamente o aplicativo:

grant codeBase "file:" {
    permission com.example.security.manager.CustomPermission "my-operation";
};

Funciona muito bem agora.

6. Conclusão

Neste artigo, verificamos como o sistema de segurança JDK interno está organizado e como podemos estendê-lo. Mesmo que o caso de uso alvo seja relativamente raro, é bom estar ciente disso.

Como de costume, o código-fonte completo deste artigo está disponívelover on GitHub.