Confiança, certificados digitais e autenticação

A diferença fundamental entre autenticação e confiança está na confirmação de algo. Enquanto que na autenticação duvidamos até que se prove a veracidade, na confiança acreditamos até que algum evento prove que estamos errados. Para usuários, o conceito de autenticação segue o mesmo princípio. Ele se identifica com seu nome, email etc. e, através de alguma das três formas descritas, confirmamos sua identidade:

  1. Através de algo que ele é: a biometria é, talvez, um dos métodos mais eficientes e seguros para se confirmar uma identidade. Impressão digital, DNA etc., são padrões com os quais o usuário nasce. É extremamente difícil falsificar esse tipo de padrão, mas também é relativamente caro e complexo utilizar esse tipo de autenticação em algumas aplicações
  2. Através de algo que ele saiba: essa é, provavelmente, uma das formas mais comumente utilizadas em uma aplicação. Quando solicitamos ao usuário uma senha, nome do primeiro professor, nome do bichinho de estimação etc., estamos pedindo algo que o usuário sabe e, teoricamente, apenas ele sabe.
  3. Através de algo que ele tenha: essa formatem sido cada vez mais utilizada por aplicações nas quais a autenticidade da informação é fundamental. É o caso, por exemplo, de internet banking, em que um Token ou um certificado digital é fornecido ao usuário. Quando utilizamos essa forma de autenticação, estamos usando algo que o usuário tem.

É comum, em uma aplicação, termos um formulário no qual o usuário informa um identificador (nome de usuário, email etc.) e uma senha. Chamamos essa senha de autenticador de identidade e, com ela, através de consulta em uma base de dados, verificamos se determinada senha pertence à determinada identidade. A grande pergunta que fica é: “A informação provida pelo usuário é autêntica?”

Uma vez que não temos como confirmar se foi, de fato, o dono da credencial que a utilizou, penso nessa verificação como confiança, e não como autenticação. O usuário pode ter perdido a senha, pode ter sido roubado, N coisas podem ter acontecido, inclusive ter emprestado a senha para alguém. Se outra pessoa, em vez do dono, estiver utilizando essa identidade, mesmo que o par “identidade e senha” seja válido, ele não é autêntico.

 

Certificado digital

O certificado digital é um arquivo que contém diversas informações sobre a identidade de alguém ou alguma coisa. Além de dados como nome (do indivíduo, da empresa ou de uma máquina), cidade, estado (UF), país etc., o certificado digital funciona como uma espécie de contrato, no qual uma autoridade certificadora assina o certificado, afirmando que os dados daquele certificado pertencem àquela identidade.

Cada certificado digital possui um par de chaves criptográficas assimétricas – uma pública, que é enviada para o destinatário, e uma privada, que é de posse e responsabilidade exclusiva do dono do certificado.

Quando uma comunicação é estabelecida, por exemplo, entre Fulano e Beltrano, Fulano recebe de Beltrano sua chave pública, utiliza sua chave privada para criptografar a informação para a chave pública de Beltrano e envia a mensagem. Como Fulano utilizou sua chave privada para criptografar para a chave pública de Beltrano, mesmo que a mensagem seja interceptada, apenas a chave privada de Beltrano poderá ser utilizada para descriptografar a mensagem de Fulano.

Essa abordagem é utilizada na autenticação digital de forma geral. Podemos utilizar um certificado digital para criptografar dados enviados entre cliente e servidor, para assinar digitalmente um documento, comprovando a leitura e a aceitação, para autenticação de usuários, para afirmar que os dados contidos em uma nota fiscal eletrônica são verdadeiros etc.

Para o propósito deste artigo, vamos usar um cenário hipotético de uma aplicação rodando em localhost. Essa aplicação chama-se example.localhost, e vamos fazer esse nome resolver para o IP 127.0.0.1. O primeiro passo é criar o certificado da CA.

Nota: Pressupõe-se, nos passos abaixo, que a máquina onde serão executados já possui openssl, Apache httpd, mod_ssl e php com a extensão openssl.

CA – Autoridade certificadora

1. Criaremos um diretório de forma que seja inacessível publicamente. Nesse diretório, criaremos as chaves e os certificados.

1
$ mkdir ~/certs

2. Dentro desse diretório, criaremos um diretório para o certificado da CA. Assim que criado, entramos nele diretório e utilizamos openssl para gerar a chave (vai solicitar a senha da chave):

1
2
3
4
5
6
7
8
9
$ mkdir ~/certs/ca
$ cd ~/certs/ca
$ opensslgenrsa -des3 -out ca.key 4096
Generating RSA private key, 4096 bit long modulus
.....................................................................++
.....................................................................++
e is 65537 (0x10001)
Enter pass phrase for ca.key:
Verifying - Enter pass phrase for ca.key

3. Utilizamos a chave para gerar uma requisição de assinatura (CSR) e o certificado da CA:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ opensslreq -new -x509 -days 365 -key ca.key -out ca.crt
Enter pass phrase for ca.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:BR
State or Province Name (full name) []:Sao Paulo
Locality Name (eg, city) [Default City]:Sao Paulo
Organization Name (eg, company) [Default Company Ltd]:iMasters
Organizational Unit Name (eg, section) []:dev
<b>Common Name (eg, your name or your server's hostname) []:Minha CA</b>
Email Address []:<a href="mailto:neto.joaobatista@localhost">neto.joaobatista@localhost</a>

Certificado do servidor

1. Criamos um diretório para o certificado do servidor de forma que seja inacessível publicamente. Da mesma forma que fizemos para a CA, vamos gerar a chave:

 

1
2
3
4
5
6
7
8
9
$ mkdir ~/certs/server
$ cd ~/certs/server
$ $ opensslgenrsa -des3 -out server.key 4096
Generating RSA private key, 4096 bit long modulus
...................................................................................++
...................................................................................++
e is 65537 (0x10001)
Enter pass phrase for server.key:
Verifying - Enter pass phrase for server.key:

2. Com a chave, vamos gerar uma requisição de assinatura (CSR) para o servidor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 $ opensslreq -new -key server.key -out server.csr
Enter pass phrase for server.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:BR
State or Province Name (full name) []:Sao Paulo
Locality Name (eg, city) [Default City]:Sao Paulo
Organization Name (eg, company) [Default Company Ltd]:iMasters
Organizational Unit Name (eg, section) []:dev
<b>Common Name (eg, your name or your server's hostname) []:example.localhost</b>
Email Address []:admin@example.localhost
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Nota: Perceba que, ao contrário do certificado da CA, utilizamos o nome do servidor em Common Name. Se não existir um nome de domínio, então o IP do servidor deverá ser utilizado.

3. Usamos o certificado da CA, que criamos anteriormente, para assinar a requisição de assinatura do servidor:

1
2
3
4
5
$ openssl x509 -req -days 365 -in ~/certs/server/server.csr -CA ~/certs/ca/ca.crt -CAkey ~/certs/ca/ca.key -set_serial 01 -out ~/certs/server/server.crt
Signature ok
subject=/C=BR/ST=Sao Paulo/L=Sao Paulo/O=iMasters/OU=dev/CN=example.localhost/emailAddress=admin@example.localhost
Getting CA Private Key
Enter pass phrase for /home/neto/certs/ca/ca.key:

Nesse instante temos: Chave privada da CA, Certificado da CA, Chave privada do servidor, Requisição de assinatura de certificado do servidor e Certificado do servidor assinado pela CA. Precisamos configurar o servidor:

1. Adicionamos a linha 127.0.0.1 example.localhost ao arquivo hosts (/etc/hosts). Isso garantirá a resolução do nome example.localhost para o IP 127.0.0.1:

1
2
3
4
5
 $ sed -i '1 i 127.0.0.1 example.localhost' /etc/hosts
 2. Criamos do DocumentRoot, onde serviremos nossa aplicação: 
$ mkdir /var/www/html/example /var/www/html/example/public
3. Criamos um VirtualHost para nosso example.localhost: 
$ vi /etc/httpd/conf.d/example.conf

 Nota: O conteúdo de /etc/httpd/conf.d/example.conf segue abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
NameVirtualHost 127.0.0.1:443
<Directory "/var/www/html/example">
        Options -Indexes
AllowOverride All
        Order allow,deny
        Allow from all
</Directory>
<VirtualHost 127.0.0.1:443>
SSLEngine ON
SSLCertificateFile /home/neto/certs/server/server.crt
SSLCertificateKeyFile /home/neto/certs/server/server.key
SSLCACertificateFile /home/neto/certs/ca/ca.crt
ServerAdminadmin@example.localhost
DocumentRoot /var/www/html/example/public
ErrorLog /var/www/html/example/error_log
ServerName example.localhost:443
LogLevel warn
ServerSignature On
</VirtualHost>

Após reiniciar o serviço httpd, já teremos acesso ao nosso example.localhost utilizando SSL. Um detalhe interessante é que, como nossa CA não é reconhecida pelo navegador, veremos uma tela como a abaixo:

01

Como podemos ver, voltamos àquela questão de confiança. Como o navegador (no caso, Firefox), não reconhece a CA, ele não consegue dizer se aquele certificado é autêntico. Isso pode ser um problema se estivermos trabalhando em um ambiente web, mas em um ambiente controlado, como de uma intranet, essa situação não é problemática, e basta adicionar o certificado da CA na lista de expedidores confiáveis do browser.

Configurando a aplicação

1. O primeiro passo para configurar a aplicação é fazer o servidor solicitar o certificado do usuário. Para isso, criaremos um arquivo .htaccess no diretório /var/www/html/example, com o seguinte conteúdo:

1
2
3
SSLVerifyClient optional
SSLVerifyDepth 1
SSLOptions +StdEnvVars

A primeira linha diz que o certificado é opcional. Se estivermos, por exemplo, em uma área administrativa da aplicação, podemos utilizar require em vez de optional. O require exigirá que o usuário tenha um certificado e, se não tiver, o servidor não permitirá acesso.

A segunda linha diz que o servidor deve verificar certificado do client e verificar a CA que o expediu. Isso é especialmente interessante, pois configuramos anteriormente o certificado da CA no nosso VirtualHost, ou seja, se o certificado do usuário não for expedido por uma CA em que o servidor confia, o servidor não permitirá acesso ao usuário.

A terceira linha vai pedir para o servidor definir as variáveis de ambiente com alguns dados do certificado. Essas variáveis estarão na super global $_SERVER, com o prefixo SSL_CLIENT_*. Vamos utilizar esses dados para autenticar o usuário.

Por uma questão de espaço, não vou demonstrar todo o código da aplicação de exemplo aqui, contudo, ela está disponível no Github e pode ser obtida através do seguinte:

1
2
$ git clone git://github.com/netojoaobatista/example.git
$ composer.phar install

Ao clonar o repositório, a seguinte estrutura será criada:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ cd ./example
$ find .
./.htaccess
./composer.json
./error_log
./public
./public/login.html
./public/login.php
./public/register.html
./public/register.php
./public/index.php
./src
./src/neto
./src/neto/openssl
./src/neto/openssl/CertificateSigningRequest.php
./src/neto/openssl/Certificate.php
./src/neto/openssl/CertificateKey.php
./src/neto/openssl/OpenSSLInfrastructure.php
./src/neto/Registration.php

Da mesma forma que utilizamos openssl para gerar os certificados da CA e do servidor, utilizaremos as funções openssl_* do PHP para gerar as chaves, as requisições de assinatura de certificado e os certificados do cliente. Abaixo, a descrição das funções utilizadas:

1
openssl_pkey_new

A função openssl_pkey_new será utilizada para a geração das chaves. Ela é equivalente ao seguinte:

1
2
3
openssl genrsa -des3 -out client.key 4096
openssl_csr_new

A função openssl_csr_new será utilizada para gerar a requisição do certificado. Ela é equivalente ao seguinte:

1
openssl req -new -key client.key -out client.csr

openssl_csr_sign

A função openssl_csr_sign será utilizada para assinar uma requisição de assinatura de certificado utilizando uma chave. Ela é equivalente ao seguinte:

1
openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt

Sempre que o usuário acessar a aplicação, verificaremos a existência de um certificado:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if (!isset($_SERVER['SSL_CLIENT_M_SERIAL']) ||
    !isset($_SERVER['SSL_CLIENT_V_END']) ||
    !isset($_SERVER['SSL_CLIENT_VERIFY']) ||
    $_SERVER['SSL_CLIENT_VERIFY'] !== 'SUCCESS' ||
    !isset($_SERVER['SSL_CLIENT_I_DN']) ||
    $_SERVER['SSL_CLIENT_V_REMAIN'] <= 0) {
//usuário não possui um certificado da aplicação
    //redirecionamos o usuário para o formulário de registro.
} else {
    //usuário possui um certificado da aplicação
    //utilizaremos as variáveis SSL_CLIENT_M_SERIAL e SSL_CLIENT_I_DN para
    //identificar o usuário na aplicação, verificar a validade do
    //certificado e, se o processo de autenticação for bem sucedido,
    //autorizamos o acesso.
}

Conclusão

Apesar de mais burocrático, a utilização de um certificado digital de cliente para autenticação adicionará uma camada de segurança à aplicação. Podemos, inclusive, chamar essa camada extra de autenticação em dois passos. Primeiro verificamos o certificado digital, sua validade (para uma política de renovação de credenciais) e, então, solicitamos ao usuário suas credenciais (nome e senha).

Uma vez autenticado no sistema, todas as ações do usuário podem ser assinadas; por exemplo, se a aplicação tratar de documentos que precisam ser aprovados pelo presidente da empresa, ele pode utilizar seu certificado digital para assinar o documento, evitando a impressão do documento e o tempo necessário para trafegar esse documento até sua sala.

Além disso, o uso de certificados digitais permite que os usuários da aplicação utilizem seus certificados para criptografar dados confidenciais. Por exemplo, essa medida foi utilizada pelo novo Mega para armazenar os arquivos dos usuários. Uma vez que a chave é assimétrica, apenas o dono da chave privada pode descriptografar um arquivo armazenado no servidor. Como o serviço Mega não possui essas chaves, eles podem alegar que não conhecem o conteúdo armazenado em seus servidores, isentando-se da responsabilidade e de acusações de pirataria.

 

Fonte: http://imasters.com.br/infra/seguranca/confianca-certificados-digitais-e-autenticacao/

Deixe um comentário