Coder Social home page Coder Social logo

backend's People

Contributors

arthurkowalsky avatar dependabot[bot] avatar gucio1200 avatar michalsikora1 avatar pawelmajthecoders avatar qlb avatar tomaszmolenda avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

backend's Issues

Podstawowa wersja CMS dla adminów

  • Admin może zobaczyć nowych pacjentów i oznaczyć ich jako zweryfikowany / niezweryfikowany
  • Admin może zobaczyć jakich użytkowników napotkał pacjent, kiedy, jak często i jaka była siła sygnału spotkani
  • Admin wybiera i oznacza wybranych użytkowników jako red

nie działa Exposure Notifications Express

Is your feature request related to a problem? Please describe.
Czy zostanie wprowadzony Exposure Notifications Express, update na IOS już jest
Describe the solution you'd like
Wprowadzenie exposure notification express
Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
b/d
Additional context
b/d

Synchronizacja danych z baza GISu.

Czesc,

zostawie wam tu mala notke na prosbe czlonkow zespolu z ktorym pracowalem nad prawie tym samym tematem. Ciut nas wyprzedziliscie wiec zamykamy temat, z ta jedna roznica ze..

Rozwazcie synchronizacje z danymi GISu ktory identyfikuje zarazonych na podstawie numeru telefonu. Mechanizm juz jest bo korzysta z niego Aplikacja Kwarantanna domowa.

Majac informacje na urzadzeniu o tym ze dany pacjent jest chory bedziecie w stanie policzyc i powiedziec innym uzytkownikom ze mogli byc narazeni na kontakt z chorym, oraz pomoc GISowi w sledzeniu epidemii co defakto chcielismy my zrobic.

Chetnie odpowiem na pytania jesli sie takowe pojawia i bedzie wola dzialan z waszej strony bo dosc mocno juz rozkminilismy temat jak to powinno dzialac.

Pozdrawiam

Zabezpieczenie procesu rejestracji

Jeśli API byłoby dostępne, wysyłając odpowiedniego requesta na /register można komuś zrobić psikusa, gdyż nie ma możliwości walidacji numeru telefonu, który poda się w zgłoszeniu o rejestrację.

Rozważyć więc należy możliwość dodania pola adresu IP (wiem, kwestia prywatności..), z którego poszedł request rejestracji,
co da możliwość zastosowania jakiegoś throthlingu, a w razie czego blokowania/zgłoszenia dowcipnisia. Można też korzystać z unikalnego identyfikatora urządzenia/instalacji aplikacji, ale
to jest nieweryfikowalne i wiadomo, że to co leży na urządzeniu jest raczej "jawne" i do zmanipulowania poza aplikacją.

Race condition w confirm_registration pozwalający na stworzenie kilku userów z tym samym msisdn

Wywołania get i put w confirm_registration nie znajdują się wewnątrz transakcji. Oznacza to, że przy wielokrotnym wywołaniu funkcji dla tych samych parametrów może dojść do stworzenia dwóch lub więcej instancji użytkownika w datastore. Przykład:

T Request 1 Request 2
1 _get_registration_entity(registration_id) => REGISTRATION_STATUS_PENDING
2 _get_registration_entity(registration_id) => REGISTRATION_STATUS_PENDING
3 _update_registration(registration_entity, REGISTRATION_STATUS_COMPLETED)
4 _update_registration(registration_entity, REGISTRATION_STATUS_COMPLETED)
5 _get_existing_user_id(registration_entity["msisdn"]) => None
6 _get_existing_user_id(registration_entity["msisdn"]) => None
7 user_id = secrets.token_hex(32) user_id = secrets.token_hex(32)
8 datastore_client.put(user)
9 datastore_client.put(user) (inny user_id)

Poprawienie weryfikacji IP clienta

Podczas rejestracji i zapewne nie tylko adres klienta pobierany jest tak:
ip = request.headers.get('X-Forwarded-For')

Jest to nieprawidłowe, gdyż, gdy w zapytaniu występuje już nagłowek X-Forwarded-For z jakakolwiek wartoscia np fake_ip - proxy googlowe po drodze doda kolejny adres do tego nagłóowka. Bedzie on wygladal tak:
fake_ip, client_ip
Wtedy wzięcie całego stringa do porównania spowoduje, że trywialnie łatwo bedzie można spoofować ten nagłowek - bez wysiłku zmiany prawdziwego adresu IP.
Jesli w naglowku jest lista adresow - trzeba brac ostatni (jeśli podczas testow w naglowku dostawaliscie jeden IP).

DOC: https://cloud.google.com/load-balancing/docs/https , https://tools.ietf.org/html/rfc7239

/get_status zapisuje dane o użytkowniku

Każde wywołanie /get_status nadpisuje w bazie danych dane użytkownika przesłane w żądaniu: platform, os_version, device_name, app_version, lang
Pole last_status_requested ustawiane jest na now()

Repozytorium nie zawiera kodu aplikacji

To repozytorium zawiera kod starej wersji aplikacji (od której funkcjonalnie nowa wprawdzie nie różni się prawie niczym), ale nie jest to kod, który jest odpalony na właściwym serwerze produkcyjnym ProteGO Safe.

Repozytorium powinno zostać zaktualizowane o nową wersję kodu, tak jak stało się to z repozytoriami android i ios.

Jeżeli kod backendu i alogrytmy określajace stan zagrożenia nie mają być publiczne - powinno być to wprost napisane w https://github.com/ProteGO-Safe/specs a to repozytorium powinno zostać usunięte, bo teraz wprowadza tylko w błąd.

limit_requests niepotrzebnie składuje adresy IP w bazie danych

Z tego co rozumiem, zakładamy, że ostatni człon w X-Forwarded-For jest wystarczająco precyzyjnie powiązany z człowiekiem, że warto go używać do karania spamerów.
(Zakładam, że wiemy to, bo sami ustawiamy ten nagłówek na krawędzi systemu by był równy IP z którego przychodzi request)
Następnie w oparciu o ten ip budujemy string używany jako klucz pod którym w Redisie trzymamy sobie ile requestów robiono do danej funkcji w danym okresie z danego ip:

    key = f"{function}:{period}:{ip}"

Wygląda na to, że dekoratora limit_request używamy w dość sensytywnej sądząc po nazwie funkcji send_encounters - dopiero zapoznaję się z projektem, więc mogę się mylić, ale nazwa brzmi jak coś czego się używa gdy się jest chorym i chce się przesłać na serwer listę spotkanych idików.

A zatem, jeśli ktoś zajrzy do Redisa i poszuka sobie kluczy zaczynających się od prefixu send_encounters:day:, to czy przypadkiem nie dostanie na tacy adresów IP osób, które są z dużym ppb są chore, a przynajmniej sądzą, że są, a przynajmniej korzystały z endpointu send_encounters, a przynajmniej jakieś IP które uważamy za dostatecznie precyzyjnie powiązane z takimi ludźmi?

Z tego co rozumiem, nie ma potrzeby by klucz key był czytelny dla ludzi czy ogólnie "odwracalny" - wystarczy tylko by istniała funkcja różnowartościowa z krotek (function,period,ip) w takie stringi.
Oczywiście liczba różnych function, różnych period a nawet różnych ip jest bardzo mała, więc zwyczajnie zahashowanie tego nie wystarczy, bo mogę sobie bruteforcem przeglądnąć wszystkie takie krotki i sprawdzić, które z nich po zahashowaniu są kluczami w Redisie.

Nie wiem ile "instancji" tego serwera mamy i jak długowieczne one są, ale może wystarczyłoby, żeby serwer przy starcie losował sobie jakiś salt, znany tylko jemu tj. trzymany w jakiejś pythonowej zmiennej, którego będzie używał przez cały czas aż padnie, by solić hashe?

Alternatywnie, może mógłby ów salt być jakoś wstrzykiwany z zewnątrz przez jakiś Env - to nieco mniej bezpieczne, ale zakładam, że jak ktoś ma dostęp do tej części serwera ORAZ do Redisa, to jest to sytuacja o oczko gorsza niż jeśli ma dostęp tylko do Redisa (czy jego dumpów, backupów, komunikacji, logów?), więc jest postęp.

Użytkownik może zarejestrować się bez nr telefonu

Ze względu na to, że numer telefonu nie będzie obowiązkowy (ProteGO-Safe/specs#34 (comment)) użytkownicy mogą zarejestrować się bez nr telefonu.

Potrzebujemy albo nowego endpoint'u /register_no_msisdn albo istniejący endpoint /register nie powinien wymagać msisdn i od razu zwracać user_id. Jak lepiej?

Częścią tego issue jest też aktualizacja dokumentacji.

Mamy podrasowaną wersję rejestracji

Proces rejestracji jest najbardziej newralgicznym elementem naszego systemu. Musimy zabezpieczyć się przed następującymi próbami nadużyć:

  • ktoś spamuje różne numery telefonu naszymi kodami (i naraża nas na koszty)
  • ktoś spamuje jeden numer telefonu naszymi kodami (i naprzykrza się)
  • ktoś próbuję uniemożliwić komuś rejestrację wysyłając /register tuż po tym jak rejestrujący się rozpoczął rejestrację, tym samym zmieniając jego kod

Jak osiągnąć powyższe:

  • jeśli z jakiegoś IP przychodzą żądania rejestracji, które nie kończą się powodzeniem, pozwalamy zrobić kolejne (wysłać SMS) po odczekaniu jakiegoś timeout'u
  • nie wysyłamy SMSa na ten sam numer częściej niż 1 na minutę
  • nie wysyłamy SMSa na ten sam numer częściej niż 4 na godzinę
  • kod weryfikacyjny jest taki sam przez 10 minut. To znaczy, że jeśli ktoś w ciągu 10 minut jeszcze raz wywoła /register dla takiego samego numeru dostanie taki sam kod (!)
  • kod weryfikacyjny jest ważny przez 10 minut. Użytkownik ma 10 minut na wpisanie poprawnego kodu
  • zapisujemy każde wywołanie /register do tabeli Registrations. czyścimy starsze niż 24h
  • zapisujemy do Registrations czy wysłaliśmy wiadomość SMS
  • zapisujemy do Registrations czy zakończyło się powodzeniem
  • limitujemy /verify_registration do 3 razy na godzinę dla tego samego numeru.

Zwracamy aplikacjom za ile czasu mogą ponowić zapytanie.

Kod do tego musi być super klarowny i wszystkie oczy na pokład.

Treści wiadomości:
pl: Twój kod dla NAZWA to: 123-456
en: Your NAZWA code is: 123-456

Źródła i inspiracje:
https://www.twilio.com/docs/verify/developer-best-practices
https://stackoverflow.com/questions/20839638/how-do-you-prevent-verification-code-attack-to-server

Współdzielenie kodu między funkcjami

Obecnie wiele funkcji zawiera duplikacje kodu - walidacja standardowych parametrów, pobieranie/aktualizowanie użytkowników w Datastore itp.

Wynika to ze specyfiki Cloud Functions które muszą być niezależne od siebie oraz posiadać plik main.py w głównym katalogu z funkcją. Nie ma możliwości importowania z plików będących poza katalogiem z plikiem main.py.

Proponuję rozwiązanie polegające na utworzeniu pliku utils.py (przykładowo) w nadrzędnym folderze repozytorium. Plik ten zawierałby wspólne metody dla wszystkich funkcji. Plik byłby linkowany na poziomie deploymentu przez terraforma poprzez

  1. utworzenie definicji pliku
data "local_file" "utils" {
  filename = "${path.module}/utils.py"
}
  1. dodanie go przy tworzeniu pliku ZIP, np:
// START check_version
[...]
data "archive_file" "check_version" {
  type        = "zip"
  output_path = "${path.module}/files/check_version.zip"
  [...]
  source {
    content  = "${file("${data.local_file.utils.filename}")}"
    filename = "utils.py"
  }
}

W każdej funkcji wystarczy zaimportować metody z modułu zwykłym importem:
from utils import ...

Co ważne, lokalne środowisko nie musi być zmieniane - ustawiając katalog nadrzędny z tego repozytorium jako katalog nadrzędny projektu, wszystkie importy działają lokalnie, a zmiana jest tylko na poziomie terraforma do wdrożenia.

Propozycja zmian

Aby nie wprowadzać ludzi w błąd proponujemy archiwizację obecnego master'a. Nowy układ będzie zawierał konfigurację proxy.

/get_status zwraca identyfikatory do rozgłaszania na 7 dni do przodu

Serwer ma zwrócić listę identyfikatorów, które telefon ma używać do rozgłaszania przez Bluetooth. Każdy identyfikator to UUID (16 bajtów). Każdy identyfikator ma być ważny przez jedną konkretną godzinę czasu lokalnego. Serwer powinien zwrócić listę identyfikatorów na 7 dni do przodu (czyli 7x24 = 168 identyfikatorów). Serwer generuje brakujące identyfikatory, zapisuje je w bazie Beacons i zwraca telefonowi w postaci:

beacon_ids : [ 
{"date":"2020032715", "beacon_id": "685632a0-3f03-4221-bd95-5a3fab6ff77f"},
{"date":"2020032716", "beacon_id": "0537d93b-7c7a-489c-abbc-690f03889b09"},
...
]

data jest w postaci YYYYmmddhh

Nieprawidłowa interpretacja wartości nagłówka X-Forwarded-For

Według dokumentacji Google Cloud:

X-Forwarded-For: [CLIENT_IP(s)], [global forwarding rule IP]
A comma-delimited list of IP addresses through which the client request has been routed. The first IP in this list is generally the IP of the client that created the request. The subsequent IPs provide information about proxy servers that also handled the request before it reached the application server. For example:

X-Forwarded-For: clientIp, proxy1Ip, proxy2Ip

Oznacza to, że wartość X-Forwarded-For może być w niektórych przypadkach listą adresów IP. Wygląda na to, że można w łatwy sposób oszukać poniższy kod:

https://github.com/ProteGO-app/backend/blob/ce9a500aefacc180e3a90134fa8e82fc8c72b399/functions/register/main.py#L89-L92

ponieważ z reguły serwery doklejają adres IP jeśli klient wyśle ten nagłówek (nie testowałem na Google Cloud).

Dodawanie encounters w mniejszych paczkach aby zmieścić się w limitach GC

Na stronie Quotas and Limits można znaleźć informację o maksymalnym rozmiarze requestu HTTP w przypadku Streaming inserts (używane przez insert_rows):

HTTP request size limit: 10 MB (see Note)
Exceeding this value will cause invalid errors.
Note: Internally the request is translated from HTTP json into an internal data structure. The translated data structure has its own enforced size limit. It's hard to predict the size of the resulting internal data structure, but the chance of hitting the internal limit is very low if you keep your HTTP requests to 5 MB or less.

Oczywiście 5 MB to sporo i jest szansa że to nigdy się nie wydarzy (zależy jak działa aplikacja mobilna) ale myślę, że z uwagi na fakt, że te dane są niezwykle ważne i nie wiadomo kiedy i czy nastąpi retry warto rozważyć trzymanie się limitu 5 MB przy dodawaniu tych danych. W praktyce trzeba wywołać insert_rows kilka razy z mniejszymi paczkami.

Originally posted by @bartekn in https://github.com/ProteGO-app/backend/pull/34/files

Endpoint confirm_registration zwraca HTTP500 na środowisku deweloperskim

Request:

:method: POST
:scheme: https
:path: /confirm_registration
:authority: europe-west3-anna-dev-272212.cloudfunctions.net
accept: */*
content-type: application/json
accept-encoding: gzip, deflate, br
user-agent: ProteGO%20Dev/1 CFNetwork/1121.2.1 Darwin/18.7.0
content-length: 177
accept-language: en-us

{
	"appVersion": "1.0",
	"lang": "en",
	"code": "SYYAN",
	"registration_id": "6c870d3f82a8f33d0b1ab0c1fd0a8d09",
	"osVersion": "13.3",
	"deviceType": "iPhone 8",
	"platform": "ios",
	"apiVersion": "1"
}

Response:

:status: 500
x-cloud-trace-context: bcd60228726dd4b472df3091e188a597;o=1
date: Fri, 03 Apr 2020 14:03:51 GMT
content-type: text/html; charset=UTF-8
server: Google Frontend
content-length: 323
alt-svc: quic=":443"; ma=2592000; v="46,43",h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,h3-T050=":443"; ma=2592000


<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>500 Server Error</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Server Error</h1>
<h2>The server encountered an error and could not complete your request.<p>Please try again in 30 seconds.</h2>
<h2></h2>
</body></html>

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.