Un tutorial pentru inginerie inversă a API-ului privat al software-ului tău: Hacking-ul canapelei

Publicat: 2022-03-11

Călătoriile sunt pasiunea mea și sunt un mare fan al Couchsurfing-ului. Couchsurfing este o comunitate globală de călători, unde puteți găsi un loc unde să stați sau să vă împărtășiți propria casă cu alți călători. În plus, Couchsurfing vă ajută să vă bucurați de o experiență de călătorie autentică în timp ce interacționați cu localnicii. Sunt implicat în comunitatea Couchsurfing de peste 3 ani. Am participat la întâlniri la început, iar apoi am reușit în sfârșit să găzduiesc oameni. Ce călătorie uimitoare a fost! Am întâlnit atât de mulți oameni incredibili din toată lumea și mi-am făcut mulți prieteni. Toată această experiență mi-a schimbat cu adevărat viața.

Eu însumi am găzduit o mulțime de călători, mult mai mulți decât am navigat până acum. În timp ce locuiam într-una dintre principalele destinații turistice de pe Riviera Franceză, am primit o cantitate enormă de solicitări de canapea (până la 10 pe zi în timpul sezonului de vârf). În calitate de dezvoltator back-end independent, am observat imediat că problema cu site-ul web couchsurfing.com este că nu se ocupă cu adevărat de astfel de cazuri de „încărcare mare”. Nu există informații despre disponibilitatea canapelei dvs. - atunci când primiți o nouă cerere de canapea, nu puteți fi sigur dacă găzduiți deja pe cineva în acel moment. Ar trebui să existe o reprezentare vizuală a cererilor dvs. acceptate și în așteptare, astfel încât să le puteți gestiona mai bine. De asemenea, dacă ați putea face publică disponibilitatea canapelei dvs., ați putea evita solicitările inutile de canapea. Pentru a înțelege mai bine ce am în minte, aruncați o privire pe calendarul Airbnb.

Multe companii sunt renumite pentru că nu își ascultă utilizatorii. Cunoscând istoria Couchsurfing-ului, nu m-am putut baza pe ei pentru a implementa această caracteristică în curând. De când site-ul a devenit o companie cu scop profit, comunitatea s-a deteriorat. Pentru a înțelege mai bine despre ce vorbesc, vă sugerez să citiți aceste două articole:

  • http://www.nithincoca.com/2013/03/27/the-rise-and-fall-of-couchsurfing/
  • http://mechanicalbrain.wordpress.com/2013/03/04/couchsurfing-a-sad-end-to-a-great-idea/

Știam că mulți membri ai comunității ar fi fericiți să aibă această funcționalitate. Deci, am decis să fac o aplicație pentru a rezolva această problemă. Se pare că nu există un API public Couchsurfing disponibil. Iată răspunsul pe care l-am primit de la echipa lor de asistență:

„Din păcate, trebuie să vă informăm că API-ul nostru nu este de fapt public și nu există planuri în acest moment să îl facem public.”

Intrând în canapeaua mea

Era timpul să folosesc unele dintre tehnicile mele preferate de inginerie inversă software pentru a intra în Couchsurfing.com. Am presupus că aplicațiile lor mobile trebuie să folosească un fel de API pentru a interoga backend-ul. Deci, a trebuit să interceptez solicitările HTTP care veneau de la o aplicație mobilă către backend. În acest scop, am configurat un proxy în rețeaua locală și am conectat iPhone-ul la acesta pentru a intercepta solicitările HTTP. În acest fel, am reușit să găsesc puncte de acces ale API-ului lor privat și să-mi dau seama formatul lor de încărcare utilă JSON.

În cele din urmă, am creat un site web care are scopul de a ajuta oamenii să-și gestioneze cererile de canapea și de a le arăta navigatorilor un calendar de disponibilitate a canapelei. Am publicat un link către el pe forumurile comunității (care sunt și ele destul de segmentate după părerea mea și e greu să găsești informații acolo). Recepția a fost în mare parte pozitivă, deși unora nu le-a plăcut ideea că site-ul web necesită acreditări couchsurfing.com, ceea ce era într-adevăr o chestiune de încredere.

Site-ul a funcționat astfel: vă conectați la site cu acreditările couchsurfing.com și, după câteva clicuri, obțineți codul html pe care îl puteți încorpora în profilul dvs. couchsurfing.com și voila - aveți un calendar actualizat automat în profilul tau. Mai jos este captura de ecran a calendarului și aici articolele despre cum l-am realizat:

  • https://github.com/nderkach/couchsurfing-python

Exemplu de calendar

Am creat o caracteristică grozavă pentru Couchsurfing și, în mod natural, am presupus că ei ar aprecia munca mea - poate chiar să-mi ofere un post în echipa lor de dezvoltare. Am trimis un e-mail la jobs(at)couchsurfing.com cu un link către site, CV-ul meu și o referință. O scrisoare de mulțumire lăsată de unul dintre oaspeții mei de la couchsurfing:

Notă de mulțumire.

Câteva zile mai târziu, au continuat eforturile mele de inginerie inversă. În răspuns, era clar că singurul lucru de care erau îngrijorați era propria lor securitate, așa că mi-au cerut să scot postările pe blog pe care le-am scris despre API și, în cele din urmă, site-ul. Am eliminat postările imediat, deoarece intenția mea nu era de a încălca condițiile de utilizare și de a căuta acreditările de utilizator, ci mai degrabă de a ajuta comunitatea de couchsurfing. Am avut impresia că am fost tratat ca un criminal, iar compania sa concentrat doar pe faptul că site-ul meu necesită acreditări de utilizator.

Le-am propus să le ofer aplicația mea gratuit. L-ar putea găzdui în mediul lor și îl pot conecta prin autentificarea Facebook. La urma urmei, este o caracteristică grozavă, iar comunitatea avea nevoie de ea. Iată rezoluția finală pe care am primit-o:

„Revenim în leagănul lucrurilor aici după sărbători și am vrut să continuăm.

Am avut câteva discuții interne despre aplicația dvs. și despre modul în care am putea onora atât creativitatea, cât și inițiativa pe care le arată, fără a compromite potențial confidențialitatea și securitatea datelor utilizatorilor Couchsurfing atunci când aceștia își introduc acreditările pe un site terță parte.

Calendarul umple în mod clar un gol pe site-ul nostru, o caracteristică care face parte dintr-un proiect mai amplu la care lucrăm acum.

Dar problema colectării numelor de utilizator și a parolelor rămâne. Nu am putut găsi o modalitate ușoară de a-l configura, astfel încât să putem găzdui sau susține asta de partea noastră, fără a vă permite nici să accesați acele date sau să vă permitem site-ul să fie văzut ca produsul nostru de lucru.

API-ul disponibil în prezent urmează să fie înlocuit în curând cu o versiune care va necesita autentificare/autorizare de la aplicațiile care îl accesează.”

Astăzi, în timp ce scriu acest tutorial de software de inginerie inversă (la un an după evenimente), funcția calendar nu este încă implementată pe Couchsurfing.

Return To Innocence - Hacking My Couch, Again

Acum câteva săptămâni am fost inspirat să scriu un articol despre tehnicile de inginerie inversă a API-urilor private. Bineînțeles, am decis să rezum articolele anterioare pe care le-am scris pe această temă și să mai adaug câteva detalii. Când am început să scriu noul articol, am vrut să prezint procesul de inginerie inversă cu un API actualizat și să iau un alt stub în hackingul API. Pe baza experienței mele anterioare și a faptului că Couchsurfing a anunțat recent o aplicație web și mobilă complet nouă http://blog.couchsurfing.com/the-future-of-couchsurfing-is-on-the-way/, am a decis să-și pirateze din nou API-ul.

De ce fac acest proces de inginerie inversă? Ei bine, în primul rând, este foarte distractiv să faci inginerie inversă a software-ului în general. Ceea ce îmi place în mod deosebit la el, este că nu implică doar priceperea ta tehnică, ci și intuiția ta. Uneori, cel mai bun mod de a înțelege lucrurile este să faci o ghicire educată - te va economisi mult timp în comparație cu forța brută. Recent, am auzit o poveste de la o companie care trebuia să lucreze cu API-uri proprietare și puțină sau deloc documentație. Ei s-au chinuit să decripteze încărcătura utilă de răspuns API într-un format necunoscut de zile întregi, apoi cineva a decis să încerce ?decode=true la sfârșitul adresei URL și avea un JSON adecvat. Uneori, dacă sunteți norocos, tot ce trebuie să faceți este să înfrumusețați răspunsul JSON.

Un alt motiv pentru care fac acest tutorial este că unele companii au nevoie de o mulțime de ani pentru a adopta o anumită caracteristică cerută de utilizatorii lor. În loc să așteptați ca acesta să fie implementat, puteți profita de puterea API-ului lor privat și îl puteți construi singur.

Deci, cu noul API couchsurfing.com, am început cu o abordare similară și le-am instalat cea mai recentă aplicație iOS.

În primul rând, trebuie să configurați un proxy în LAN pentru a falsifica solicitări HTTP care vin de la aplicație către API, efectuând un atac man-in-the-middle (MITM).

Pentru conexiunile necriptate atacul este destul de simplu - un client se conectează la proxy și transmiteți cererile primite către serverul de destinație înainte și înapoi. Puteți modifica sarcina utilă, dacă este necesar. Într-o rețea WLAN publică, este destul de ușor să efectuați acest lucru sub deghizare prin uzurparea identității routerului WiFi.

Pentru conexiunile criptate, există o diferență minoră: toate solicitările sunt criptate end-to-end. nu este posibil ca atacatorul să decripteze mesajul, decât dacă el obține cumva acces la cheia privată (care desigur nu este trimisă în timpul acestor interacțiuni). Acestea fiind spuse, chiar dacă canalul de comunicare API este sigur, punctele finale - în special clientul - nu sunt atât de sigure.

Pentru ca SSL să funcționeze corect, trebuie îndeplinite următoarele condiții:

  • Certificatul serverului trebuie semnat cu o autoritate de certificare (CA) de încredere
  • Numele comun al serverului, din certificat, trebuie să se potrivească cu numele de domeniu al serverului

Pentru a depăși criptarea într-un atac MITM, proxy-ul nostru trebuie să acționeze ca un CA (Autoritate de certificare) și să genereze certificate din mers. De exemplu, dacă un client încearcă să se conecteze la www.google.com, proxy-ul creează în mod dinamic un certificat pentru www.google.com și îl semnează. Acum, clientul crede că proxy-ul este de fapt www.google.com

Această diagramă prezintă pașii pentru a face inginerie inversă a unui API privat.

Pentru a implementa un proxy de sniffing folosit pentru a face inginerie inversă a API-ului privat, voi folosi instrumentul numit mitmproxy. Puteți utiliza orice alt proxy HTTPS transparent. Charles este un alt exemplu cu o interfață grafică frumoasă. Pentru a face acest lucru, trebuie să setăm următoarele lucruri:

Configurați gateway-ul implicit al conexiunii WiFi a telefonului dvs. să fie proxy-ul (astfel încât proxy-ul să fie în mijloc și toate pachetele să treacă prin ele) Instalați certificatul proxy-ului pe telefon (astfel încât clientul să aibă cheia publică a proxy-ului în magazinul său de încredere)

Verificați documentația proxy-ului despre instalarea certificatului. Iată instrucțiunile pentru mitmproxy. Și aici este fișierul certificat PEM pentru iOS.

Pentru a monitoriza cererile HTTP interceptate, pur și simplu lansați mitmproxy și vă conectați la acesta de pe telefonul mobil (portul implicit este 8080).

Setări telefon mobil.

Deschideți un site web în browserul dvs. mobil. În acest moment, ar trebui să puteți vedea traficul în mitmproxy.

Odată ce ați confirmat că totul funcționează, ingineria software inversă poate începe.

După ce vă asigurați că totul funcționează conform planului, este timpul să începeți să explorați API-ul privat ales de dvs. Practic, în acest moment puteți doar să deschideți aplicația, să vă jucați cu ea și să vă faceți o idee despre punctele finale API și structura solicitărilor.

Nu există un algoritm strict cu privire la modul de proiectare inversă a unui API software - de cele mai multe ori te bazezi pe intuiția ta și faci presupuneri.

Abordarea mea este să reproduc apelurile API și să mă joc cu diferite opțiuni. Un început bun este să redați o solicitare pe care ați prins-o în mitmproxy și să vedeți dacă funcționează (apăsați „r” pentru a reda o solicitare). Primul pas este să vă dați seama ce anteturi sunt obligatorii. Este destul de convenabil să te joci cu anteturile cu mitmproxy: apăsați „e” pentru a intra în modul de editare, apoi „h” pentru a modifica anteturile. Cu comenzile rapide pe care le folosesc, dependenții de vim s-ar simți ca acasă. Puteți utiliza, de asemenea, extensii de browser precum Postman pentru a testa API-ul, dar acestea tind să adauge anteturi inutile, așa că vă sugerez să rămâneți la mitmproxy sau curl.

Am realizat un script care citește fișierul dump mitmproxy și generează un șir curl - https://gist.github.com/nderkach/bdb31b04fb1e69fa5346

Să începem cu solicitarea trimisă atunci când vă autentificați.

 POST https://hapi.couchsurfing.com/api/v2/sessions ← 200 application/json 

Primul pas în acest tutorial de inginerie inversă este să reproduci apelurile API și să te joci cu opțiunile rezultate.

Primul lucru pe care l-am observat este că fiecare cerere conține un antet obligatoriu X-CS-Url-Signature care este diferit de fiecare dată. De asemenea, am încercat să redau o solicitare după un timp pentru a verifica dacă există o verificare a marcajului de timp pe server și nu există. Următorul lucru de făcut este să vă dați seama cum se calculează această semnătură.

În acest moment, am decis să fac o inginerie inversă a binarului și să descopăr algoritmul. Desigur, având experiență în dezvoltarea pentru iPhone și având la dispoziție un iPhone, am decis să încep cu iPhone ipa (livrabil pentru aplicația iPhone). Se pare că pentru a decripta unul, am nevoie de un telefon cu jailbreak. Stop! Timpul ciocanului.

Apoi, mi-am amintit că au și o aplicație pentru Android. Am ezitat puțin să încerc această abordare, deoarece nu știu nimic despre Android sau Java. Atunci m-am gândit că ar fi o șansă bună de a învăța ceva nou. S-a dovedit a fi mai ușor să obțineți un cod sursă cvasi-citit de om prin decompilarea codului de octeți java decât codul de mașină pentru iPhone puternic optimizat.

Apk (livrabil pentru aplicația Android) este practic un fișier zip. Puteți folosi orice extractor de fermoar pentru a despacheta conținutul acestuia. Veți găsi un fișier numit classes.dex, care este un bytecode Dalvik. Dalvik este o mașină virtuală folosită pentru a rula bytecode Java tradus pe Android.

Pentru a decompila fișierul .dex în codul sursă .java, am folosit instrumentul numit dex2jar. Rezultatul acestui instrument este un fișier jar, pe care îl puteți decompila cu o varietate de instrumente. Puteți chiar să deschideți un borcan în Eclipse sau IntelliJ IDEA și va face toată munca pentru dvs. Cele mai multe dintre aceste instrumente produc un rezultat similar. Nu ne interesează dacă îl putem compila înapoi pentru a-l rula, îl folosim doar pentru a analiza codul sursă.

Iată o listă cu instrumentele pe care le-am încercat:

  • FernFlower (acum parte a IntelliJ IDEA)
  • CFR
  • JD-GUI
  • Krakatau
  • Procion

CFR și FernFlower au funcționat cel mai bine pentru mine. JD-GUI nu a reușit să decompileze unele părți critice ale codului și a fost inutil, în timp ce celelalte aveau aproximativ aceeași calitate. Din fericire, se pare că codul de cod Java nu a fost ofuscat, dar există instrumente precum ProGuard http://developer.android.com/tools/help/proguard.html pentru a vă ajuta să dezfundați codul.

Decompilarea Java nu este cu adevărat scopul acestui tutorial de inginerie inversă - sunt multe scrise pe acest subiect, așa că să presupunem că ați decompilat și deobfuscat cu succes codul Java.

Am combinat tot codul relevant folosit pentru a calcula X-CS-Url-Signature în următorul text: https://gist.github.com/nderkach/d11540e9af322f1c1c74

În primul rând, am căutat mențiuni pentru X-CS-Url-Signature , pe care le-am găsit în RetrofitHttpClient . Un apel anume părea interesant - către modulul EncUtils . Săpând în el, mi-am dat seama că folosesc HMAC SHA1. HMAC este un cod de autentificare a mesajului care utilizează o funcție criptografică (SHA1 în acest caz) pentru a calcula un hash al unui mesaj. Este folosit pentru a asigura integritatea (adică pentru a împiedica un om din mijloc să modifice cererea) și autentificarea.

Avem nevoie de două lucruri pentru a calcula X-CS-Url-Signature : cheia privată și mesajul codificat (probabil o variație a sarcinii utile a cererii HTTP și a URL-ului).

 final String a2 = EncUtils.a(EncUtils.a(a, s)); final ArrayList<Header> list = new ArrayList<Header>(request.getHeaders()); list.add(new Header("X-CS-Url-Signature", a2));

În cod, a este un mesaj și s este cheia care este folosită pentru a calcula antetul a2 (apelul dublu la EncUtils doar calculează un digest hexadecimal HMAC SHA1).

Găsirea cheii nu a fost o problemă - aceasta a fost stocată în text simplu în ApiModule și a fost folosită pentru a inițializa al doilea parametru al RetrofitHttpClient.

 RetrofitHttpClient a(OkHttpClient okHttpClient) { return new RetrofitHttpClient(okHttpClient, "v3#!R3v44y3ZsJykkb$E@CG#XreXeGCh"); }

Dacă ne uităm la apelul la EncUtils , putem vedea că literalul șir de mai sus este folosit literal ca o cheie pentru a calcula HMAC, cu excepția cazului în care este definit this.b În acest din urmă caz, this.b este atașat cu un punct.

 String s; if (this.b == null) { s = this.a; } else { s = this.a + "." + this.b; }

Acum, doar uitându-mă la cod, nu mi-a fost clar unde și cum este inițializat this.b (singurul lucru pe care l-am putut descoperi este că este numit într-o metodă cu o semnătură this.a(String b) , dar nu am putut găsi un apel către acesta nicăieri în cod).

 public void a(final String b) { this.b = b; }

Vă încurajez să îl decompilați și să aflați singuri :)

Înțelegerea mesajului a fost destul de simplă - în cod puteți vedea că este o concatenare a căii URL, adică /api/v2/sessions și un șir cu sarcină utilă JSON (dacă există).

 final byte[] b = this.b(request.getUrl()); byte[] a; if (request.getBody() != null && request.getBody() instanceof JsonTypedOutput) { System.out.println("body"); // this.a(x, y) concatenates byte arrays a = this.a(b, ((JsonTypedOutput)request.getBody()).a); } else { a = b; }

Doar privind codul, a fost dificil să ne dăm seama care este algoritmul exact pentru calculul HMAC. Deci, am decis să reconstruiesc aplicația cu simboluri de depanare pentru a afla exact cum funcționează aplicația. Am folosit un instrument numit apktool https://code.google.com/p/android-apktool/ pentru a dezasambla bytecode-ul Dalvik folosind smali https://code.google.com/p/smali/. Am urmat ghidul de la https://code.google.com/p/android-apktool/wiki/SmaliDebugging

După ce ați creat apk-ul, trebuie să îl semnați și să îl instalați pe dispozitiv. Deoarece nu aveam un dispozitiv Android, am folosit emulatorul care vine cu Android SDK. Cu puțină hrănire cu lingura, iată cum o faci:

 jarsigner -verbose -keystore ~/.android/debug.keystore -storepass android -keypass android <path_to_your_built_apk> androiddebugkey jarsigner -verify -verbose -certs <path_to_your_built_apk> zipalign -v 4 <path_to_your_built_apk> <path_to_your_output_signed_apk>

Am folosit un emulator Android încorporat care vine cu sdk și o imagine virtuală Atom x86 cu HAXM activat pentru a mă asigura că funcționează fără probleme.

 tools/emulator -avd mydroid -no-boot-anim -cpu-delay 0

Iată un ghid frumos despre cum să configurați o imagine virtuală: http://jolicode.com/blog/speed-up-your-android-emulator

Asigurați-vă că vedeți că linia HAX funcționează și emulatorul rulează în modul virt rapid la pornirea emulatorului pentru a vă asigura că aveți HAXM activat.

Apoi, am instalat apk-ul în emulator și am rulat aplicația. Urmând ghidul apktool, am folosit depanatorul de la distanță IntelliJ IDEA pentru a se conecta la emulator și a seta câteva puncte de întrerupere a liniilor:

Unele tehnici de inginerie inversă implică rularea aplicației și doar să vedem ce se întâmplă.

Jucându-mă puțin cu aplicația, am reușit să-mi dau seama că cheia privată utilizată pentru a inițializa RetrofitHttpClient este folosită pentru calcularea HMAC a unei semnături de solicitare de conectare. În răspunsul la POST de conectare, primiți un ID de utilizator și accessToken ( X-Access-Token ). Jetonul de acces este utilizat pentru a autoriza toate solicitările următoare. HMAC-ul pentru toate cererile post logare este construit în același mod ca și cererea de conectare, cu excepția faptului că cheia este compusă prin adăugarea .<user_id> la cheia privată originală.

Acesta arată procesul de autorizare necesar pentru ingineria inversă a acestui API privat.

Odată ce sunteți autorizat, aplicația trimite următoarea solicitare:

 POST https://hapi.couchsurfing.com/api/v2/users/1003669205/registerDevice ← 200 application/json

După cum am putut deduce empiric, această solicitare este opțională pentru autentificare. Puncte bonus dacă vă dați seama la ce este folosit!

Odată autentificat, puteți trimite o solicitare pentru a prelua profilul dvs. de utilizator (sau al oricui altcuiva), astfel:

 GET https://hapi.couchsurfing.com/api/v2/users/1003669205 ← 200 application/json 

În acest proces de inginerie inversă, puteți prelua profilul de utilizator al oricui.

Nu am intrat prea mult în detalii, dar am observat că un profil este actualizat cu o solicitare PUT. Doar pentru distracție, am încercat să actualizez un alt profil cu aceeași solicitare - nu a fost autorizat, așa că se pare că sunt implementate elementele de bază de securitate.

Am scris un script Python simplu pentru a vă autentifica folosind acreditările couchsurfing.com și pentru a obține profilul dvs. de utilizator: https://gist.github.com/nderkach/899281d7e6dd0d497533. Iată wrapper-ul Python pentru API: https://github.com/nderkach/couchsurfing-python cu un pachet disponibil în depozitul pypi (pip install couchsurfing).

Pasii urmatori

Nu sunt sigur ce voi face exact cu API-ul de data aceasta. Codul HTML din profilurile utilizatorului nu mai este permis, așa că va trebui să vin cu o abordare diferită a vechei probleme. Voi continua să dezvolt și să îmbunătățesc python API wrapper, dacă există o cerere pentru el și presupunând că couchsurfing.com nu va cauza prea multe probleme. Nu am explorat prea mult API-ul și doar l-am testat pentru câteva vulnerabilități de bază. Pare suficient de sigur, dar ar fi interesant să aflați dacă puteți obține acces la datele care nu sunt disponibile prin intermediul site-ului. Oricum ar fi, acum puteți folosi ingineria mea de software inversă pentru a construi un client alternativ pentru Windows Phone, Pebble sau canapeaua dvs. inteligentă.

Încheiere cu o întrebare

Există o discuție pe care aș dori să o deschid - de ce să nu-ți publici API-ul și să-l faci public? Chiar dacă nu am reușit să piratez API-ul, tot ar fi posibil să răzuiesc site-ul. Ar fi mai lent și mai dificil de întreținut, dar cu siguranță ar prefera ca consumatorii să folosească un API mai degrabă decât un web scraper. Disponibilitatea API-urilor ar permite dezvoltatorilor terți să îmbunătățească produsul companiei și să construiască servicii cu valoare adăugată în jurul acestuia. Se poate argumenta că ar fi mai costisitor să se mențină API-ul public decât unul privat; dar, din nou, avantajele serviciilor de creare a comunității pe lângă produsul dvs. ar depăși costurile de întreținere API.

Este posibil să previi complet utilizarea unui API privat de către clienții terți? nu cred. Utilizarea fixarii SSL ar preveni identificarea solicitărilor API folosind o tehnică simplă de proxy transparent, așa cum este descris mai devreme. În cele din urmă, chiar dacă ofuscați binarul, un hacker motivat, cu anumite resurse și timp, va putea întotdeauna să facă o inginerie inversă a binarului aplicației și să obțină cheia privată/certificatul. Cred că presupunerea că punctul final al clientului este sigur este în mod inerent greșită. Un client API este un punct slab.

Păstrând un API privat, o companie transmite practic un mesaj de neîncredere utilizatorilor lor. Cu siguranță, puteți încerca să vă protejați și mai mult API-ul privat. Cu toate acestea, nu ați prefera să implementați o securitate de bază pentru API pentru a preveni utilizarea rău intenționată; și, în schimb, vă concentrați resursele pe îmbunătățirea software-ului pentru a oferi o experiență mai bună pentru utilizator?

Couchsurfing, te rog frumos, cu zahăr deasupra, deschide API-ul.