Noções básicas de segurança Java
1. Visão geral
Neste tutorial, veremos os princípios básicos de segurança na plataforma Java. Também vamos nos concentrar no que está disponível para escrevermos aplicativos seguros.
A segurança éa vast topic that encompasses many areas. Alguns deles fazem parte do próprio idioma, como modificadores de acesso e carregadores de classes. Além disso, outros estão disponíveis como serviços, que incluem criptografia de dados, comunicação segura, autenticação e autorização, entre outros.
Portanto, não é prático obter uma visão significativa de tudo isso neste tutorial. No entanto, vamos tentar obter pelo menos um vocabulário significativo.
2. Características da linguagem
Acima de tudo,security in Java begins right at the level of language features. Isso nos permite escrever código seguro, além de nos beneficiarmos de muitos recursos de segurança implícitos:
-
Digitação de dados estáticos: Java é uma linguagem digitada estaticamente, quereduces the possibilities of run-time detection of type-related errors
-
Modificadores de acesso: Java nos permite usardifferent access modifiers like public and private to control access to fields, methods, and classes
-
Gerenciamento automático de memória: Java temgarbage-collection based memory management, o que libera os desenvolvedores de gerenciar isso manualmente
-
Verificação de bytecode: Java é uma linguagem compilada, o que significa que converte o código em bytecode independente de plataforma eruntime verifies every bytecode it loads for execution
Esta não é uma lista completa dos recursos de segurança fornecidos pelo Java, mas é boa o suficiente para nos dar alguma garantia!
3. Arquitetura de segurança em Java
Antes de começarmos a explorar áreas específicas, vamos passar algum tempo entendendo a arquitetura central de segurança em Java.
Os princípios básicos de segurança em Java são orientados porinteroperable and extensible Provider implementations. Uma implementação particular deProvider pode implementar alguns ou todos os serviços de segurança.
Por exemplo, alguns dos serviços típicos que umProvider pode implementar são:
-
Algoritmos criptográficos (como DSA, RSA ou SHA-256)
-
Recursos de geração, conversão e gerenciamento de chaves (como chaves específicas de algoritmos)
Java vem commany built-in providers. Além disso, é possível que um aplicativo configure vários provedores com uma ordem de preferência.
Consequentemente, a estrutura do provedor emJava searches for a specific implementation of a service in all providers in the order of preference definida neles.
Além disso, sempre é possível implementar provedores personalizados com funções de segurança conectáveis nesta arquitetura.
4. Criptografia
A criptografia é a pedra angular dos recursos de segurança em geral e em Java. Isso se refere atools and techniques for secure communication in the presence of adversaries.
4.1. Criptografia Java
OJava Cryptographic Architecture (JCA) fornece uma estrutura para acessar e implementar funcionalidades criptográficas em Java, incluindo:
-
Assinaturas digitais
-
Códigos de autenticação de mensagens
-
Principais geradores e principais fábricas
Mais importante ainda, Java usaProvider-based implementations para funções criptográficas.
Além disso, o Java inclui provedores internos para algoritmos criptográficos comumente usados como RSA, DSA e AES, para citar alguns. Podemosuse these algorithms to add security to data em repouso, em uso ou em movimento.
4.2. Criptografia na Prática
Um caso de uso muito comum em aplicativos é armazenar senhas de usuários. Usamos isso para autenticação posteriormente. Agora, é óbvio que o armazenamento de senhas em texto simples compromete a segurança.
Portanto, uma solução é embaralhar as senhas de modo que o processo seja repetível, mas apenas unidirecional. Esse processo é conhecido como função hash criptográfica e o SHA1 é um desses algoritmos populares.
Então, vamos ver como podemos fazer isso em Java:
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] hashedPassword = md.digest("password".getBytes());
Aqui,MessageDigest é um serviço criptográfico no qual estamos interessados. Somosusing the method getInstance() to request this service from any of the available security providers.
5. Infraestrutura de chave pública
Infraestrutura de chave pública (PKI) se refere asetup that enables the secure exchange of information over the network using public-key encryption. Essa configuração depende da confiança criada entre as partes envolvidas na comunicação. Essa confiança é baseada em certificados digitais emitidos por uma autoridade neutra e confiável conhecida como Autoridade de Certificação (CA).
5.1. Suporte à PKI em Java
A plataforma Java tem APIs parafacilitate the creation, storage, and validation of digital certificates:
-
KeyStore: Java fornece a classeKeyStore para armazenamento persistente de chaves criptográficas e certificados confiáveis. Aqui,KeyStore can represent both key-store and trust-store files. Esses arquivos têm conteúdo semelhante, mas variam em seu uso.
-
CertStore: Além disso, Java tem a classeCertStore, que representa um repositório público de certificados e listas de revogação potencialmente não confiáveis. Precisamos recuperar certificados e listas de revogaçãofor certificate path building amongst other usages.
Java tem umbuilt-in trust-store called “cacerts” que contém certificados para CAs bem conhecidos.
5.2. Ferramentas Java para PKI
Java possui algumas ferramentas realmente úteis para facilitar a comunicação confiável:
-
Existe uma ferramenta interna chamada “keytool” para criar e gerenciar o armazenamento de chaves e o armazenamento confiável
-
Há também outra ferramenta “jarsigner” que podemos usar para assinar e verificar arquivos JAR
5.3. Trabalhando com certificados em Java
Vamos ver como podemos trabalhar com certificados em Java para estabelecer uma conexão segura usando SSL. Uma conexão SSL autenticada mutuamente exige que façamos duas coisas:
-
Apresentar certificado - precisamos apresentar um certificado válido para outra parte na comunicação. Para isso, precisamos carregar o arquivo de armazenamento de chaves, onde devemos ter nossas chaves públicas:
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
char[] keyStorePassword = "changeit".toCharArray();
try(InputStream keyStoreData = new FileInputStream("keystore.jks")){
keyStore.load(keyStoreData, keyStorePassword);
}
-
Verificar certificado - Também precisamos verificar o certificado apresentado por outra parte na comunicação. Para isso, precisamos carregar o armazenamento confiável, onde devemos ter certificados previamente confiáveis de outras partes:
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
// Load the trust-store from filesystem as before
Raramente precisamos fazer isso programaticamente e normalmente transmitimos parâmetros do sistema para Java em tempo de execução:
-Djavax.net.ssl.trustStore=truststore.jks
-Djavax.net.ssl.keyStore=keystore.jks
6. Autenticação
A autenticação é oprocess of verifying the presented identity of a user ou máquina com base em dados adicionais como senha, token ou uma variedade de outras credenciais disponíveis hoje.
6.1. Autenticação em Java
As APIs Java usampluggable login modules para fornecer mecanismos de autenticação diferentes e frequentemente múltiplos para aplicativos. LoginContext fornece essa abstração, que por sua vez se refere à configuração e carrega umLoginModule apropriado.
Enquanto vários provedores disponibilizam seus módulos de login,Java has some default ones available para uso:
-
Krb5LoginModule, para autenticação baseada em Kerberos
-
JndiLoginModule, para autenticação baseada em nome de usuário e senha apoiada por um armazenamento LDAP
-
KeyStoreLoginModule, para autenticação baseada em chave criptográfica
6.2. Entrar por Exemplo
Um dos mecanismos mais comuns de autenticação é o nome de usuário e a senha. Vamos ver como podemos conseguir isso por meio deJndiLoginModule.
Este módulo é responsável por obter o nome de usuário e a senha de um usuário e verificar em um serviço de diretório configurado no JNDI:
LoginContext loginContext = new LoginContext("Sample", new SampleCallbackHandler());
loginContext.login();
Aqui, somosusing an instance of LoginContext to perform the login. LoginContext leva o nome de uma entrada na configuração de login - neste caso, é “Amostra”. Além disso, temos que fornecer uma instância deCallbackHandler, usando oLoginModule que interage com o usuário para obter detalhes como nome de usuário e senha.
Vamos dar uma olhada em nossa configuração de login:
Sample {
com.sun.security.auth.module.JndiLoginModule required;
};
Simples o suficiente, sugere que estamos usandoJndiLoginModule comoLoginModule obrigatório.
7. Comunicação segura
A comunicação pela rede é vulnerável a muitos vetores de ataque. Por exemplo, alguém pode entrar na rede e ler nossos pacotes de dados enquanto eles estão sendo transferidos. Ao longo dos anos, o setor estabeleceu muitos protocolos para proteger essa comunicação.
7.1. Suporte Java para comunicação segura
Java forneceAPIs to secure network communication comencryption, message integrity, and both client and server authentication:
-
SSL/TLS: SSL and its successor, TLS, provide security over untrusted network communication through data encryption and public-key infrastructure. Java fornece suporte de SSL / TLS por meio deSSLSocket definido no pacote “java.security.ssl“.
-
SASL: Camada de autenticação e segurança simples (SASL) é um padrão para autenticação entre cliente e servidor. Java oferece suporte a SASL como parte do pacote “java.security.sasl“.
-
GGS-API/Kerberos: Generic Security Service API (GSS-API) offers uniform access to security services over a variety of security mechanisms like Kerberos v5. Java suporta GSS-API como parte do pacote “java.security.jgss“.
7.2. Comunicação SSL em ação
Vamos agora ver como podemos abrir uma conexão segura com outras partes emJava using SSLSocket:
SocketFactory factory = SSLSocketFactory.getDefault();
try (Socket connection = factory.createSocket(host, port)) {
BufferedReader input = new BufferedReader(
new InputStreamReader(connection.getInputStream()));
return input.readLine();
}
Aqui, estamos usandoSSLSocketFactory para criarSSLSocket. Como parte disso, podemos definir parâmetros opcionais, como conjuntos de cifras e qual protocolo usar.
Para que isso funcione corretamente,we must have created and set our key-store and trust-store como vimos anteriormente.
8. Controle de acesso
Controle de acesso refere-se aprotecting sensitive resources like a filesystem ou base de código de acesso indevido. Isso geralmente é conseguido restringindo o acesso a esses recursos.
8.1. Controle de acesso em Java
Podemosachieve access control in Javausing classes Policy and Permission mediated through the SecurityManager class. SecurityManager faz parte do pacote “java.lang” e é responsável por impor verificações de controle de acesso em Java.
Quando o carregador de classes carrega uma classe no tempo de execução, ele concede automaticamente algumas permissões padrão para a classe encapsulada no objetoPermission. Além dessas permissões padrão, podemos conceder mais alavancagem a uma classe por meio de políticas de segurança. Eles são representados pela classePolicy.
Durante a sequência de execução do código, se o tempo de execução encontrar uma solicitação para um recurso protegido,SecurityManager verifies the requested Permission against the installed Policy através da pilha de chamadas. Conseqüentemente, ele concede permissão ou lançaSecurityException.
8.2. Ferramentas Java para política
Java tem uma implementação padrão dePolicy que lê os dados de autorização do arquivo de propriedades. No entanto, as entradas de política nesses arquivos de política precisam estar em um formato específico.
O Java é fornecido com o "policytool", um utilitário gráfico para compor arquivos de políticas.
8.3. Controle de acesso através de exemplo
Vamos ver como podemos restringir o acesso a um recurso como um arquivo em Java:
SecurityManager securityManager = System.getSecurityManager();
if (securityManager != null) {
securityManager.checkPermission(
new FilePermission("/var/logs", "read"));
}
Aqui, estamos usandoSecurityManager para validar nossa solicitação de leitura para um arquivo, agrupado emFilePermission.
Mas,SecurityManager delega essa solicitação paraAccessController. AccessController usa internamente oPolicy instalado para chegar a uma decisão.
Vejamos um exemplo do arquivo de política:
grant {
permission
java.security.FilePermission
<>, "read";
};
Estamos concedendo permissão de leitura a todos os arquivos para todos. Mas,we can provide much more fine-grained control through security policies.
É importante notar que aSecurityManager pode não ser instalado por padrão em Java. Podemos garantir isso sempre iniciando o Java com o parâmetro:
-Djava.security.manager -Djava.security.policy=/path/to/sample.policy
9. Assinatura XML
As assinaturas XML sãouseful in securing data and provide data integrity. O W3C fornece recomendações para o controle da assinatura XML. Podemos usar a assinatura XML para proteger dados de qualquer tipo, como dados binários.
9.1. Assinatura XML em Java
A API Java suportagenerating and validating XML signatures de acordo com as diretrizes recomendadas. A API de assinatura digital Java XML está encapsulada no pacote “java.xml.crypto“.
A assinatura em si é apenas um documento XML. As assinaturas XML podem ser de três tipos:
-
Desanexado: esse tipo de assinatura está sobre os dados externos ao elemento Signature
-
Envelope: esse tipo de assinatura está sobre os dados internos ao elemento Signature
-
Envelope: esse tipo de assinatura está sobre os dados que contêm o próprio elemento Signature
Certamente, o Java suporta a criação e verificação de todos os tipos acima de assinaturas XML.
9.2. Criando uma assinatura XML
Agora, vamos arregaçar as mangas e gerar uma assinatura XML para nossos dados. Por exemplo, podemos estar prestes a enviar um documento XML pela rede. Portanto,we would want our recipient to be able to verify its integrity.
Então, vamos ver como podemos conseguir isso em Java:
XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM");
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
Document document = documentBuilderFactory
.newDocumentBuilder().parse(new FileInputStream("data.xml"));
DOMSignContext domSignContext = new DOMSignContext(
keyEntry.getPrivateKey(), document.getDocumentElement());
XMLSignature xmlSignature = xmlSignatureFactory.newXMLSignature(signedInfo, keyInfo);
xmlSignature.sign(domSignContext);
Para esclarecer, estamos gerando uma assinatura XML para nossos dados presentes no arquivo“data.xml”. Enquanto isso, há algumas coisas a serem observadas sobre este trecho de código:
-
Em primeiro lugar,XMLSignatureFactory é a classe de fábrica para gerar assinaturas XML
-
XMLSigntaure requer um objetoSignedInfo sobre o qual calcula a assinatura
-
XMLSigntaure também precisa deKeyInfo, que encapsula a chave de assinatura e o certificado
-
Finalmente,XMLSignature assina o documento usando a chave privada encapsulada comoDOMSignContext
Como resultado,the XML document will now contain the Signature element, que pode ser usado para verificar sua integridade.
10. Segurança além do Java principal
Como já vimos até agora, a plataforma Java fornece muitas das funcionalidades necessárias para escrever aplicativos seguros. No entanto, às vezes, eles são de nível bastante baixo e não são diretamente aplicáveis, por exemplo, ao mecanismo de segurança padrão na Web.
Por exemplo, ao trabalhar em nosso sistema,we generally don’t want to have to read the full OAuth RFC and implement that ourselves. Muitas vezes precisamos de maneiras mais rápidas e de nível superior para obter segurança. É aqui que as estruturas de aplicativos entram em cena - elas nos ajudam a alcançar nosso objetivo com muito menos código padrão.
E, na plataforma Java -generally that means Spring Security. A estrutura faz parte do ecossistema do Spring, mas na verdade pode ser usada fora do aplicativo puro do Spring.
Em termos simples, ajuda a obter autenticação, autorização e outros recursos de segurança de maneira simples, declarativa e de alto nível.
Claro, Spring Security é amplamente coberto ema series of tutorials, bem como de forma guiada, emLearn Spring Security course.
11. Conclusão
Em resumo, neste tutorial, examinamos a arquitetura de alto nível de segurança em Java. Além disso, entendemos como o Java nos fornece implementações de alguns dos serviços criptográficos padrão.
Também vimos alguns dos padrões comuns que podemos aplicar para obter segurança extensível e conectável em áreas como autenticação e controle de acesso.
Para resumir, isso nos fornece uma prévia dos recursos de segurança do Java. Consequentemente, cada uma das áreas discutidas neste tutorial merece mais explorações. Mas, esperançosamente, devemos ter insight suficiente para começar nessa direção!