Segurança da Informação com Spring Security e JWT
Tags: spring, security, springsecurity, jwt
Published: 2020-11-24 14:12:31

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/zucs1dglddybqimzng0s.jpeg)

__Segurança da Informação__ trata de sistemas, recursos, metodologias de armazenamento, compartilhamento e quaisquer ativos que sirvam para impedir que dados sejam acessados, alterados por pessoas não autorizadas ou perdidos em desastres (proposital ou não). Selecionar e implementar controles de segurança adequados pode ajudar inicialmente uma organização a reduzir seus riscos a níveis aceitáveis e, em geral, eles são divididos em dois tipos: __controles físicos__ (são barreiras que impedem ou limitam o acesso físico direto as informações ou infraestrutura que contém as informações, como portas, trancas, alarmes, catracas, etc) e __controles lógicos__ (são barreiras que impedem ou limitam o acesso à informação por meio do monitoramento e controle de acesso a informações e a sistemas de computação, como senhas, criptografia, biometria, etc).

A segurança da informação se baseia sobre cinco princípios:

· Confidencialidade: este princípio diz que os dados podem ser acessados apenas por usuários legítimos e pessoas autorizadas, garantindo o sigilo da informação. A ferramenta que garante este princípio é a Criptografia (técnica que embaralha a informação por meio de algoritmos de criptografia, fazendo com que a informação se transforme em algo inteligível);

· Integridade: de acordo com este princípio, a informação só pode ser alterada por pessoas autorizadas, ou seja, a integridade garante o controle das alterações. Ele também garante a completude da informação, para que não haja perda de partes da informação. O emissor deve ser capaz de emitir um documento e o mesmo ser disponibilizado para o destinatário sem a possibilidade de ter sido alterado proposital ou acidentalmente. Quando funcionários excluem ou alteram dados importantes isso é considerado uma quebra desse princípio, o que ocorre também quando um vírus é responsável por essas alterações. As ferramentas que garantem este princípio são a: assinatura digital e o backup;

· Disponibilidade: de acordo com este princípio, a informação estará disponível sempre que for preciso para os usuários legítimos. Os sistemas utilizados para armazenar e processar os dados devem estar sempre funcionando de maneira correta. Como exemplo, imagine um banco que deixe seu sistema fora do ar durante o Natal, ele está ferindo o princípio da disponibilidade e afetando milhões de pessoas. Os equipamentos que garantem a disponibilidade de um sistema são: firewall, backups, redundância, equipamentos de energia, entre outros;

· Autenticidade: se refere a confirmação de que o usuário é realmente quem alega ser, desde quem está emitindo a informação até quem irá recebê-la, ou seja, garante a veracidade da autoria da informação;

· Irretratabilidade ou não repúdio: este princípio é derivado do princípio da autenticidade. Ele garante que o autor da informação não tem como recusar que ele é o verdadeiro autor, ou seja, é a incapacidade da negação da autoria da informação. As ferramentas que garantem o princípio da autenticidade são: biometria, assinatura digital, certificados digitais, entre outros.

__Spring Security__

É uma estrutura Java com foco em tornar a parte de autenticação e autorização algo mais simples de se fazer. Ele possui uma grande variedade de opções e é muito extensível. Com algumas poucas configurações, já podemos ter uma autenticação via banco de dados, LDAP ou até por memória. Além das integrações que ele suporta, há a possibilidade de criar suas próprias. Com o Security, também é possível protegermos as requisições web, através das permissões que atribuímos aos usuários autenticados.

__JSON Web Token (JWT)__

O JSON Web Token é um padrão que define uma forma segura de transmitir mensagens utilizando um token compacto e autocontido no formado de um objeto JSON. É uma estratégia de autenticação para APIs em REST simples e segura, é um padrão aberto para autenticações web totalmente baseado em requisições JSON entre o cliente e o servidor. A assinatura de um JWT é seu componente mais sensível por tratar justamente da segurança deste token. Para saber mais sobre o assunto, confira este artigo que explica o JWT no Spring em mais detalhes: https://blog.brq.com/autenticacao-jwt-no-spring-boot/

__Bearer Authentication__ (também chamado de token authentication) é um esquema de autenticação HTTP que envolve tokens de segurança, chamado de bearer tokens. Ele é uma String criptografada, geralmente gerada pelo servidor em resposta a uma solicitação de login. O cliente deve enviar este token no header (cabeçalho) da autorização ao fazer solicitações para recursos protegidos, como mostrado neste exemplo:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/w2pkdur3x8gkwks4kdng.png)

__Authorization Bearer__ eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Vamos colocar o JWT no site https://jwt.io/ para decodificar o token. Na sua forma compacta, o JWT consiste em três partes, que são separadas por ponto. São elas: Header (trecho em vermelho), Payload (trecho em azul) e Signature (trecho em preto).

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/89x3o16m1d3bybmiwst8.png)

O __Header__(Cabeçalho) consiste normalmente em duas partes, o tipo de token (que é JWT) e o algoritmo de assinatura que está sendo usado (como HMAC SHA256 ou RSA). No exemplo do nosso token, o JSON é codificado em Base64Url para formar a primeira parte do JWT, conforme a imagem a seguir:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/saq390lpcfwkureti0hx.png)

O __Payload__(carga útil) é a segunda parte do token e contém as informações (claims) sobre uma entidade (normalmente, um usuário) e alguns dados adicionais. Cada conjunto de chave/valor do payload é chamado de claims. O payload é o local que mantém os dados que realmente queremos transmitir por esse token. Existem três tipos de claims:

· Claims Registrados: trata-se de um conjunto de declarações predefinidas que não são obrigatórias, mas recomendados, para fornecer um conjunto de declarações uteis e interoperáveis. Alguns deles são: iss (emissor), exp (tempo de expiração), sub (quem é o dono do token, que normalmente é o usuário), aud (público), iat (diz o horário que o token foi emitido, no formato timestamp) e outros;

· Claims Públicos: podem ser definidas por aqueles que usam JWT, mas devem ser definidos no IANA JSON Web Token Registry ou ser definida como um URI que contém um namespace resistente a colisão;

· Claims Privados: são os claims personalizados criados para compartilhar informações entre as partes que concordam em usá-las e não são reivindicações registradas ou públicas.

Para os tokens assinados, embora as informações sejam protegidas contra adulterações, elas podem ser lidar por qualquer pessoa. Por isso, nunca insira informações sensíveis no header ou payload de um JWT, a não ser que ele esteja criptografado. Segundo o exemplo do nosso token JWT, o Payload ficou assim:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/arr5j8qboaxgu6ddovgf.png)

A __Signature__ (assinatura) é a última parte do token e é utilizado para validá-lo, verificando se o mesmo está integro. É aqui que passamos o "segredo" de decodificação do token. Para cria-lo, é necessário pegar o header codificado, o payload criptografado, um segredo, o algoritmo especificado no header e assiná-lo. A assinatura é utilizada para verificar se a mensagem não foi alterada ao longo do caminho e, no caso de tokens assinados com uma chave privada, também é possível verificar se o remetente do JWT é mesmo quem diz que é (princípio da Autenticidade). Vejamos o exemplo, segundo o nosso token:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fxfi740e80dee8pyo5np.png)

__Como o JWT funciona?__

Na autenticação, quando o usuário efetua login com sucesso utilizando suas credenciais, um JWT será retornado. O mecanismo de autenticação do JWT funciona da seguinte maneira:

1. O usuário faz uma solicitação apenas uma vez ao enviar as credencias de login e senha;
2. O servidor faz a validação das credenciais. Caso estejam corretas, retorna um JSON com um token que codifica dados de um usuário logado no sistema;
3. Após receber o token, o usuário poderá armazená-lo nos Cookies, LocalStorage ou através de outros mecanismos;
4. Toda vez que o usuário acessar uma rota que requer autenticação, ele precisa enviar apenas este token para a API fazer a autenticação e liberar o acesso;
5. O servidor sempre valida esse token para permitir ou bloquear uma solicitação do client.

Não é recomendável manter os tokens por muito tempo, pois se ele for "vazado" e alguém utilizá-lo, poderá acessar o seu sistema. Para evitar este tipo de problema, é altamente recomendável definir um tempo de expiração do token, que o tornará inválido após sua expiração. Assim o usuário será obrigado a fazer login novamente, gerando um novo token, para ter acesso ao sistema. Também, não se deve armazenar dados confidencias da sessão no armazenamento do navegador, devido à falta de segurança.

Sempre que o usuário deseje acessar uma rota ou recurso protegido, é necessário enviar o JWT (no header de autorização, através do Bearer), segundo o esquema __Authorization: Bearer <token>__. Caso o token seja enviado no header de autorização, o __Cross-Origin Resource Sharing (CORS)__ não será um problema, já que não utiliza cookies.

__Por que devemos usar o JWT?__

Comparado com o Simple Web Tokens (SWT) e aos Security Assertion Markup Language Tokens (SAML), o JWT possui diversas vantagens. Como o JSON é menos prolixo do que XML, o seu tamanho quando codificado também é menor, deixando o JWT mais compacto que o SAML. Com relação a segurança, o SWT só pode ser assinado simetricamente por um segredo compartilhado usando o algoritmos HMAC, enquanto os tokens JWT e SAML podem usar par de chaves pública/privada na forma de um certificado X.509 para assinatura.

Os JSON parse são comuns na maioria das linguagens de programação, pois eles mapeiam diretamente para objetos. Em contrapartida, o XML não possui um mapeamento natural de documento para objeto, tornando mais fácil se trabalhar com JWT do que com as asserções SAML.

__Cross-Origin Resource Sharing (CORS)__

O CORS é um mecanismo utilizado pelos navegadores para compartilhar recursos entre diferentes origens, fazendo uso de headers do HTTP para informar aos navegadores se determinado recurso pode ou não ser acessado. Ele é uma especificação do W3C.
Os navegadores fazem uso de uma funcionalidade de segurança conhecida como Same-Origin Policy, que nada mais é do que um recurso de um site que só pode ser chamado por outro site se ambos estivem sob o mesmo domínio (endereço), limitando a chamada de APIs REST por aplicações Javascript (por exemplo, hospedadas em servidores diferentes). Mesmo os subdomínios dos sites não são considerados seguros, sendo bloqueados pelo navegador.

Através do CORS, um domínio permite comunicação com outro de forma livre e independente da chamada (GET, POST, PUT e DELETE), desde que o domínio de destino tenha especificado esse tipo de comunicação. Geralmente, essa configuração é feita no lado da API, incluindo o Access-Control-Allow-Origin no header da resposta da API.

__Protocolo OAuth2__

__OAuth2__ é um protocolo (framework) de autorização muito utilizado, que permite que uma aplicação se autentifique com outra, mas sem manipular diretamente o nome de usuário e sua senha. Para que isso aconteça, uma aplicação pede permissão de acesso para um usuário, sem que tenha acesso a alguma senha dele, e o usuário pode conceder ou não o acesso à aplicação. Depois de aceitar a permissão, caso o usuário necessite alterar a senha de acesso, a permissão continuará válida para a aplicação e, se for necessário, a permissão dada à aplicação pode ser revogada a qualquer momento. Grandes empresas como Google, Facebook e Twitter já utilizam este padrão para prover o acesso a seus recursos de forma segura em aplicações de terceiros, ou seja, você está terceirizando a segurança dos dados dos usuários a sistemas que já os possuem e gerenciam.

O OAuth2 foi construído em cima de quatro papéis: __Resource Owner__ (pessoa ou entidade que concede o acesso a seus dados, chamado também de dono do recurso), __Client__ (é a aplicação que interage com o Resource Owner), __Resource Server__ (a API que está exposta na internet necessita da proteção dos dados, e para conseguir o acesso ao seu conteúdo, é necessário um token, que é emitido pela authorization server) e __Authorization Server__ (é o responsável por autenticar o usuário e emitir os tokens de acesso. É quem possui as informações do usuário, autenticando e interagindo com o mesmo após a identificação do cliente). O mecanismo de autenticação do OAuth2 funciona da seguinte maneira:

1. Solicitação de autorização: o cliente (aplicação) solicita a autorização para ter acesso aos recursos do servidor do usuário;
2. Concessão de autorização: se o usuário autorizar a solicitação, a aplicação recebe uma concessão de autorização;
3. Concessão de autorização: o cliente solicita um token de acesso ao servidor de autorização, através da autenticação da própria identidade e da concessão de autorização;
4. Token de acesso: caso a identidade da aplicação está autenticada e a concessão de autorização for válida, o servidor de autorização gera um token de acesso ao sistema;
5. Token de acesso: quando o cliente precisar solicitar um recurso ao servidor de recursos, basta apresentar o token de acesso;
6. Recurso protegido: o servidor de recursos fornece o recurso para o cliente, caso o token de acesso dele seja válido. O servidor de autorização é responsável pelo Single Sign One, que centraliza as credencias dos acessos dos usuários e faz a autenticação, gerencindo as permissões dos usuários e emitindo os tokens de acesso.

O __Client__ (aplicação que roda na máquina do usuário) é definido através de dois tipos de aplicação:__Confidential__ (clientes que são capazes de manter a confidencialidade das suas credenciais) e __Public__ (clientes que são incapazes de manter a confidencialidade das suas credenciais).

Com relação aos fluxos de autorização, existem quatro formas de se trabalhar com essa integração: __Implicit__ (é um fluxo de autorização simplificado, otimizado para clientes web. Ao emitir um token de acesso, o authorization server não autentica o cliente), __Authorization Code__ (é obtido utilizando um authorization server como intermediário entre o client e o usuário, onde o client redireciona o usuário para um servidor de autorização. Esse tipo é usado em aplicação não confiáveis), __Resource Owner Password Credentials__ (é utilizado quando o client solicita diretamente o usuário e senha, sendo utilizado em aplicações confiáveis, como aplicações da própria empresa) e __Client Credentials__ (pode ser utilizado quando a aplicação client é protegida, que são utilizados em integrações de sistemas). 

O JWT é uma forma segura e compacta para fazermos o tráfego de informações de um usuário. Já o OAuth2 é um framework de autorização que define vários fluxos de autorização para aplicações. Ou seja, podemos utilizar os dois ao mesmo tempo, já que ambos possuem funções e objetivos distintos. Caso queira se aprofundar mais no assunto, recomendo a leitura deste artigo: https://medium.com/rapaduratech/login-com-oauth2-usando-o-spring-security-4aefa3f57a63