Archive

Archive for the ‘Segurança’ Category

Como Integrar o Apache Shiro a uma Aplicação JSF

O Shiro é um framework de segurança da Apache escrito em Java que permite a criação de soluções para autenticação, autorização, criptografia, gerenciamento de sessão e ainda fornece várias implementações de cache. Ele é simples de configurar e tem vários pontos de extensão que nos permitem intervir sobre seu funcionamento – são características de um framework bem projetado -, mas as configurações padrão já são suficientes para uma aplicação de pequeno porte.

Figura 1 – Arquitetura do Shiro

Nesse artigo, vou mostrar um exemplo de como integrar o Shiro a uma aplicação JSF. Nosso modelo será composto por uma enum chamada Permissao, uma enum Perfil para agrupar as permissões, e a entidade Usuario, que possui um Perfil:

public enum Permissao {
   CRIAR_PEDIDO, 
   LISTAR_PEDIDOS;
}

public enum Perfil {
   ADMINISTRADOR(Permissao.CRIAR_PEDIDO, Permissao.LISTAR_PEDIDOS);
   private List<Permissao> permissoes;
   private Perfil(Permissao... permissoes) {
      this.permissoes = Arrays.stream(permissoes).
         collect(Collectors.toList());
   }
}

@Entity
@Table(name = "TBL_USUARIO")
@TypeDefs(value = {@TypeDef(name = "TIPO_PERFIL" ...)})
public class Usuario {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "PK_USUARIO")
   private Long id;
   @Column(name = "NM_USUARIO")
   private String nome;
   @Column(name = "COD_PERFIL")
   @Type(type = "TIPO_PERFIL")
   private Perfil perfil;
}

Há várias formas de configurar o Shiro. Vou mostrar como configurá-lo à partir do arquivo de configuração shiro.ini. Precisamos incluir duas dependências no arquivo pom.xml – isso é o básico para o Shiro ser integrado a uma aplicação web:

<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-core</artifactId>
   <version>1.3.2</version>
</dependency>
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-web</artifactId>
   <version>1.3.2</version>
</dependency>

Em seguida, vamos configurar o arquivo shiro.ini, que deve ficar no classpath – eu costumo colocar em /src/main/resources. As seções desse arquivo agrupam propriedades que determinam o comportamento do Shiro. Basicamente, informamos qual é o Realm utilizado (será explicado mais adiante), qual é a página de autenticação para a qual o Shiro redirecionará o usuário não autenticado, para onde o usuário será redirecionado após o logout e também permite que informemos que há páginas privadas que só podem ser acessadas por usuários que tenham determinadas permissões. No nosso exemplo, a página “criarpedido.xhtml” só pode ser acessada por usuários que contenham a permissão “CRIAR_PEDIDO”.

[main]
apprealm = br.com.app.autorizacao.AppRealm
securityManager.realms = $apprealm
authc.loginUrl = /publico/index.xhtml
logout.redirectUrl = /publico/index.xhtml

[users]

[roles]
ADMINISTRADOR = *

[urls]
/privado/criarpedido.xhtml =  authc, perms["CRIAR_PEDIDO"]

No arquivo web.xml, configuraremos os filtros e listeners do Shiro e também informaremos quais são as páginas que responderão pelos códigos de erro HTTP.

<filter>
   <filter-name>ShiroFilter</filter-name>
   <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>

<filter-mapping>
   <filter-name>ShiroFilter</filter-name>
   <url-pattern>/*</url-pattern>
   <dispatcher>REQUEST</dispatcher>
   <dispatcher>FORWARD</dispatcher>
   <dispatcher>INCLUDE</dispatcher>
   <dispatcher>ERROR</dispatcher>
</filter-mapping>

<listener>
   <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener
</listener-class>
</listener>
	
<error-page>
   <error-code>401</error-code>
   <location>/publico/acessonegado.xhtml</location>
</error-page>

<error-page>
   <error-code>403</error-code>
   <location>/publico/acessonegado.xhtml</location>
</error-page>

<error-page>
   <error-code>404</error-code>
   <location>/publico/paginanaoencontrada.xhtml</location>
</error-page>

<error-page>
   <error-code>500</error-code>
   <location>/publico/erro.xhtml</location>
</error-page>

Essa é toda a configuração básica que qualquer aplicação web precisa para ser integrada ao Shiro. De agora em diante, começaremos a implementação do nosso mecanismo de autenticação e autorização. Só então você verá como é simples trabalhar com o Shiro. Uma peça importante do mecanismo de autenticação é o AuthenticationToken, que é a classe que mantém as credenciais do usuário. Você pode escolher uma das implementações dessa interface disponíveis, mas vamos criar uma implementação dela que recebe o ID do usuário:

public class IdAuthenticationToken implements AuthenticationToken {
   private Integer userId;

   public IdAuthenticationToken(Integer userId) {
      this.userId= userId;
   }

   @Override
   public Object getPrincipal() {
      return this.id;
   }

   @Override
   public Object getCredentials() {
      return this.id;
   }
}

Você precisará informar ao Shiro que um usuário está se autenticando. Você pode fazer isso à partir de um servlet, campos de input em um formulário de uma tela que é tratada por um ManagedBean, etc. Eu fiz através de um servlet porque antes que o usuário se autenticasse na minha aplicação era feita client authentication contra um Apache Server para validar o certificado digital. Modifiquei um pouco o código para indicar que as credenciais do usuário estão vindo pela request, que no meu caso era um post realizado pela aplicação que rodava em um JBoss debaixo daquele Apache. A credencial é apenas o atributo “userId”, que foi fornecido pela aplicação que validou o certificado digital.

@WebServlet(displayName = "AutenticacaoServlet", 
   name = "AutenticacaoServlet", urlPatterns = "/autenticar")
public class AutenticacaoServlet extends HttpServlet {

protected void doPost(HttpServletRequest request, 
      HttpServletResponse response)
     throws ServletException, IOException {
   Integer userId = (Integer) request.getAttribute("userId");
   Subject subject = SecurityUtils.getSubject();
   subject.login(new IdAuthenticationToken(token, userId));
   subject.checkPermission("CRIAR_PEDIDO");

   response.sendRedirect(request.getContextPath() + 
      "/private/criarpedido.xhtml?faces-redirect=true";

O Realm é um componente que interpreta os artefatos de segurança da aplicação – como usuários, regras e permissões – para o Shiro. Sendo o Realm a fonte de dados para autorização, podemos dizer, grosso modo, que ele é o DAO, ou melhor, um repository, que serve um modelo de autorização e autenticação.

Figura 2 – Sequência Simples de Autenticação

public class AppRealm extends SimpleAccountRealm {

   @Override
   protected AuthenticationInfo doGetAuthenticationInfo(
       AuthenticationToken token) throws AuthenticationException {
      IdAuthenticationToken authToken = (IdAuthenticationToken) token;
      Optional<Usuario> usuario = usuarioDao.buscar(token.getUserId());
      return new SimpleAuthenticationInfo(
         usuario.get(), usuario.get().getId(), getName());
   }

   @Override
   protected AuthorizationInfo doGetAuthorizationInfo(
        PrincipalCollection principals) {
      Set<String> roles = new HashSet<>();
      Set<String> permissions = new HashSet<>();

      Usuario usuario = (Usuario) SecurityUtils.getSubject().getPrincipal();
      Perfil perfil = usuario.getPerfil();

      roles.add(perfil.name());

      perfil.getPermissoes().forEach(a -> {
         permissions.add(a.nome());
      });

      SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
      info.setRoles(roles);
      info.setStringPermissions(permissions);
      return info;
   }

   @Override
   public String getName() {
      return getClass().getName();
   }

   @Override
   public boolean supports(AuthenticationToken token) {
      return IdAuthenticationToken.class.equals(token.getClass());
   }
}

Utilizamos a implementação SimpleAccountRealm, que é suficiente para o que nos propusemos a fazer. Se você quiser que o Shiro fique automaticamente consultando o banco de dados para carregar as permissões, basta utilizar um JdbcRealm e adicionar a consulta que o Shiro deve utilizar no arquivo shiro.ini.

Nesse momento, já temos um mecanismo que gerencia as credenciais do usuário e autoriza o acesso às páginas informadas na configuração inicial. Se você precisar fazer checagens de permissão ou verificar se o usuário está autenticado programaticamente, você deve acessar o Subject através do SecurityUtils ou utilizar as anotações do Shiro nos métodos das suas classes que devem ser autorizados.

Recomendações para Migração de Aplicações JSF “Puras”

Se você tem uma implementação de PhaseListener que de alguma forma toma decisões com base na URL acessada em sua aplicação JSF, remova-o. Na verdade, você deveria remover filtros, servlets e quaisquer outras implementações interessadas em autorização. Quem cuidará disso é o Shiro – mais especificamente a sua implementação de Realm.

É comum que aplicações JSF tenham uma ExceptionHandlerFactory para interceptar e tratar exceções nas páginas. Isso também não será necessário, pois o Shiro contém a ShiroException e suas variantes. Você também pode definir páginas específicas para tratar os códigos de erro HTTP mapeadas no seu arquivo web.xml.

Referências

1. [http://shiro.apache.org/reference.html]
2. [https://shiro.apache.org/java-authorization-guide.html]
3. [https://shiro.apache.org/authorization.html]
4. [https://shiro.apache.org/architecture.html]
5. [https://shiro.apache.org/configuration.html]
6. [http://galluzzo.com.br/?p=698]
7. [https://dzone.com/articles/java-security-framework-apache]
8. [http://czetsuya-tech.blogspot.com/2012/10/how-to-integrate-apache-shiro-with.html]
9. [http://www.javastutorial.com/2016/03/how-to-use-apache-shiroauthentication.html]

Como Gerar o Checksum de um Arquivo

Como expliquei no artigo Criptografia de Senha em Java, uma função de hash gera uma cadeia de caracteres de tamanho fixo a partir de uma sequência de qualquer tamanho; é uma equação matemática que a partir de um texto cria um código chamado message digest (resumo de mensagem), que é o resultado retornado por uma função de hash. Este pode ser comparado a uma impressão digital, pois cada documento possui um valor único de resumo e até mesmo uma pequena alteração no documento, como a inserção de um espaço em branco, resulta em um resumo completamente diferente.

Naquele artigo, mostrei como criptografar um texto utilizando o SHA-256, que é a variante mais utilizada do SHA-2. O código abaixo utiliza outros algoritmos (ou funções hash) para gerar o message digest do conteúdo de um arquivo qualquer. Quando esse resultado é utilizado para checar se um arquivo é genuíno e isento de erros, ele passa a ser chamado de hash sum ou mais popularmente de checksum:

public static void main(String[] args) throws Exception {
   byte[] fileBytes = Files.readAllBytes(Paths.get("/path/my_file.war"));
   Arrays.asList("MD5", "SHA-1", "SHA-256", "SHA-512").forEach((alg) -> {
      try {
         MessageDigest algoritmo = MessageDigest.getInstance(alg);
         byte digestMessage[] = algoritmo.digest(fileBytes);
         System.out.println(alg);
         System.out.println(new HexBinaryAdapter().marshal(digestMessage));
      } catch (NoSuchAlgorithmException e) {
         e.printStackTrace();
      }
   });
}

Utilizei o HexBinaryAdapter do Java, mas mas você poderia utilizar o Hex.encodeHexString(…) do Apache Commons ou ainda poderia converter os bytes para a versão hexadecimal manualmente byte-a-byte, assim:

(...)
StringBuilder hexPassword = new StringBuilder();
for (byte aByte : digestMessage) {
   hexPassword.append(String.format("%02X", 0xFF & aByte));
}
System.out.println(hexPassword.toString());

Alternativas

Se você só precisa do checksum e estiver utilizando Windows, você poderia baixar o FCIV da Microsoft, que pelo menos é um utilitário de linha de comando, ou o Hash Calculator, que mostra os checksums de forma gráfica. O FCIV é bem simples de utilizar:

C:\>fciv -SHA1 {ARQUIVO}

Referências

1. [http://howtodoinjava.com/core-java/io/how-to-read-file-content-into-byte-array-in-java/]
2. [http://www.adam-bien.com/roller/abien/entry/java_8_reading_a_file]
3. [http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#MessageDigest]
4. [http://www.devmedia.com.br/como-funciona-a-criptografia-hash-em-java/31139]
5. [https://www.lifewire.com/what-does-checksum-mean-2625825]

Uma Breve História das Moedas Virtuais

A história do dinheiro revela um desafio central: como desenvolver um sistema que possa efetivamente facilitar o intercâmbio de bens e serviços ao mesmo tempo que gera prosperidade e impede que as instituições que o administram abusem da confiança decorrente dessa função? No terceiro episódio da série O Futuro das Instituições Financeiras, Jim Kittridge apresentou uma Breve História das Moedas Virtuais. Curiosamente, essa história começa no século XIX. Antes de tratarmos das moedas virtuais, precisamos entender o que é uma moeda real e o que a faz ter um valor real.

A Moeda Fiduciária

Você já pensou quanto realmente vale uma cédula de Real em sua carteira? O valor real daquele pedaço de papel não é o que está estampado, mas sim o contrato que ele representa. Para que qualquer moeda se torne viável, é necessário que ela conquiste a confiança da comunidade: as pessoas devem concordar que o dinheiro pode ser trocado por bens e serviços. No caso das criptomoedas, a confiança deve ser independente de agentes governamentais ou financeiros.

Como podemos confiar no valor intrínseco da moeda? Um caminho é atrelá-la à um produto valioso, escasso e durável como o ouro – isso é chamado de lastro. Estando atrelada (lastreada), a moeda não fica tão suscetível à inflação. O valor de um bem está atrelado a diversos fatores, dentre eles a importância deste para o mercado e o quanto as pessoas estão dispostas a pagar pela mercadoria. Isso tudo se encontra dentro de uma sistemática ligada à oferta e a demanda.

De 1944 a 1971 o valor do dólar era fixado em US$ 35.00 por 31,1034768 gramas de ouro de acordo com o sistema de Bretton Woods. O sistema acabou em 1971, quando o presidente Richard Nixon cancelou a conversibilidade do dólar em ouro, deixando o câmbio flutuante e acabando com qualquer lastro do papel-moeda.

Moeda real ou fiduciária (fiat money) é qualquer título emitido por um governo central ou instituição financeira que seja não-conversível, ou seja, que não seja lastreado a nenhum metal (ouro, prata) e não tem nenhum valor intrínseco [2]. Seu valor advém da confiança (fidúcia, do latim fidere, confiar) que as pessoas têm em quem emitiu o título. A moeda fiduciária pode ser uma ordem de pagamento (cheques, por exemplo), títulos de crédito, notas promissórias, ou qualquer documento que você poderia aceitar como pagamento, confiando que, depois, o tal documento seria aceito como pagamento de outro produto ou serviço por outra pessoa ou empresa.

fiatmoney

Figura 1 – Moedas fiduciárias (fiat money)

Por exemplo, você aceita um cheque de R$ 500,00 pois sabe que tem fundos e que poderá utilizá-lo para pagar outra coisa. Não importa que seja apenas um pedaço de papel sem valor próprio, você confia que essa nota será aceita por qualquer pessoa, instituição ou comércio do Brasil como uma forma de pagamento. O Real é uma moeda de curso forçado, ou seja, uma pessoa não pode se negar a aceitá-lo como método de pagamento. O governo garante assim o valor da moeda como meio de troca e consegue criar dinheiro sem precisar de um ativo – como ouro – para servir de lastro [2].

As Primeiras Moedas Ditas Virtuais: Quem Iria Imaginar?

O Bitcoin não foi a primeira moeda virtual. Na verdade, não está nem próximo de ser a primeira. Além disso, as primeiras moedas virtuais tinham, contraintuitivamente, existência física. Você precisa voltar até 1896 para encontrar a primeira, que era chamada Selo S&H e foi lançada pela empresa Sperry and Hutchins. Os selos S&H eram vendidos em postos de gasolina e em supermercados que os davam como bonificação aos compradores que podiam então resgatar mercadorias específicas em um catálogo da S&H. Nos anos 60, a empresa tinha emitido 3 vezes mais selos que o serviço postal dos EUA. Na década de 70, a S&H alterou seu curso de um modelo de negócios baseado em selos e começou a entrar em declínio. Isso ocorreu porque a competição de grandes corporações cortou o intermediário, que era a própria S&H.

4fd2fa5b73f4cc14622ef6804c4ed8e5

Figura 2 – Selos S&H

A próxima moeda virtual a causar entusiasmo teve início em 1981 quando a American Air Lines lançou o American Advantage (AAdvantage), que foi o primeiro programa de milhagens aéreas. Hoje, toda companhia aérea e até mesmo empresas de aluguel de carros e a maior parte dos hotéis (EUA) oferecem alguma versão do programa de milhagem. Em 2005, a revista The Economist estimou que o valor total das milhas não resgatadas valia mais que todas as cédulas de dólar em circulação. As milhas aéreas são vendidas a preços razoáveis por milha e podem ser gastas em um número crescente de estabelecimentos e em uma infinidade de serviços – até mesmo para pagar por funerais! Ao longo dos últimos dez anos, as companhias aéreas fizeram mais dinheiro vendendo essa moeda virtual para companhias de cartões de crédito e hotéis do que realmente fizeram pelos vôos em si.

Uma outra moeda que tem crescido rapidamente, embora pouco usual, está na África. Uma vez que poucas pessoas na África dispõem de uma conta bancária e as moedas locais têm imensas volatilidades, as pessoas estão se voltando para seus celulares, que têm uma significativa penetração de mercado e estão usando minutos pré-pagos como moeda. Isso se tornou um negócio de bilhões de dólares por ano. A maior parte dos comércios e dos logistas aceitam minutos pré-pagos de boa vontade. Existem até mesmo empresas como a Ezetop, em Dublin na Irlanda, para ajudar os clientes a comprarem e venderem minutos e enviá-los para qualquer lugar do mundo. Minutos podem ser enviados internacionalmente via Internet ou mensagens SMS e são aceitos em mais de 450 mil estabelecimentos em mais de 20 países.

Pensando assim, de forma tão abrangente, muitas coisas podem ser consideradas moedas virtuais desde que todos concordem com o valor atribuído à coisa que se tornou moeda: escambo, comércio de vale refeição e vale transporte (muito comum na década de 90 quando eram emitidos em papel), latas de leve-leite (comum na cidade de São Paulo também na década de 90) e até sanduíches de presunto no caso do Chaves.

Agora Sim, as Moedas Virtuais do Jeito que Você Imagina

Uma moeda virtual não é emitida por nenhum governo. Ela é emitida por qualquer entidade onde um conjunto de usuários concorde sobre qual valor ela tem. Pode-se concluir que as moedas virtuais não tem “valor real”, mas que valor uma moeda fiduciária emitida pelo governo oferece que está além de um valor combinado por todos os usuários? Em muitos aspectos, todo o dinheiro fiduciário somente se distingue do dinheiro virtual porque nós, usuários, concordamos em um valor relativamente estável.

O Bitcoin não é sequer a primeira moeda online. Esse título pertence à empresa E-gold, que foi fundada em 1996. E-gold era uma moeda virtual lastreada por ouro real, algo com o qual nem mesmo as moedas fiduciária podem contar hoje em dia. Era o mesmo que negociar a propriedade do ouro de forma anônima. Em seu pico em 2008, o E-gold tinha mais de 5 milhões de contas. Contudo, sistemas de segurança fracos contribuíram para seu desaparecimento em 2009. Beenz, Flooz e Qcoins eram moedas online que surgiram depois do E-gold, mas tiveram os mesmos problemas de segurança. No caso do Qcoins (China), houve problemas com o governo que causaram sua vida curta.

No final de 2008, duas novas moedas de alto potencial foram lançadas. Bitcoin e Facebook Credits. Ambas apresentaram propostas para resolver os problemas de segurança das tentativas anteriores, mas de maneiras totalmente distintas. O Facebook Credits enfrentou uma morte prematura em 2012, não por causa de segurança ou fraude, mas porque só podia ser gasto dentro do Facebook, que na época era bem menor do que é hoje.

facebook-credits

Figura 3 – Facebook Credits

Em outubro de 2008, sob o pseudônimo de Satoshi Nakamoto, Craig Wright lançou um artigo técnico na Internet [6] em que ele propôs uma versão puramente ponto-a-ponto do dinheiro eletrônico e que garantia a segurança através de sofisticada técnica de encriptação baseada em um modelo matemático. Assim nasceu o Bitcoin, uma criptomoeda segura e um sistema de pagamento online baseado em protocolo de código aberto que é independente de qualquer autoridade central.

images

Figura 4 – Bitcoin

No âmbito da moeda virtual Bitcoin, um blockchain é a estrutura de dados que representa uma entrada de contabilidade financeira ou um registro de uma transação. Cada transação (bloco) é digitalmente assinada com o objetivo de garantir sua autenticidade e garantir que ninguém a adultere de forma que o próprio registro e as transações existentes dentro dele sejam considerados de alta integridade [10] – esses são alguns dos pilares da segurança da informação. Essa idéia foi, provavelmente, inspirada no conceito de autoridades certificadoras utilizado no mundo dos certificados digitais. Essa segurança nas transações dificultava muito a cópia do dinheiro. O conceito de bloco é a fundação que alicersa o Bitcoin e é conhecida como Blockchain.

1-newfxaocasu-zm9glkmejw

Figura 5 – Blockchain

Em janeiro de 2009, o primeiro bloco, de codinome Gênesis, foi lançado e permitiu que a mineração inicial de Bitcoins surgisse.

A Mineração de Bitcoins

O processo pelo qual os bitcoins entram no mercado é mais parecido com o que ocorre com o ouro que, por sinal, também pode ser usado como moeda: tanto o ouro quanto os bitcoins são obtidos por mineração (do inglês, mining) [7]. Para minerar bitcoins é necessário um computador rodando um programa Bitcoin Miner (Minerador de Bitcoin) que esteja ligado em rede a um conjunto de outros computadores pertencentes a proprietários diversos ou organizações. Esse software gera os valores na conta de um usuário à partir de limites ajustados constantemente pela rede [7]. Esta rede tem nós dedicados à mineração e nós de instituições que negociam com a moeda virtual e que utilizam o mesmo software usado para mineração. Essa rede é descentralizada – não há um nó centralizador do processo. Ela é uma rede ponto-a-ponto, o que garante a não existência de uma autoridade ou algum tipo de governança que controle o processo de emissão e o valor da cotação.

Em intervalos controlados pelo software que administra o sistema e que está distribuído por todos os nós, é emitido um hash (sequência de bits gerada pelo algoritmo de criptografia) contendo um determinado valor criptografado. Tratei brevemente da função hash nesse artigo, mas lá o foco era como fazer isso programaticamente. A dificuldade em quebrar este hash – encontrar a chave que o gerou por criptografia – é ajustável. Ao ser lançado um novo hash, todos os nós dedicados à mineração se põem imediatamente a tentar decifrá-lo (quebrá-lo). Matematicamente, quebrar um hash significa encontrar os números primos que o geraram, o que é impossível de se fazer manualmente e demorariam décadas para fazer de forma automatizada com o poder computacional que temos. Porém, se alguém descobrir a solução da hipótese de Rieman, que é um dos problemas de Hilbert que ainda não foram solucionados, o mundo dos bitcoins entrará em ruínas. Quebrar o hash gerado é o desafio imposto aos mineradores de bitcoins.

O primeiro minerador que conseguir decifrar o hash recebe como recompensa um determinado número de bitcoins. Tão logo isto ocorra, aquele nó anuncia à toda a rede que quebrou o código e que aqueles bitcoins relacionados ao hash lhe pertencem. Assim que esta transação estiver registrada em todos os nós da rede, o que ocorre relativamento rápido, aquele feliz minerador pode fazer uso de seus bitcoins. A geração aleatória de hashes garante a escasses de moedas, o que inibe a ação de especuladores e a “inflação virtual”. A idéia da escasses nos remete aos tempos das moedas fiduciárias lastreadas por metais como o ouro.

cradle_psf

Figura 6 – Um paciente minerador

Referências

1. [https://www.youtube.com/watch?v=iHYjsOFkHn0]
2. [http://www.mundodosbancos.com/moeda-fiduciaria/]
3. [http://www.investopedia.com/terms/f/fiatmoney.asp?lgl=no-infinite]
4. [http://www.dummies.com/personal-finance/investing/how-the-fiat-system-works/]
5. [http://www.techtudo.com.br/artigos/noticia/2014/01/bitcoin-o-que-e.html]
6. [http://www.techtudo.com.br/noticias/noticia/2016/05/quem-e-satoshi-nakamoto-identidade-do-criador-do-bitcoin-e-revelada.html]
7. [http://www.techtudo.com.br/artigos/noticia/2014/01/bitcoin-a-mineracao-de-moedas.html]
8. [http://www.techtudo.com.br/tudo-sobre/bitcoin.html]
9. [http://computerworld.com.br/blockchain-o-que-e-e-como-funciona]
10. [https://letstalkbitcoin.com/blog/post/goodbye-mike-and-some-thoughts-about-bitcoin]
11. [https://dzone.com/articles/java-and-the-blockchain]

Implementação de Autorização com Token Utilizando RESTEasy

Gosto bastante de desenvolver orientado a aspectos. A especificação JAX-RS possibilita implementar um mecanismo de autorização simples para seu web service REST. Um mecanismo de segurança simples ainda é melhor do que não ter segurança e a segurança deve ser definida como parte da arquitetura e não como uma funcionalidade.

Nesse exemplo, vamos mostrar como implementar um mecanismo de autorização baseado em token que é verificado em um interceptador do RESTEasy. Você poderia utilizar um ContainerRequestFilter ao invés do interceptor, mas você teria que utilizar a annotation @NameBinding em conjunto com a sua annotation para só então poder utilizá-la para anotar seu filtro.

1. Crie um enum que será utilizado para parametrizar sua anotação.

public enum Role {
   AUTHENTICATION_REQUIRED;
}

2. Crie uma anotação que utiliza a enum definida anteriormente para criar uma política de segurança. Essa anotação e aquela enum serão verificadas no interceptador. Você poderia utilizar outros métodos para identificar os recursos onde a política se aplicará, mas a combinação de enum e anotação é simples e elegante.

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
public @interface SecurityPolicy {
   Role[] value() default {};
}

3. Implemente um interceptador que verifica a anotação criada e a presença do atributo “TOKEN” no header da request. Note que além da anotação que criamos anteriormente (SecurityPolicy), estamos testando as anotações padrão PermitAll e DenyAll que poderiam estar anotando o recurso e são mais abrangentes que a nossa. Se tudo é permitido ou se tudo é negado, não faz sentido fazer uma verificação mais granular.

@Provider
@ServerInterceptor
public class SecurityInterceptor implements PreProcessInterceptor {
   @Override
   public ServerResponse preProcess(HttpRequest request, 
        ResourceMethod methodInvoked) 
      throws Failure, WebApplicationException {
      Method method = methodInvoked.getMethod();
      if (method.isAnnotationPresent(PermitAll.class)) {
         return null;
      }
      if (method.isAnnotationPresent(DenyAll.class)) {
         return new ServerResponse("Não pode acessar esse recurso",
         Status.UNAUTHORIZED.getStatusCode(), 
         new Headers<Object>());
      }
      if (method.isAnnotationPresent(SecurityPolicy.class)) {
         SecurityPolicy rolesAnnotation = 
           method.getAnnotation(SecurityPolicy.class);
         List<Role> roles = Arrays.asList(rolesAnnotation.value());
         if (roles.contains(Role.AUTHENTICATION_REQUIRED)) {
            HttpHeaders headers = request.getHttpHeaders();
            List<String> authorization = 
              headers.getRequestHeader("TOKEN");
            if(authorization != null && !authorization.isEmpty())
            {
               String token = authorization.get(0); 
               boolean autorizado = /*regras de autorizacao*/;
               if(autorizado){
                  // Deve-se retornar nulo para que o 
                  // processamento da request continue normalmente
                  return null;
               }
            }
            return new ServerResponse("Usuário não autorizado", 
              Status.FORBIDDEN.getStatusCode(),
              new Headers<Object>());
         }
      }
      // Deve-se retornar nulo para que o 
      // processamento da request continue normalmente
      return null;
   }
}

4. Crie um recurso e anote o método que exige a aplicação da política de segurança

@Path("/usuario")
public class UsuarioResource {
 
  @EJB
   private UsuarioService service;

   @GET
   @SecurityPolicy(Role.AUTHENTICATION_REQUIRED)
   @Path("/buscar")
   @Produces(MediaType.APPLICATION_JSON)
   public Response buscar(@PathParam("id") String id) {
      try {
         Usuario usuario = service.buscar(id);
         ResponseUsuario respUsuario = new ResponseUsuario();
         respUsuario.setNome(usuario.getNome());
         return Response.status(Response.Status.OK).
            entity(respUsuario).
            header("Content-type", "application/json; charset=utf-8").
            build();
      } catch (ServicoException e) {
          return Response.status(Response.Status.FORBIDDEN).
            entity("Nao foi possivel localizar o usuario.").
            header("Content-type", "application/json; charset=utf-8").
            build();
      }
      return Response.status(Response.Status.UNAUTHORIZED).
        entity("Usuário não autorizado.").
        header("Content-type", "application/json; charset=utf-8").
        build();
   }
}

Você poderia utilizar algum navegador para testar o funcionamento do seu web service, mas prefiro utilizar o SOAPUI. Se você tiver alguma problema relacionado a certificado do Java, dê uma olhada nesse artigo.

token

Figura 1 – Interface do SOAPUI

Note o parâmetro “TOKEN” que passamos no cabeçalho da request. O ideal é que o valor seja obtido do próprio web service, talvez acessando o banco de dados, e que este tenha um tempo de expiração que faça sentido para o negócio e para alguma política de segurança da informação de nível operacional.

Referências

1. [http://stackoverflow.com/questions/26777083/best-practice-for-rest-token-based-authentication-with-jax-rs-and-jersey
2. [https://www.infoq.com/br/news/2012/10/autenticacao-rest
3. [http://blog.rivendel.com.br/2013/06/07/seguranca-em-apis-rest-parte-1/
4. [http://www.slideshare.net/stormpath
5. [http://www.developerscrappad.com/1814/java/java-ee/rest-jax-rs/java-ee-7-jax-rs-2-0-simple-rest-api-authentication-authorization-with-custom-http-header/
6. [http://stackoverflow.com/questions/26777083/best-practice-for-rest-token-based-authentication-with-jax-rs-and-jersey
7. [https://www.mkyong.com/webservices/jax-rs/get-http-header-in-jax-rs/
8. [http://howtodoinjava.com/resteasy/jax-rs-resteasy-basic-authentication-and-authorization-tutorial/
9. [http://howtodoinjava.com/resteasy/jax-rs-2-0-resteasy-3-0-2-final-security-tutorial/[

Criptografia de Senha em Java

Uma senha armazenada em sua forma original pode ser visualizada por qualquer pessoa ou aplicação que tenha acesso ao banco de dados. As senhas também podem ser interceptadas com fishing. Uma boa prática de segurança é armazenar o hash da senha e não a senha original. Esse processo pode ser unidirecional ou bidirecional, mas quando é unidirecional é mais forte, pois para validar a senha informada pelo usuário, é necessário calcular o seu hash com o mesmo algoritimo criptográfico para só então comparar com a versão armazenada. Vamos mostrar um exemplo em Java, mas antes precisamos fazer uma breve explicação sobre o funcionamento da função de hash.

Função de Hash

Criptografia é um conjunto de princípios e técnicas utilizadas para codificar uma mensagem e torná-la ininteligível para os que não tenham acesso às convenções utilizadas na codificação.

Criptografia

Figura 1 – A ciência da criptografia

Uma função de dispersão criptográfica ou função hash criptográfica é uma função considerada praticamente impossível de inverter, isto é, de recriar o valor de entrada utilizando somente o valor de dispersão. Os dados de entrada são chamados de mensagem e o valor de dispersão é chamado de mensagem resumida ou simplesmente resumo.

hash

Figura 2 – Hashing

Uma função de dispersão criptográfica deve possuir as seguintes propriedades:

  • Resistência à pré-imagem: Dado um valor hash deve ser difícil encontrar qualquer mensagem m tal que h = hash(m). Este conceito está relacionado ao da função de mão única (ou função unidirecional). Funções que não possuem essa propriedade estão vulneráveis a ataques de pré-imagem.
  • Resistência à segunda pré-imagem: Dada uma entrada m1 deve ser difícil encontrar outra entrada m2 tal que hash(m1) = hash(m2). Funções que não possuem essa propriedade estão vulneráveis a ataques de segunda pré-imagem.
  • Resistência à colisão: Deve ser difícil encontrar duas mensagens diferentes m1 e m2 tal que hash(m1) = hash(m2). Tal par é chamado de colisão hash criptográfica. Essa propriedade também é conhecida como forte resistência à colisão. Ela requer um valor hash com pelo menos o dobro do comprimento necessário para resistência à pré-imagem.

Funções hash criptográficas possuem várias aplicações em segurança da informação como por exemplo os certificados digitais. Elas também podem ser utilizadas para indexar dados em tabelas, para detectar dados duplicados, identificar arquivos únicos e como checksum para detectar dados corrompidos.

Uma função de hash gera uma cadeia de caracteres de tamanho fixo a partir de uma sequência de qualquer tamanho. É uma equação matemática que a partir de um texto cria um código chamado message digest (resumo de mensagem). O resumo criptográfico é o resultado retornado por uma função de hash. Este pode ser comparado a uma impressão digital, pois cada documento possui um valor único de resumo e até mesmo uma pequena alteração no documento, como a inserção de um espaço em branco, resulta em um resumo completamente diferente.

É quase impossível achar duas mensagem que resultam no mesmo hash. Se mudar apenas um bit da mensagem original, o valor de hash muda completamente. Em criptografia, “dificuldade” geralmente significa “quase certamente longe do alcance de qualquer adversário que deve ser impedido de quebrar o sistema enquanto a segurança de tal sistema for importante”. O esforço que o agente malicioso deve colocar na tarefa é normalmente proporcional ao que ele espera conseguir. Entretanto, como o esforço necessário geralmente cresce rapidamente com o comprimento do resumo, até um atacante com um grande poder de processamento pode ser neutralizado adicionando algumas dúzias de bits ao resumo.

SHA-2 é um conjunto de funções hash criptográficas projetadas pela NSA (Agência de Segurança Nacional dos EUA). SHA significa secure hash algorithm (algoritmo de hash seguro). Dentre os variantes do SHA-2, a mais utilizada é o SHA-256. Em Java, SHA-256 função hash de 256 bits que fornece 128 bits de segurança contra ataques de colisão.

AppnimiSHA256DecrypterIcon256

Figura 3 – SHA-2

As aplicações que usam hashes criptográficos para armazenar senhas só são minimamente afetadas por um ataque de colisão. Se o algoritmo de hash for fraco, pode-se fazer um ataque de pré-imagem. Nesse caso, pode-se também tentar um ataque de força bruta à partir da inversão da encriptação das senhas.

Exemplo em Java

O código abaixo utiliza o algorítmo SHA-256 para codificar um array de bytes em um array de tamanho fixo (16 bytes). Cada byte desse array é convertido para uma versão hexadecimal:

   public String digest(String password) throws NoSuchAlgorithmException, 
         UnsupportedEncodingException {
      MessageDigest algoritmo = MessageDigest.getInstance("SHA-256");
      byte digestMessage[] = algoritmo.digest(password.getBytes("UTF-8"));
      StringBuilder hexPassword = new StringBuilder();
      for (byte aByte : digestMessage) {
         hexPassword.append(String.format("%02X", 0xFF & aByte));
      }
      return hexPassword.toString();
   }

O valor retornado pode ser armazenado em banco de dados. Para aumentar a dificuldade de êxito do atacante, poderíamos concatenar um valor aleatório (sal) à String original antes da conversão.

Referências

1. [http://www.devmedia.com.br/como-funciona-a-criptografia-hash-em-java/31139]
2. [http://blog.caelum.com.br/guardando-senhas-criptografadas-em-java/]
3. [http://docs.oracle.com/javase/7/docs/api/java/security/MessageDigest.html]
4. [https://pt.wikipedia.org/wiki/Fun%C3%A7%C3%A3o_hash_criptogr%C3%A1fica]
5. [https://pt.wikipedia.org/wiki/SHA-2]
6. [http://slideplayer.com.br/slide/397484/]

A Pirâmide de Maslow Aplicada à Análise da Decepção do Atacante Cibernético

Em 1943, o psicólogo Abraham Maslow publicou uma teoria que explica as motivações humanas e que hoje é amplamente aceita. A forma hierárquica com a qual as necessidades das pessoas são distribuídas ficou conhecida como a Pirâmide de Maslow:

6a00d8341c500653ef0128779b9b12970c

De forma geral, essa pirâmide descreve o que uma pessoa precisa para ser feliz indo das necessidades mais básicas – como alimentação – até a auto-realização e o conhecimento. Nitsan Saddan, Pesquisador Chefe de Inteligência de Ameaças na Cymmetria, propôs um modelo piramidal que agrupa e explica o que efetivamente decepciona ou, dito de outra forma, impede a felicidade de um atacante cibernético:

cyber_pyramid

Com a ajuda desse modelo, os profissionais de segurança podem planejar e implementar táticas e ferramentas que visam impedir o sucesso no ataque a uma infraestrutura – rede de decepção. Porém, o autor lembra que assim como a pirâmide de Maslow, a rede e as estratégias de decepção devem ser revistas e reorganizadas de tempos em tempos principalmente após um ataque em larga escala.

Análise Organizacional (Organization analysis)

Para ludibriar um atacante cibernético, as organizações primeiro devem se conhecer. Elas devem conhecer e saber utilizar bem suas tecnologias, seus processos de negócio, em que contexto estão inseridas, o que elas vendem e com quem competem. Identificados os ativos mais importantes, os profissionais de segurança podem identificar os elementos físicos e lógicos que mais precisam ser protegidos. Conhecendo os ativos, esses profissionais podem analisar os vetores de ataque, como engenharia social, vulnerabilidades no software, etc. Em seguida, deve-se procurar conhecer o inimigo. Para isso, deve-se analisar as ferramentas de ataque (modus operandi e malwares) possíveis para saber o que utilizar e em que locais da rede elas serão mais eficientes.

Defesa integrada em malha(Defense grid integration)

Consiste em determinar a posição das medidas de decepção cibernética em relação às outras medidas defensivas. A eficácia das medidas vem da integração das medidas de decepção com um SIEM e transferência dos dados de ataque para o IPS e o IDS.

Isca Incorruptível (Incorruptible decoy)

Iscas são partes integrantes das estratégias de decepção. Deve-se fazer com que o atacante acredite que acessou a rede permitindo acesso a um ambiente e dados que não podem ser corrompidos, o que poderia ser utilizado em um ataque destrutivo ao ambiente real.

Serviço indetectável (Undetectable service)

O sistema de decepção cibernética deve ser o mais autêntico possível. Ele deve emular respostas que façam o atacante acreditar que está na rede real. Pode-se utilizar honeypots para registrar e analisar o comportamento do atacante.

Engodo inevitável (Unavoidable lure)

O engodo é a primeira parte do planejamento da decepção do atacante cibernético. Deve-se fornecer elementos que chamem a atenção do atacante e que apontem para os ativos importantes, como senhas que possam ser utilizadas para adquirir privilégios. Analisar as estratégias e objetivos do atacante é útil para inserir o engodo bem no meio do seu caminho. A rede orientada à decepção do atacante é eficaz quando distribui os dados de ataque para outras ferramentas de segurança.

Como Utilizar o OpenSSL Para Criar um Arquivo p7b

O OpenSSL é um projeto open source que implementa os protocolos TLS (Transport Layer Security) e SSL (Secure Sockets Layer) utilizado por aplicações que precisam garantir a segurança na comunicação ou garantir a autenticidade da identidade de uma das partes comunicantes. Vamos mostrar como utilizar os comandos crl2pkcs7 e enc do OpenSSL para gerar um arquivo p7b à partir de arquivos que contém certificados digitais.

Função crl2pkcs7

A função crl2pkcs7 cria uma estrutura PKCS#7 à partir da LCR (Lista de Certificados Revogados) e de certificados.

-nocrl: indica que não haverá tentativa de inclusão da LCR no certificado gerado

-certfile filename: nome do arquivo que contém um ou mais certificados que serão inclusos na estrutura PKCS#7. Essa opção pode ser repetida no mesmo comando uma vez para cada arquivo.

-out filename: especifica o nome do arquivo onde a estrutura PKCS#7 será escrita.

Função enc

A função enc contém um conjunto de rotinas de criptografia simétrica.

-in filename: nome do arquivo

-out filename: nome do arquivo gerado

-d: decriptografa o arquivo de entrada

-base64: codifica os dados para base64 depois do processo de criptografia. Se a opção de decriptografia da entrada estiver setada, os dados são codificados para base64 depois da criptografia

Exemplo

openssl crl2pkcs7 -nocrl -certfile certificado1.cer 
-certfile certificado2.cer -certfile -out cadeia.p7b

openssl enc -d -base64 -in cadeia.p7b -out cadeia_bin.p7b

Referências

[https://www.openssl.org/]
[https://en.wikipedia.org/wiki/OpenSSL]
[https://www.tbs-certificates.co.uk/FAQ/en/openssl-windows.html]
[https://slproweb.com/products/Win32OpenSSL.html]
[http://serverfault.com/questions/617616/nginx-fails-to-load-a-file-ssl-certificate-even-if-its-clearly-there/617632]
[http://stackoverflow.com/questions/8249705/how-to-run-an-application-as-run-as-administrator-from-the-command-prompt]

Categorias:Segurança Tags:, , , , , , ,