Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Forçar API para só estar disponível para usuárias autenticadas #427

Closed
3 of 6 tasks
berinhard opened this issue Sep 16, 2020 · 5 comments · Fixed by #464
Closed
3 of 6 tasks

Forçar API para só estar disponível para usuárias autenticadas #427

berinhard opened this issue Sep 16, 2020 · 5 comments · Fixed by #464

Comments

@berinhard
Copy link
Contributor

berinhard commented Sep 16, 2020

Essa issue tem como objetivo limitar o uso abusivo da API do Brasil.io e também permitir que possamos entrar em contato com pessoas que estejam realizando requisições abusivas via nossa API. Para isso precisamos:

  • Adicionar captha na página de cadastro;
  • Atualizar a API para forçar autenticação;
  • Criar parte da aplicação para poder gerenciar os tokens de autenticação da API;
  • Documentar a API;
  • Blogpost falando do porquê dessa decisão (quando colocarmos isso no ar);
  • Resposta para requisição não autenticada deve conter texto descritivo com o link do blogpost;
@berinhard
Copy link
Contributor Author

@turicas acha que podemos usar o captcha do Google para isso?

@berinhard
Copy link
Contributor Author

Para a autenticação, na minha opinião a estratégia de TokenAuthentication do DRF nos atende. De acordo @turicas?

Com ele as pessoas precisarão:

  1. Realizar uma requisição POST para um endpoint como /api/obtain-auth-token/ informando o email e senha do usuário;
  2. Isso vai gerar um token de acesso e retorná-lo na resposta: { 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' }
  3. As requests do cliente para a API precisarão ter o header: Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b

Como você acha que podemos documentar essa questão?

@berinhard
Copy link
Contributor Author

Me parece que, inicialmente, o blogpost pode ser um bom lugar para falar sobre a autenticação na API. Acho que com isso vem o benefício da pessoa se deperar com o post e ter a chance de pensar "opa, se posso baixar o CSV nem preciso de API então! menos trabalho..."

@turicas
Copy link
Owner

turicas commented Sep 18, 2020

@turicas acha que podemos usar o captcha do Google para isso?

Sim, já temos o recaptcha na página de contato, podemos utilizá-lo no cadastro também.
Precisamos também que os emails sejam confirmados antes do cadastro ficar habilitado para usar a API (não lembro se isso já está feito).

Para a autenticação, na minha opinião a estratégia de TokenAuthentication do DRF nos atende. De acordo @turicas?

Sim.

Com ele as pessoas precisarão:

  1. Realizar uma requisição POST para um endpoint como /api/obtain-auth-token/ informando o email e senha do usuário;
  2. Isso vai gerar um token de acesso e retorná-lo na resposta: { 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' }

Acho mais fácil que o usuário gerencie os tokens pela interface Web e não usemos email/senha na API (somente token). Nesse sentido, seria importante termos alguma política para que o usuário possa deletar/invalidar tokens, além da possibilidade de criar novos (poderia existir uma página de gestão de tokens linkada no menu "Sua conta" -- essa página já poderia explicar rapidamente como funciona a autenticação na API); acho que faz sentido o rate limit ser por usuário, mas talvez possamos deixar um usuário criar mais de um token.

É importante que todas as requisições na API sejam autenticadas (e não somente a da listagem dos dados) e que o usuário consiga acessar a interface do DRF caso esteja logado no navegador e acesse algum endpoint da API.

Como você acha que podemos documentar essa questão?

Inicialmente na página de listagem dos tokens.

Me parece que, inicialmente, o blogpost pode ser um bom lugar para falar sobre a autenticação na API. Acho que com isso vem o benefício da pessoa se deperar com o post e ter a chance de pensar "opa, se posso baixar o CSV nem preciso de API então! menos trabalho..."

Eu posso criar algo baseado nesse comentário.

@berinhard
Copy link
Contributor Author

Esse comentário é para documentar respostas bem completas do @turicas a um dos muitos emails que ele recebeu com questionamentos sobre requisições sendo bloqueadas. Esses textos serão utéis como norte para parte da documentação API e/ou blogpost:

Email 1

Por enquanto estamos ajustando a quantidade de requisições para que os
ataques que estamos recebendo sejam contidos, então não tenho como te
precisar os valores. O que consigo adiantar é que as requisições para
a API serão obrigatoriamente cacheadas em breve. Para que seu site
seja atualizado com frequência e sem onerar muito nossos servidores,
peço que baixe o arquivo completo do dataset e mantenha uma cópia
local, fornecendo os dados para seus usuários a partir dessa cópia e
não diretamente pela API do Brasil.IO. No caso do dataset da COVID-19,
você encontra os links para download das tabelas completas em:
https://brasil.io/dataset/covid19/files/
O projeto é feito por voluntários e mantido por uma campanha de
financiamento coletivo[https://apoia.se/brasilio] e, por isso, nossos
recursos não são tão abundantes quanto gostaríamos (pelo menos para
conseguir segurar essa carga que estamos tendo hoje).

Como estamos bastante sobrecarregados por aqui (atualização do dataset
COVID-19, ataques que recebemos, dados das eleições etc.), não estamos
conseguindo nos comunicar muito bem em todos os canais, por isso
sugiro que acompanhe nas novidades em nosso Telegram, que é onde
atualizamos mais facilmente/recorrentemente: https://t.me/brasil_io
Também é possível acompanhar o desenvolvimento em nosso GitHub:
https://github.com/turicas/brasil.io/issues/

Email 2

a questão é justamente você usar a API. É mais rápido para você e melhor 
para nossos servidores se você baixar o arquivo completo, como comentei
 - assim você fará apenas uma requisição e essa lógica de atualização 
poderá ser simplificada. Veja o link https://brasil.io/dataset/covid19/files/ - 
lá você encontra as tabelas completas para download, não sendo necessário 
baixar de 1.000 em 1.000 registros (cada arquivo contém todos os registros). 

Sobre o 429: ele é um código de erro HTTP, quando o cliente faz muitas 
requisições (da mesma forma que o código 200 significa "OK") e não significa 
que tenham sido 429 requisições.

Email 3

O nosso site está sendo atacado e essa foi a única forma que conseguimos 
de conter os ataques. Nós não temos recursos para pagar uma equipe só 
para isso, ao mesmo tempo não queremos deixar o site offline por conta dos 
ataques, pois muitas instituições dependem dele. No futuro, quando a API 
possuir autenticação, o limite de requisições será maior; no momento essa é 
a única forma e estamos fazendo o melhor possível para continuar servindo 
a nossos usuários (de forma totalmente gratuita).

Em geral vai ser mais rápido (tanto para criar o código, quanto para executá-lo) 
baixar o arquivo completo compactado e filtrá-lo do que fazer diversas 
requisições à API. O código em anexo (escrito em Python) baixa o arquivo, 
descompacta em tempo de execução e só imprime os registros para uma data 
específica, sem salvar o arquivo no disco. Você pode se basear nele para adaptar 
o seu código.

Snippet Python

import csv
import io
from urllib.request import Request, urlopen
from gzip import GzipFile


def brasilio_csv(dataset, table):
    url = f"https://data.brasil.io/dataset/{dataset}/{table}.csv.gz"
    request = Request(url, headers={"User-Agent": "python/urllib"})
    response = urlopen(request)
    fobj = io.TextIOWrapper(GzipFile(fileobj=response), encoding="utf-8")
    for row in csv.DictReader(fobj):
        yield row


for row in brasilio_csv("covid19", "caso"):
    if row["date"] != "2020-09-15":
        continue
    print(row)

Email 4

O IP de seu provedor (X.X.X.X) não está em
nossa lista permanente de bloqueio - isso significa que as mensagens
de erro HTTP 429 que você recebeu foram em decorrência a muitas
requisições sendo feitas num instante curto de tempo, mas isso não
acarretou bloqueio permanente. Por não ter feito uma quantidade grande
(total) de requisições (foi apenas a velocidade delas). Quando isso
acontece, basta dar um intervalo entre as requisições e o sistema
desbloqueará seu IP automaticamente. Se você estiver acessando a API,
então o próprio sistema te responderá com a quantidade de tempo que
você precisa esperar, será algo como:

{
    "message": "Você atingiu o limite de requisições e, por isso, essa
requisição foi bloqueada. Caso você precise acessar várias páginas de
um dataset, por favor, baixe o dataset completo em vez de percorrer
várias páginas na API (o link para baixar o arquivo completo
encontra-se na página do dataset, em
https://brasil.io/datasets/).\nUtilizar a API desnecessariamente e de
maneira não otimizada onera muito nossos servidores e atrapalha a
experiência de outros usuários. Se o abuso continuar, precisaremos
restringir ainda mais a API e não gostaríamos de fazer
isso.\nLembre-se: o Brasil.IO é um projeto colaborativo, desenvolvido
por voluntários e mantido por financiamento coletivo, você pode doar
para o projeto em: https://apoia.se/brasilio",
    "available_in": "43 seconds"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants