-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.html
764 lines (741 loc) · 45.6 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Criando APIs seguras | Vinícius Campitelli</title>
<link rel="stylesheet" href="reveal.js/dist/reset.css">
<link rel="stylesheet" href="reveal.js/dist/reveal.css">
<link rel="stylesheet" href="reveal.js/dist/theme/solarized.css" id="theme">
<link rel="stylesheet" href="reveal.js/plugin/highlight/zenburn.css" id="highlight-theme">
<link rel="stylesheet" href="css/style.css?d=202010281032">
<link href="https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@500&display=swap" rel="stylesheet">
</head>
<body>
<div class="reveal">
<div class="slides">
<section>
<h1>Criando APIs seguras</h1>
</section>
<section>
<h2>Quem sou eu?</h2>
<div class="d-flex align-items-center">
<div class="mr-2">
<img src="img/profile.png" alt="Vinícius Campitelli" alt="Vinícius Campitelli" class="mb-0" id="img-profile">
<h4>Vinícius Campitelli</h4>
</div>
<div>
<ul>
<li>Desenvolvedor na <a href="https://www.ottera.tv/" target="_blank" rel="noopener">OTTera</a></li>
<li>Membro do <a href="https://phpsp.org.br" target="_blank" rel="noopener">PHPSP</a></li>
<li>GitHub e Twitter: <a href="https://twitter.com/vcampitelli" target="_blank" rel="noopener">@vcampitelli</a></li>
<li>Slides: <a href="https://viniciuscampitelli.com/slides-apis-seguras/" target="_blank" rel="noopener">viniciuscampitelli.com</a></li>
</ul>
</div>
</div>
</section>
<section>
<h2>Agenda</h2>
<ul>
<li class="fragment">Autenticação e autorização</li>
<li class="fragment">Melhores práticas com access tokens</li>
<li class="fragment">Throttling e Rate Limiting</li>
<li class="fragment">Camuflagem de IDs sequenciais</li>
<li class="fragment">Criptografando e assinando requisições e respostas</li>
</ul>
</section>
<section>
<section>
<h1>Autenticação e autorização</h1>
</section>
<section data-auto-animate>
<h2>Autenticação</h2>
<div class="r-stack">
<div>
<blockquote cite="https://pt.wikipedia.org/wiki/Autentica%C3%A7%C3%A3o">
É o ato de estabelecer ou confirmar algo (ou alguém) como autêntico <small>(...)</small>
</blockquote>
<small><a href="https://pt.wikipedia.org/wiki/Autentica%C3%A7%C3%A3o" target="_blank" rel="noopener">Fonte: Wikipedia</a></small>
</div>
<div class="fragment fade-up">
<img src="img/porteiro-castelo-ratimbum.png">
</div>
</div>
</section>
<section data-auto-animate>
<h2>Autenticação</h2>
<div>
Para autenticar algo ou alguém, precisamos de uma credencial que o identifique.<br>
Ela precisa ser emitida por algo (ou alguém) que o autorizador confie.
</div>
</section>
<section>
<h3>“O que você sabe”</h3>
<p>Autenticação baseada no conhecimento</p>
<div class="fragment">
Exemplos:<br>
<ul>
<li>Usuário e senha</li>
<li>Certificado digital</li>
<li>Client ID e Client Secret</li>
</ul>
</div>
</section>
<section>
<h3>“O que você tem”</h3>
<p>Autenticação baseada na propriedade</p>
<div class="fragment">Exemplos:</div>
<div class="d-flex">
<div class="fragment">
<img src="img/yubikey.png" style="height: 20%"><br>
Token ou cartão físico
</div>
<div class="fragment">
<img src="img/google-authenticator.png" style="height: 20%"><br>
Código via aplicativo
</div>
</div>
</section>
<section>
<h3>“O que você é”</h3>
<p>Autenticação baseada na característica</p>
<div class="fragment">
Exemplos:<br>
<ul>
<li>Impressão digital</li>
<li>Identificação de íris</li>
<li>Reconhecimento facial</li>
<li>Reconhecimento de voz</li>
</ul>
</div>
</section>
<section>
<div class="r-stack">
<div>
<h2>Autorização</h2>
<blockquote cite="https://pt.wikipedia.org/wiki/Autoriza%C3%A7%C3%A3o">
É garantir que apenas usuários autorizados consumam os recursos protegidos de um sistema computacional
</blockquote>
<small><a href="https://pt.wikipedia.org/wiki/Autoriza%C3%A7%C3%A3o" target="_blank" rel="noopener">Fonte: Wikipedia</a></small>
</div>
<div class="fragment">
<img src="img/authorized-personnel-signs.jpg">
</div>
</div>
</section>
<section>
<h2>Autorização</h2>
<div>
Após saber quem é o cliente no processo de Autenticação, preciso agora entender o que ele pode fazer. Quais recursos ele pode consumir? Por quanto tempo?
</div>
</section>
<section>
<h3>Como efetuar autenticação e autorização?</h3>
<div class="fragment">
Para autenticação, podemos utilizar o <a href="https://openid.net/" target="_blank" rel="noopener">OpenID</a> ou implementar nosso próprio sistema <em>(por exemplo, através do banco de dados)</em>.
</div>
<br>
<div class="fragment">
<a href="https://oauth.net/2/" target="_blank" rel="noopener">OAuth 2.0</a> é o protocolo mais conhecido de <strong>autorização</strong>.
Ele, por si só, não contempla processos de autenticação.
</div>
</section>
<section>
<h4>Famosa tela de Autorização via OAuth 2</h4>
<p class="small mb-0">
Utilizando o <em>Grant</em> de <em>Authorization Code</em><br>
<em>(saiba como escolher o Grant Type certo <a href="https://auth0.com/docs/api-auth/which-oauth-flow-to-use" target="_blank" rel="noopener">nesse link</a>)</em>
</p>
<figure>
<a href="https://shotgundebugging.blogspot.com/2016/11/authorization-with-oauth2.html" target="_blank" rel="noopener">
<img src="img/google-oauth-consent.png" alt="Tela de exemplo do fluxo de Authorization Code do OAuth 2.0 do Google" class="mb-0" data-width="443">
</a>
<figcaption><a href="https://shotgundebugging.blogspot.com/2016/11/authorization-with-oauth2.html" target="_blank" rel="noopener">Referência: Shotgun Debugging</a></figcaption>
</figure>
</section>
<section>
<h6>Referências</h6>
<ul>
<li><a href="https://openid.net/" target="_blank" rel="noopener">OpenID</a></li>
<li><a href="https://auth0.com/" target="_blank" rel="noopener">Auth0</a></li>
<li><a href="https://oauth.net/2/" target="_blank" rel="noopener">OAuth 2.0</a></li>
<li>
Para PHP
<ul>
<li><a href="https://oauth2.thephpleague.com/" target="_blank" rel="noopener">The PHP League: OAuth 2.0 Server</a></li>
<li><a href="https://viniciuscampitelli.com/slides/expressive-oauth2-jwt/" target="_blank" rel="noopener">Meu slides sobre OAuth2</a></li>
</ul>
</li>
<li>
Para Node.JS
<ul>
<li><a href="https://github.com/oauthjs/node-oauth2-server" target="_blank" rel="noopener">oauthjs/node-oauth2-server</a></li>
<li><a href="https://github.com/t1msh/node-oauth20-provider" target="_blank" rel="noopener">t1msh/node-oauth20-provider</a></li>
</ul>
</li>
<li>
<a href="https://oauth.net/code/" target="_blank" rel="noopener">Mais bibliotecas no oauth.net</a>
</li>
</ul>
</section>
</section>
<section>
<section>
<h1>Melhores práticas com <em>access tokens</em></h1>
</section>
<section>
<h2>O que é um <em>access token</em>?</h2>
<div class="fragment">
<blockquote cite="https://docs.microsoft.com/pt-br/windows/win32/secauthz/access-tokens">
É um objeto que descreve o contexto de segurança de um processo <small>(...)</small>
</blockquote>
<small><a href="https://docs.microsoft.com/pt-br/windows/win32/secauthz/access-tokens" target="_blank" rel="noopener">Fonte: MSDN</a></small>
</div>
</section>
<section data-auto-animate>
<h3>E no mundo de APIs?</h3>
<div>
O processo de autenticação e autorização pode ser caro computacionalmente <em>(consultas a banco de dados, servidores de autenticação externos, criptografia de senha etc)</em>
</div>
</section>
<section data-auto-animate>
<h3>E no mundo de APIs?</h3>
<div>
Ao invés de sempre termos essa carga a cada requisição a nossos servidores, podemos ter um único <em>endpoint</em> de autenticação / autorização que irá realizar essa etapa
uma vez e gerar um <em>access token</em> com as informações necessárias para autenticar e autorizar mais rapidamente o cliente nas requisições seguintes
</div>
</section>
<section data-auto-animate>
<h3>E no mundo de APIs?</h3>
<div>
Esse <em>token</em> deve possuir um tempo de vida limitado, tanto para diminuir efeitos colaterais caso haja um vazamento quanto porque sua informação pode ficar desatualizada
</div>
</section>
<section data-auto-animate>
<h3>E no mundo de APIs?</h3>
<div>
Esse segundo processo pode ser automatizado através de <em>refresh tokens</em>
<div class="fragment">
<br>
Eles são utilizados para regerar um <em>access token</em> automaticamente, sem necessitar da intervenção manual do usuário
</div>
</div>
</section>
<section>
</section>
<section data-auto-animate>
<h3>Como deixar os <em>tokens</em> seguros?</h3>
<ul>
<li class="fragment">
Utilizando algoritmos de criptografia seguros e com assinatura;
<ul class="fragment">
<li>AES-256-GCM, ChaCha20+Poly1305, Ed25519 entre outros</li>
</ul>
</li>
<li class="fragment">
Tendo cuidado com implementações de bibliotecas com falhas de segurança;
<ul class="fragment">
<li>Exemplo: <a href="https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/" target="_blank" rel="noopener">JWT com alg=none</a></li>
</ul>
</li>
</ul>
</section>
<section data-auto-animate>
<h3>Como deixar os <em>tokens</em> seguros?</h3>
<ul>
<li>Não faça <em>commit</em> de chaves e outros segredos, nem deixe-os <em>hardcoded</em> na aplicação</li>
<li class="fragment">Não guarde informações muito sensíveis <em>(como senhas e outras credenciais)</em></li>
<li class="fragment">Se precisar armazenar do lado do cliente, utilize cookies seguros <em>(flags <code>httpOnly</code> e <code>secure</code>)</em> ao invés do <em>LocalStorage</em></li>
</ul>
</section>
<section data-auto-animate>
<h3>Como deixar os <em>tokens</em> seguros?</h3>
<ul>
<li>Apenas trafegue <em>tokens</em> no cabeçalho ou corpo da requisição, nunca na URL</li>
<li class="fragment">Não exiba informações do <em>token</em> em seus <em>logs</em></li>
</ul>
</section>
<section>
<h3>Exemplo de implementação</h3>
<pre><code class="php">use Lcobucci\JWT\Builder;
$time = time();
$token = (new Builder())
->issuedBy('http://example.com') // Configures the issuer (iss claim)
->permittedFor('http://example.org') // Configures the audience (aud claim)
->identifiedBy('4f1g23a12aa', true) // Configures the id (jti claim), replicating as a header item
->issuedAt($time) // Configures the time that the token was issue (iat claim)
->canOnlyBeUsedAfter($time + 60) // Configures the time that the token can be used (nbf claim)
->expiresAt($time + 3600) // Configures the expiration time of the token (exp claim)
->withClaim('uid', 1) // Configures a new claim, called "uid"
->getToken(); // Retrieves the generated token</code></pre>
<a href="https://github.com/lcobucci/jwt/blob/3.3/README.md" class="small" target="_blank" rel="noopener">lcobucci/jwt</a>
</section>
<section>
<h5>Bibliotecas</h5>
<h6>JWT</h6>
<p>Implementação mais conhecida de tokens</p>
<ul>
<li>PHP: <a href="https://github.com/lcobucci/jwt" target="_blank" rel="noopener">lcobucci/jwt</a></li>
<li>Node.JS: <a href="https://github.com/auth0/node-jsonwebtoken" target="_blank" rel="noopener">auth0/node-jsonwebtoken</a></li>
<li>Python: <a href="https://github.com/jpadilla/pyjwt/" target="_blank" rel="noopener">jpadilla/pyjwt</a></li>
<li>Site oficial: <a href="https://jwt.io/" target="_blank" rel="noopener"></a></li>
</ul>
</section>
<section>
<h5>Bibliotecas</h5>
<h6>PASETO</h6>
<p>Implementação com design "mais seguro" por padrão</p>
<ul>
<li>PHP: <a href="https://github.com/paragonie/paseto" target="_blank" rel="noopener">paragonie/paseto</a></li>
<li>Node.JS: <a href="https://github.com/panva/paseto" target="_blank" rel="noopener">panva/paseto</a></li>
<li>Python: <a href="https://github.com/rlittlefield/pypaseto" target="_blank" rel="noopener">rlittlefield/pypaset</a></li>
<li>Site oficial: <a href="https://paseto.io/" target="_blank" rel="noopener">paseto.io</a></li>
</ul>
</li>
</section>
<section>
<h6>Referências</h6>
<ul>
<li><a href="https://viniciuscampitelli.com/slides/libsodium-php/" target="_blank" rel="noopener">Meu slides sobre a libsodium</a>, biblioteca moderna de criptografia</li>
<li><a href="https://symfony.com/doc/current/security/guard_authentication.html" target="_blank" rel="noopener">Symfony Guard</a>, componente do framework PHP Symfony</li>
<li>
Artigo: <a href="https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-that-everyone-should-avoid" target="_blank" rel="noopener">
No Way, JOSE! Javascript Object Signing and Encryption is a Bad Standard That Everyone Should Avoid
</a>
</li>
</ul>
</section>
</section>
<section>
<section>
<h1>Throttling e Rate Limiting</h1>
</section>
<section data-auto-animate>
<h2>O que é Throttling?</h2>
<div class="fragment">
É a desaceleração intencional do processamento de uma requisição para prevenir sobrecarga do servidor
</div>
</section>
<section data-auto-animate>
<h2>O que é Throttling?</h2>
<div>
Imagine um <em>endpoint</em> que consuma grande recursos computacionais <em>(como, por exemplo, o processo de autenticação e autorização descritos anteriormente)</em>
</div>
</section>
<section data-auto-animate>
<h2>O que é Throttling?</h2>
<div>
Se um agente malicioso identificar esse recurso, ele pode se tornar muito visado para ataques, causando sobrecarga no nosso servidor e podendo gerar paralisação e até queda total do serviço
</div>
</section>
<section data-auto-animate>
<h2>O que é Throttling?</h2>
<div>
Nesses casos, podemos configurar que o servidor irá aceitar somente <code>x</code> requisições em algum(ns) <em>endpoint(s)</em> por um certo período de tempo
</div>
</section>
<section data-auto-animate>
<h2>O que é Throttling?</h2>
<div>
Após esse valor <code>x</code>, as requisições entrarão em uma fila para serem processadas alguns instantes depois, assim que as primeiras tiverem sido liberadas
</div>
</section>
<section></section>
<section data-auto-animate>
<h2>Mas então o que é Rate Limiting?</h2>
<div class="fragment">
Ao contrário do <em>Throttling</em>, em a requisição será processada com um atraso, <em>Rate Limiting</em> é fazer o servidor se recusar
a responder após um certo número de requisições
</div>
</section>
<section data-auto-animate>
<h2>Mas então o que é Rate Limiting?</h2>
<div>
Nesses casos, devemos emitir um status HTTP <code>503 Service Unavailable</code> ou <code>429 Too Many Requests</code>
</div>
</section>
<section>
<h3>Como essas duas práticas se relacionam entre si?</h3>
Geralmente, primeiro aplicamos uma política de <em>Throttling</em> para desacelerar o processamento nas <code>x</code> primeiras requisições, e após um outro número <code>y</code>, iremos
simplesmente parar de responder
</section>
<section data-auto-animate>
<h3>Onde e como configurar essas políticas?</h3>
<div>
Você deve configurá-las em seu servidor Web <em>(por exemplo, Apache, IIS ou nginx)</em> ou no seu serviço de DNS <em>(por exemplo, o Cloudflare)</em>
</div>
</section>
<section data-auto-animate>
<h3>Onde e como configurar essas políticas?</h3>
<div>
Tomando como exemplo o <em>nginx</em>, utilizaremos o módulo <code>ngx_http_limit_req_module</code> <em>(que implementa o mais conhecido algoritmo desse tipo de prática, o
<a href="https://pt.wikipedia.org/wiki/Leaky_Bucket" target="_blank" rel="noopener">Leaky Bucket</a>)</em>
</div>
</section>
<section data-auto-animate>
<h3>Onde e como configurar essas políticas?</h3>
<div>
<pre><code class="nginx" data-trim>
limit_req_zone $binary_remote_addr zone=login_zone:10m rate=10r/s;
server {
location /login {
limit_req zone=login_zone burst=5;
# outras configurações padrões do meu bloco location...
}
}
</code></pre>
</div>
</section>
<section data-auto-animate>
<h3>Onde e como configurar essas políticas?</h3>
<div>
O código anterior irá proteger nosso <em>endpoint</em> <code>/login</code>, permitindo apenas 10 requisições por segundo por IP <em>(ou seja, 1 a cada 100ms)</em>
</div>
</section>
<section data-auto-animate>
<h3>Onde e como configurar essas políticas?</h3>
<div>
Mas também permitimos um <em>burst</em>, permitindo que 5 requisições extras sejam colocadas na fila de processamento antes de serem enviadas para o <code>upstream</code>
</div>
</section>
<section data-auto-animate>
<h3>Onde e como configurar essas políticas?</h3>
<div>
<p>Nesse caso, se recebermos de um mesmo IP 10 requisições em um período de 100ms, o que ocorrerá?</p>
<ul>
<li class="fragment">A 1ª requisição será processada instantaneamente</li>
<li class="fragment">As 2ª, 3ª, 4ª, 5ª e 6ª requisições serão colocadas em uma fila e serão processadas sequencialmente após o término da anterior</li>
<li class="fragment">As 7ª, 8ª, 9ª e 10ª requisições serão negadas</li>
</ul>
</div>
</section>
<section>
<h6>Referências</h6>
<ul>
<li><a href="https://support.cloudflare.com/hc/en-us/articles/115001635128-Configuring-Cloudflare-Rate-Limiting" target="_blank" rel="noopener">Como implementar no CloudFlare</a></li>
<li><a href="https://www.nginx.com/blog/rate-limiting-nginx" target="_blank" rel="noopener">Como implementar no nginx</a></li>
</ul>
</section>
</section>
<section>
<section>
<h1>Camuflagem de IDs sequenciais</h1>
</section>
<section data-auto-animate>
<h3>O que é um ID sequencial e por que escondê-lo?</h3>
<div>
Ao criarmos <em>endpoints</em> no formato <code>/user/1</code>, <code>/user/2</code>, <code>/user/3</code> etc, estamos
fornecendo uma informação muito valiosa sobre a quantidade de registros que possuímos daquela entidade
</div>
</section>
<section data-auto-animate>
<h3>O que é um ID sequencial e por que escondê-lo?</h3>
<div>
Isso pode ser utilizado tanto por alguém mal intencionado quanto por algum competidor.
<p class="fragment">Cuidado com espionagem industrial! <img src="https://img.icons8.com/color/48/000000/spy-male--v1.png"></p>
</div>
</section>
<section data-auto-animate>
<h2 data-id="title"><span class="label fragment">Versão Standard</span><br>Como resolver?</h2>
<ul class="fragment">
<li>
Crie um segundo campo na tabela com um valor único para aquele registro
<ul class="fragment">
<li>Esse valor pode ser um <a href="https://en.wikipedia.org/wiki/Universally_unique_identifier" target="_blank" rel="noopener">GUID</a>, um hash do ID incremental ou um valor aleatório...</li>
</ul>
</li>
<li class="fragment">Então, transforme o recurso <code>/user/<IdIncremental></code> em <code>/user/<Identificador></code></li>
</ul>
</section>
<section data-auto-animate>
<h2 data-id="title">
<span class="label">Versão Standard</span><br>Como <b data-id="block-no" style="display: none">não</b> resolver?
</h2>
<h6>PHP</h6>
<ul>
<li>
Funções para gerar valores aleatórios:
<ul>
<li>
<a href="https://www.php.net/manual/en/function.random-bytes.php" target="_blank" rel="noopener">random_bytes()</a> para PHP 7
<ul>
<li>Para PHP 5, use o polyfill <a href="https://github.com/paragonie/random_compat" target="_blank" rel="noopener">paragonie/random_compat</a></li>
</ul>
</li>
</ul>
</li>
<li>
Funções para gerar hash:
<ul>
<li><a href="https://www.php.net/manual/en/function.hash-hmac.php" target="_blank" rel="noopener">hash_hmac()</a></li>
</ul>
</li>
<li>
<a href="https://paragonie.com/blog/2017/05/building-searchable-encrypted-databases-with-php-and-sql#solution-literal-search" target="_blank" rel="noopener">Artigo no blog da Paragon</a>
</li>
</ul>
</section>
<section data-auto-animate>
<h2 data-id="title">
<span class="label">Versão Standard</span><br>Como <b data-id="block-no">não</b> resolver?
</h2>
<h6>PHP</h6>
<p>Funções que <b>não devem</b> ser utilizadas:</p>
<ul>
<li>
Para gerar valores aleatórios:
<ul>
<li><span class="strike">rand()</span></li>
<li><span class="strike">mt_rand()</span></li>
<li><span class="strike">uniqid()</span></li>
</ul>
</li>
<li>
Para gerar hash:
<ul>
<li><span class="strike">sha1()</span></li>
<li><span class="strike">md5()</span></li>
</ul>
</li>
</ul>
</section>
<section>
<h2 data-id="title"><span class="label">Versão Standard</span><br>Como resolver?</h2>
<h6>Node.JS</h6>
<ul>
<li>
Módulo <a href="https://nodejs.org/api/crypto.html" target="_blank" rel="noopener">Crypto</a>
</li>
</ul>
<pre><code class="javascript" data-trim>
const { createHash } = require('crypto');
const hash = createHash('sha256');
user.lookupHash = hash.update(user.id).digest('hex');
</code></pre>
</section>
<section>
<h2 data-id="title"><span class="label">Versão Standard</span><br>Como resolver?</h2>
<h6>Python</h6>
<ul>
<li>
Módulo <a href="https://docs.python.org/3/library/crypt.html" target="_blank" rel="noopener">crypt</a> <em>(built-in na versão 3)</em>
</li>
</ul>
<pre><code class="python" data-trim>
from hashlib import sha256
sha256(user.id).hexdigest()
</code></pre>
</section>
<section>
<h2><span class="label flames fragment">Versão Hardcore</span><br>Como resolver?</h2>
<div class="fragment">
<p>
Utilizando a biblioteca <a href="https://github.com/paragonie/ciphersweet" target="_blank" rel="noopener">paragonie/ciphersweet</a>, que deriva uma chave para cada coluna a partir de uma chave-mestra
</p>
<br>
<h6>Referência</h6>
<ul>
<li>
<a href="https://paragonie.com/blog/2019/01/ciphersweet-searchable-encryption-doesn-t-have-be-bitter" target="_blank" rel="noopener">Artigo no blog da Paragon</a>
</li>
</ul>
</div>
</section>
</section>
<section>
<section>
<h1 class="h2">Criptografando e assinando requisições e respostas</h1>
</section>
<section data-auto-animate>
<h2>Precaução extra</h2>
<div>
Para usuários avançados e sistemas críticos, podemos adicionar uma camada extra de proteção: criptografar os dados da requisição e da resposta
</div>
</section>
<section data-auto-animate>
<h2>Precaução extra</h2>
<div>
<blockquote>
Mas, espera aí! Eu já uso HTTPS. Meu dados já estão sendo criptografados usando TLS.
</blockquote>
</div>
</section>
<section data-auto-animate>
<h2>Precaução extra</h2>
<div>
Após o estabelecimento do protocolo, realmente os dados transitados estão criptografados, mas ainda podemos sofrer um ataque de <a href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack" target="_blank" rel="noopener">Man in the Middle</a>
</div>
</section>
<section></section>
<section data-auto-animate>
<h3>Man in the Middle</h3>
<ul>
<li>Existem diversos <em>hops</em> entre o cliente e o servidor. Quem garante que todos os <em>gateways</em> do caminho são seguros?</li>
<li class="fragment">Se você não for o administrador da sua rede local, alguém pode instalar uma Autoridade Certificadora em sua máquina e emitir certificados próprios</li>
</ul>
</section>
<section data-auto-animate>
<h3>Man in the Middle</h3>
<ul>
<li>
Nem todos os sites utilizam <a href="https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security" target="_blank" rel="noopener">HSTS</a>
<ul class="fragment">
<li>Ou seja, pode haver uma conexão HTTP antes do redirecionamento para HTTPS pelo servidor</li>
</ul>
</li>
<li class="fragment">Teoria da conspiração: grandes empresas possuem <em>backdoors</em> para bisbilhotar seu tráfego</li>
</ul>
</section>
<section></section>
<section data-auto-animate>
<h2>Precaução extra</h2>
<div>
<p>Antes de seguir nessa etapa, faça um <a href="https://owasp.org/www-community/Threat_Modeling" target="_blank" rel="noopener">Threat Modeling</a> e certifique-se que realmente valhe a pena</p>
<p class="fragment">Compensa instalar um sistema de segurança de última geração em um depósito que não possui algo de extremo valor dentro?</p>
</div>
</section>
<section data-auto-animate>
<h2>Precaução extra</h2>
<div>
<blockquote>
SIM! Meu sistema é crítico e preciso disso. <span class="fragment">Ou eu não confio em grandes corporações.</span>
</blockquote>
</div>
</section>
<section data-auto-animate>
<h2>Precaução extra</h2>
<div>
Você pode exigir que toda requisição tenha seu corpo criptografado pelo cliente, utilizando um segredo em que só vocês dois sabem
</div>
</section>
<section data-auto-animate>
<h2>Precaução extra</h2>
<div>
Por exemplo, você pode utilizar uma terceira informação fora o Client ID e o Client Secret e usá-la como chave assimétrica, ou fornecer um certificado digital para seu cliente
</div>
</section>
<section data-auto-animate>
<h2>Precaução extra</h2>
<div>
Do lado do servidor, você utiliza essa informação sigilosa para descriptografar o corpo da requisição - se falhar, você emite um erro e para o processamento
</div>
</section>
<section data-auto-animate>
<h2>Precaução extra</h2>
<div>
Entretanto, esse processo de descriptografia pode ser muito custoso operacionalmente, podendo ser um outro ponto de ataque DoS <em>(lembre-se do que falamos na seção de </em>Throttling e Rate Limiting<em>)</em>.
Você pode, então, utilizar um processo de assinatura digital além da criptografia.
</div>
</section>
<section>
<h3>Fluxo de criptografia e assinatura</h3>
<div>
O cliente...
<ul>
<li>Autentica na sua API fornecendo as credenciais</li>
<li class="fragment">
Para cada requisição, assina e criptografa os dados <em>(combinação do corpo da requisição + URL)</em>;
<ul>
<li class="fragment">Utiliza um algoritmo de hash para assinar os dados</li>
<li class="fragment">Criptografa os dados mais a assinatura</li>
<li class="fragment">Envia a requisição somente com os dados criptografados</li>
</ul>
</li>
<li class="fragment">
Para cada resposta seguinte, ele deve:
<ul>
<li class="fragment">Verificar a assinatura</li>
<li class="fragment">Descriptografar o corpo</li>
</ul>
</li>
</ul>
</div>
</section>
<section>
<h3>Fluxo de criptografia e assinatura</h3>
<div>
A cada requisição recebida, o servidor deve...
<ul>
<li class="fragment">Verificar a assinatura</li>
<li class="fragment">Descriptografar o corpo</li>
<li class="fragment">
Ao responder à requisição, deve assinar e criptografar os dados <em>(combinação do corpo da requisição + URL)</em>;
<ul>
<li class="fragment">Utiliza um algoritmo de hash para assinar os dados</li>
<li class="fragment">Criptografa os dados mais a assinatura</li>
<li class="fragment">Envia a requisição somente com os dados criptografados</li>
</ul>
</li>
</ul>
</div>
</section>
<section>
<h6>Referências</h6>
<ul>
<li>
<a href="https://www.php.net/manual/en/function.openssl-encrypt.php" target="_blank" rel="noopener">openssl_encrypt()</a> e
<a href="https://www.php.net/manual/en/function.openssl-decrypt.php" target="_blank" rel="noopener">openssl_decrypt()</a>
</li>
<li>
Artigos usando a libsodium:<br>
<ul>
<li><a href="https://paragonie.com/book/pecl-libsodium/read/04-secretkey-crypto.md" target="_blank" rel="noopener">Basic Secret-key Cryptography</a></li>
<li><a href="https://paragonie.com/book/pecl-libsodium/read/05-publickey-crypto.md" target="_blank" rel="noopener">Basic Public-key Cryptography</a></li>
</ul>
</li>
</ul>
</section>
</section>
<section>
<h2>Concluindo...</h2>
<ul>
<li class="fragment">
Segurança não é trivial<br>
<span class="fragment"><span class="color-transparent">Segurança</span> não é fácil</span><br>
<span class="fragment"><span class="color-transparent">Segurança</span> não é para leigos</span>
</li>
<li class="fragment">
Nenhum sistema operante é <strong>invencível</strong><span class="fragment">,<br>
mas você <strong>deve dificultar</strong> o trabalho de atacantes
</span>
</li>
<li class="fragment">Saiba equilibrar e avaliar a relação de custo-benefício entre segurança e usabilidade</li>
</ul>
</section>
<section>
<h2>Obrigado!</h2>
<div class="d-flex">
<div>
<h4>Slides</h4>
<div><img src="img/qr.jpg" alt="QR Code"></div>
<div><a href="https://viniciuscampitelli.com/slides-apis-seguras/" target="_blank">viniciuscampitelli.com</a></div>
</div>
<div>
<h4>Contato</h4>
<div>GitHub e Twitter</div>
<div><a href="https://twitter.com/vcampitelli" target="_blank" rel="noopener">@vcampitelli</a></div>
</div>
</div>
</section>
</div>
</div>
<script src="reveal.js/dist/reveal.js"></script>
<script src="reveal.js/plugin/highlight/highlight.js"></script>
<script>
Reveal.initialize({
hash: true,
slideNumber: true,
mouseWheel: true,
history: true,
overview: false,
plugins: [RevealHighlight]
});
// @see https://stackoverflow.com/a/26893663
const element = document.querySelector('.slides'),
scaleX = element.getBoundingClientRect().width / element.offsetWidth;
document.querySelectorAll('img[data-width]').forEach(node => {
node.style.width = (node.dataset.width / scaleX) + 'px';
});
</script>
</body>
</html>