Autenticação em APIs
Marcelo Milhomem
Agenda
Agenda
• HTTP REST API
• Autenticação
• SSL / Autoridade Certificadora / Certificados
• Aplicação em Mobile
Autenticação x Autorização
401 vs 403
• 401 Unauthorised - Não autenticado
Eu preciso saber quem você é
• 403 Forbidden - Não autorizado
Eu sei quem você é mas, você não tem direito
Autenticação hoje
HTTP Basic
(Usuário e Senha)
• Cleartext
• Precisa de SSL
• Fácil de "crackear"
• Usuário preguiçoso (mesma senha / senha fraca)
• Mesma senha em vários sistemas
OAuth
(Autenticação + Autorização)
Token / JWT
1 {
2 "sub": "1234567890",
3 "name": "John Doe",
4 "admin": true
5 }
1 HMACSHA256(
2 base64UrlEncode(header) + "." +
3 base64UrlEncode(payload),
4 secret)
1 eyJhbGciOiJIUzI1NiIsInR
2 5cCI6IkpXVCJ9.
3 eyJzdWIiOiIxMjM0NTY3ODk
4 wIiwibmFtZSI6IkpvaG4gRG
5 9lIiwiYWRtaW4iOnRydWV9.
6 TJVA95OrM7E2cBab30RMHrH
7 DcEfxjoYZgeFONFh7HgQ
Todos usam SSL
Por que o SSL?
Certificados
• Par de chaves assimétricas (Pública e Privada)
• Oferece a mesma coisa que o SSL
• Autentica o cliente através da assinatura digital
• Requer um `round trip` extra
Autoridade Certificadora (CA)
• Self signed (todo CA é)
• CA intermediário (cadeias de CA) - boa prática para evitar perda total em caso de
comprometimento da chave privada
• Você é a autoridade :0 dona da verdade
• Utilizar CA intermediários como ACL
Show Case
Ingredientes
Keystore
Certificado do Cliente Certificado do Servidor
Keystore
CA
Gerar certificado do cliente
Gerar certificado - PHP
Gerando par de chaves do cliente
1 /**
2 * Chave privada
3 */
4 $clientPrivateKey = new Crypt_RSA();
5 $clientPrivateKey->setPassword($password);
6 $generatedKeyPair = $clientPrivateKey->createKey();
7 $clientPrivateKey->loadKey($generatedKeyPair['privatekey']);
8 /**
9 * Chave pública
10 */
11 $clientPublicKey = new Crypt_RSA();
12 $clientPublicKey->loadKey($generatedKeyPair['publickey']);
13 $clientPublicKey->setPublicKey();
Gerar certificado - PHP
Par de chaves do CA
1 /**
2 * Chave privada do CA necessária para assinar
3 */
4 $privateKeyIntermediateCA = new Crypt_RSA();
5 $privateKeyIntermediateCA->setPassword('Intermediate CA password');
6 $privateKeyIntermediateCA->loadKey(file_get_contents($privateCAKeyPath));
7 /**
8 * Certificado do CA
9 */
10 $certificateIntermediateCA = new File_X509();
11 $certificateIntermediateCA->setPrivateKey($privateKeyIntermediateCA);
12 $certificateIntermediateCA->loadX509(file_get_contents($certificateCAKeyPath));
Certificado do Cliente - PHPAssinando o certificado
1 /**
2 * CSR - Requisição de certificado
3 */
4 $certificateSigningRequest = new File_X509();
5 $certificateSigningRequest->setDN($certificateIntermediateCA->getDN());
6 $certificateSigningRequest->setPublicKey((object)$clientPublicKey);
7 $certificateX509 = new File_X509();
8 $certificateX509->setEndDate('+1 month');
9 /**
10 * Assinatura do CA
11 */
12 $clientCertificate =
13 $certificateX509->sign($certificateIntermediateCA, $certificateSigningRequest);
14 /**
15 * Resultado chave privada + certificado do cliente
16 */
17 echo $clientPrivateKey->getPrivateKey();
18 echo PHP_EOL;
19 echo $certificateX509->saveX509($clientCertificate);
Certificado do Cliente - Android
1 /**
2 * Certificado do cliente + chave privada empacotados em um arquivo PFX
3 */
4 KeyStore keyStore = KeyStore.getInstance("PKCS12");
5 FileInputStream clientCertificateContent =
6 new FileInputStream("/path/to/publicAndPrivateKey.p12");
7 keyStore.load(clientCertificateContent, "private key password".toCharArray());
8 KeyManagerFactory keyManagerFactory =
9 KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
10 keyManagerFactory.init(keyStore, "private key password".toCharArray());
Embarcar CA
1 -----BEGIN CERTIFICATE-----
2 MIIDnzCCAwigAwIBAgIJAJZTKp0w82kyMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYD
3 VQQGEwJCUjETMBEGA1UECBQKU8OjbyBQYXVsbzETMBEGA1UEBxQKU8OjbyBQYXVs
4 bzERMA8GA1UEChMIRWFzeVRheGkxETAPBgNVBAsTCEVhc3lUYXhpMQswCQYDVQQD
5 EwJFVDEmMCQGCSqGSIb3DQEJARYXY29udGF0b0BlYXN5dGF4aS5jb20uYnIwHhcN
6 MTYwMTE4MTYwNDQ2WhcNMzYwMTEzMTYwNDQ2WjCBkjELMAkGA1UEBhMCQlIxEzAR
7 BgNVBAgUClPDo28gUGF1bG8xEzARBgNVBAcUClPDo28gUGF1bG8xETAPBgNVBAoT
8 CEVhc3lUYXhpMREwDwYDVQQLEwhFYXN5VGF4aTELMAkGA1UEAxMCRVQxJjAkBgkq
9 hkiG9w0BCQEWF2NvbnRhdG9AZWFzeXRheGkuY29tLmJyMIGfMA0GCSqGSIb3DQEB
10 AQUAA4GNADCBiQKBgQDTny6B8fbG1UXEtMYYFKfODKduzYTovLIUzXKFrX9wHEsC
11 lTOLqtvKsvkLkjXsC3R/HedWoRbFXJbaaw723csPlxrxuBqfkNBJB25ihccwVWbP
12 WpEaDluL2btsBdW2uuDshpXk2z6Gf5xcePnmf24iWpvJs1uBJWkEGRR2TzEi8wID
13 AQABo4H6MIH3MB0GA1UdDgQWBBRMm/EjlWrvxXTtUmotq+kwN52u3zCBxwYDVR0j
14 BIG/MIG8gBRMm/EjlWrvxXTtUmotq+kwN52u36GBmKSBlTCBkjELMAkGA1UEBhMC
15 QlIxEzARBgNVBAgUClPDo28gUGF1bG8xEzARBgNVBAcUClPDo28gUGF1bG8xETAP
16 BgNVBAoTCEVhc3lUYXhpMREwDwYDVQQLEwhFYXN5VGF4aTELMAkGA1UEAxMCRVQx
17 JjAkBgkqhkiG9w0BCQEWF2NvbnRhdG9AZWFzeXRheGkuY29tLmJyggkAllMqnTDz
18 aTIwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQAEcW5DO0ODdWd0kZzU
19 6eSg8ckDPImveTiKpFU5a96WxlVmwU8IlwAZ695w6ciIwDjys6BUNUBayTczhJbO
20 83Ykrt+b62+ksqKKFrCcba10R8QSjhYZSy7Yv08m/6+OiP+rUb2Jg4zVdAPhaaVn
21 lb1Nff1EgOdWIdjTKpPzHRjY4g==
22 -----END CERTIFICATE-----
Autoridade Certificadora Aplicativo Mobile
Requisição OkHttp - Android
1 OkHttpClient client = new OkHttpClient();
2 client.setSslSocketFactory(sslContext.getSocketFactory());
3 client.newCall(new Request.Builder()
4 .url("https://easytaxi.com.br")
5 .build()
6 ).execute();
Adicionando Cabeçalhos
1 GET /passenger/56edfd08756f458a6f0041ad HTTP/1.1
2 Host: api.easytaxi.com.br
3 User-Agent: curl/7.43.0
4 X-SSL: 1
5 X-SSL-Client-Verify: 0
6 X-SSL-Client-SHA1: "a01b894d12579d88efce97d27107f380b05f5968"
7 X-SSL-Client-CN: "56edfd08756f458a6f0041ad"
8 X-SSL-Issuer: "/C=BR/OU=EasyTaxi/emailAddress=contato@easytaxi.com.br”
9 X-SSL-Client-Not-Before: "120101100030Z"
10 X-SSL-Client-Not-After: "160101100030Z"
11 Accept: */*
Use Cases
Validade
• Todo certificado tem validade
• Demonstração
• Teste gratuito temporário
• Revalidação de login
Grupos e Cadeias
• Você pode criar vários CAs intermediários
• Criar intermediário e assinar os usuários do grupo com ele
• Revogar um intermediário e todos certificados abaixo dele
• Intermediários também possuem validade
Integridade
• Benefício da autenticação mútua (2WAY)
Assinatura digital
• Não repúdio - Garantia da que o portador assinou
• Assinar documentos digitalmente
• Certificado digital
Offload
Descentralizado
• Servidores conseguem validar o certificado offline
• Precisam apenas compartilhar as chaves do CA
• Ideal para microserviços
Emissão on-demand
• Emissão de certificados dinamicamente
• Let’s Encrypt faz isso para certificado de servidores
• Crie sua PKI para emitir certificados para clientes
Autorização Simples - 403
1 #GET /passenger/56edfd08756f458a6f0041ad HTTP/1.1
2 $uri = current(explode('?', getenv('REQUEST_URI')));
3 preg_match('#[a-zA-Z0-9-]+(/)?$#', $uri, $matches);
4 $passengerId = $matches[0];
5 if ($request->headers->get('X-SSL-Client-CN') != $passengerId) {
6 return new Response('Forbidden', 403);
7 }
Gerar certificado - PHPAssinando o certificado
1 /**
2 * CSR - Requisição de certificado
3 */
4 $certificateSigningRequest = new File_X509();
5 $certificateSigningRequest->setDN($certificateIntermediateCA->getDN());
6 $certificateSigningRequest->setDNProp('uniqueidentifier', 'my unique ID');
7 $certificateSigningRequest->setPublicKey((object)$clientPublicKey);
8 $certificateX509 = new File_X509();
9 $certificateX509->setEndDate('+1 month');
10 /**
11 * Assinatura do CA
12 */
13 $clientCertificate =
14 $certificateX509->sign($certificateIntermediateCA, $certificateSigningRequest);
Por que ninguém ta usando isso?
Perguntas?
Vamos manter contato!
https://legacy.joind.in/17491
https://gist.github.com/milhomem

Autenticacao em APIs com SSL

  • 1.
  • 2.
  • 3.
    Agenda • HTTP RESTAPI • Autenticação • SSL / Autoridade Certificadora / Certificados • Aplicação em Mobile
  • 4.
  • 5.
    401 vs 403 •401 Unauthorised - Não autenticado Eu preciso saber quem você é • 403 Forbidden - Não autorizado Eu sei quem você é mas, você não tem direito
  • 6.
  • 7.
    HTTP Basic (Usuário eSenha) • Cleartext • Precisa de SSL • Fácil de "crackear" • Usuário preguiçoso (mesma senha / senha fraca) • Mesma senha em vários sistemas
  • 8.
  • 9.
    Token / JWT 1{ 2 "sub": "1234567890", 3 "name": "John Doe", 4 "admin": true 5 } 1 HMACSHA256( 2 base64UrlEncode(header) + "." + 3 base64UrlEncode(payload), 4 secret) 1 eyJhbGciOiJIUzI1NiIsInR 2 5cCI6IkpXVCJ9. 3 eyJzdWIiOiIxMjM0NTY3ODk 4 wIiwibmFtZSI6IkpvaG4gRG 5 9lIiwiYWRtaW4iOnRydWV9. 6 TJVA95OrM7E2cBab30RMHrH 7 DcEfxjoYZgeFONFh7HgQ
  • 10.
  • 11.
  • 12.
    Certificados • Par dechaves assimétricas (Pública e Privada) • Oferece a mesma coisa que o SSL • Autentica o cliente através da assinatura digital • Requer um `round trip` extra
  • 13.
    Autoridade Certificadora (CA) •Self signed (todo CA é) • CA intermediário (cadeias de CA) - boa prática para evitar perda total em caso de comprometimento da chave privada • Você é a autoridade :0 dona da verdade • Utilizar CA intermediários como ACL
  • 14.
  • 15.
    Ingredientes Keystore Certificado do ClienteCertificado do Servidor Keystore CA
  • 16.
  • 17.
    Gerar certificado -PHP Gerando par de chaves do cliente 1 /** 2 * Chave privada 3 */ 4 $clientPrivateKey = new Crypt_RSA(); 5 $clientPrivateKey->setPassword($password); 6 $generatedKeyPair = $clientPrivateKey->createKey(); 7 $clientPrivateKey->loadKey($generatedKeyPair['privatekey']); 8 /** 9 * Chave pública 10 */ 11 $clientPublicKey = new Crypt_RSA(); 12 $clientPublicKey->loadKey($generatedKeyPair['publickey']); 13 $clientPublicKey->setPublicKey();
  • 18.
    Gerar certificado -PHP Par de chaves do CA 1 /** 2 * Chave privada do CA necessária para assinar 3 */ 4 $privateKeyIntermediateCA = new Crypt_RSA(); 5 $privateKeyIntermediateCA->setPassword('Intermediate CA password'); 6 $privateKeyIntermediateCA->loadKey(file_get_contents($privateCAKeyPath)); 7 /** 8 * Certificado do CA 9 */ 10 $certificateIntermediateCA = new File_X509(); 11 $certificateIntermediateCA->setPrivateKey($privateKeyIntermediateCA); 12 $certificateIntermediateCA->loadX509(file_get_contents($certificateCAKeyPath));
  • 19.
    Certificado do Cliente- PHPAssinando o certificado 1 /** 2 * CSR - Requisição de certificado 3 */ 4 $certificateSigningRequest = new File_X509(); 5 $certificateSigningRequest->setDN($certificateIntermediateCA->getDN()); 6 $certificateSigningRequest->setPublicKey((object)$clientPublicKey); 7 $certificateX509 = new File_X509(); 8 $certificateX509->setEndDate('+1 month'); 9 /** 10 * Assinatura do CA 11 */ 12 $clientCertificate = 13 $certificateX509->sign($certificateIntermediateCA, $certificateSigningRequest); 14 /** 15 * Resultado chave privada + certificado do cliente 16 */ 17 echo $clientPrivateKey->getPrivateKey(); 18 echo PHP_EOL; 19 echo $certificateX509->saveX509($clientCertificate);
  • 20.
    Certificado do Cliente- Android 1 /** 2 * Certificado do cliente + chave privada empacotados em um arquivo PFX 3 */ 4 KeyStore keyStore = KeyStore.getInstance("PKCS12"); 5 FileInputStream clientCertificateContent = 6 new FileInputStream("/path/to/publicAndPrivateKey.p12"); 7 keyStore.load(clientCertificateContent, "private key password".toCharArray()); 8 KeyManagerFactory keyManagerFactory = 9 KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 10 keyManagerFactory.init(keyStore, "private key password".toCharArray());
  • 21.
    Embarcar CA 1 -----BEGINCERTIFICATE----- 2 MIIDnzCCAwigAwIBAgIJAJZTKp0w82kyMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYD 3 VQQGEwJCUjETMBEGA1UECBQKU8OjbyBQYXVsbzETMBEGA1UEBxQKU8OjbyBQYXVs 4 bzERMA8GA1UEChMIRWFzeVRheGkxETAPBgNVBAsTCEVhc3lUYXhpMQswCQYDVQQD 5 EwJFVDEmMCQGCSqGSIb3DQEJARYXY29udGF0b0BlYXN5dGF4aS5jb20uYnIwHhcN 6 MTYwMTE4MTYwNDQ2WhcNMzYwMTEzMTYwNDQ2WjCBkjELMAkGA1UEBhMCQlIxEzAR 7 BgNVBAgUClPDo28gUGF1bG8xEzARBgNVBAcUClPDo28gUGF1bG8xETAPBgNVBAoT 8 CEVhc3lUYXhpMREwDwYDVQQLEwhFYXN5VGF4aTELMAkGA1UEAxMCRVQxJjAkBgkq 9 hkiG9w0BCQEWF2NvbnRhdG9AZWFzeXRheGkuY29tLmJyMIGfMA0GCSqGSIb3DQEB 10 AQUAA4GNADCBiQKBgQDTny6B8fbG1UXEtMYYFKfODKduzYTovLIUzXKFrX9wHEsC 11 lTOLqtvKsvkLkjXsC3R/HedWoRbFXJbaaw723csPlxrxuBqfkNBJB25ihccwVWbP 12 WpEaDluL2btsBdW2uuDshpXk2z6Gf5xcePnmf24iWpvJs1uBJWkEGRR2TzEi8wID 13 AQABo4H6MIH3MB0GA1UdDgQWBBRMm/EjlWrvxXTtUmotq+kwN52u3zCBxwYDVR0j 14 BIG/MIG8gBRMm/EjlWrvxXTtUmotq+kwN52u36GBmKSBlTCBkjELMAkGA1UEBhMC 15 QlIxEzARBgNVBAgUClPDo28gUGF1bG8xEzARBgNVBAcUClPDo28gUGF1bG8xETAP 16 BgNVBAoTCEVhc3lUYXhpMREwDwYDVQQLEwhFYXN5VGF4aTELMAkGA1UEAxMCRVQx 17 JjAkBgkqhkiG9w0BCQEWF2NvbnRhdG9AZWFzeXRheGkuY29tLmJyggkAllMqnTDz 18 aTIwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQAEcW5DO0ODdWd0kZzU 19 6eSg8ckDPImveTiKpFU5a96WxlVmwU8IlwAZ695w6ciIwDjys6BUNUBayTczhJbO 20 83Ykrt+b62+ksqKKFrCcba10R8QSjhYZSy7Yv08m/6+OiP+rUb2Jg4zVdAPhaaVn 21 lb1Nff1EgOdWIdjTKpPzHRjY4g== 22 -----END CERTIFICATE----- Autoridade Certificadora Aplicativo Mobile
  • 22.
    Requisição OkHttp -Android 1 OkHttpClient client = new OkHttpClient(); 2 client.setSslSocketFactory(sslContext.getSocketFactory()); 3 client.newCall(new Request.Builder() 4 .url("https://easytaxi.com.br") 5 .build() 6 ).execute();
  • 23.
    Adicionando Cabeçalhos 1 GET/passenger/56edfd08756f458a6f0041ad HTTP/1.1 2 Host: api.easytaxi.com.br 3 User-Agent: curl/7.43.0 4 X-SSL: 1 5 X-SSL-Client-Verify: 0 6 X-SSL-Client-SHA1: "a01b894d12579d88efce97d27107f380b05f5968" 7 X-SSL-Client-CN: "56edfd08756f458a6f0041ad" 8 X-SSL-Issuer: "/C=BR/OU=EasyTaxi/emailAddress=contato@easytaxi.com.br” 9 X-SSL-Client-Not-Before: "120101100030Z" 10 X-SSL-Client-Not-After: "160101100030Z" 11 Accept: */*
  • 24.
  • 25.
    Validade • Todo certificadotem validade • Demonstração • Teste gratuito temporário • Revalidação de login
  • 26.
    Grupos e Cadeias •Você pode criar vários CAs intermediários • Criar intermediário e assinar os usuários do grupo com ele • Revogar um intermediário e todos certificados abaixo dele • Intermediários também possuem validade
  • 27.
    Integridade • Benefício daautenticação mútua (2WAY)
  • 28.
    Assinatura digital • Nãorepúdio - Garantia da que o portador assinou • Assinar documentos digitalmente • Certificado digital
  • 29.
  • 33.
    Descentralizado • Servidores conseguemvalidar o certificado offline • Precisam apenas compartilhar as chaves do CA • Ideal para microserviços
  • 34.
    Emissão on-demand • Emissãode certificados dinamicamente • Let’s Encrypt faz isso para certificado de servidores • Crie sua PKI para emitir certificados para clientes
  • 35.
    Autorização Simples -403 1 #GET /passenger/56edfd08756f458a6f0041ad HTTP/1.1 2 $uri = current(explode('?', getenv('REQUEST_URI'))); 3 preg_match('#[a-zA-Z0-9-]+(/)?$#', $uri, $matches); 4 $passengerId = $matches[0]; 5 if ($request->headers->get('X-SSL-Client-CN') != $passengerId) { 6 return new Response('Forbidden', 403); 7 }
  • 36.
    Gerar certificado -PHPAssinando o certificado 1 /** 2 * CSR - Requisição de certificado 3 */ 4 $certificateSigningRequest = new File_X509(); 5 $certificateSigningRequest->setDN($certificateIntermediateCA->getDN()); 6 $certificateSigningRequest->setDNProp('uniqueidentifier', 'my unique ID'); 7 $certificateSigningRequest->setPublicKey((object)$clientPublicKey); 8 $certificateX509 = new File_X509(); 9 $certificateX509->setEndDate('+1 month'); 10 /** 11 * Assinatura do CA 12 */ 13 $clientCertificate = 14 $certificateX509->sign($certificateIntermediateCA, $certificateSigningRequest);
  • 37.
    Por que ninguémta usando isso?
  • 38.