Amikor négy szereplőből nem a PHP-t kell utálni véletlen...

Ilyen is ritkán van, amikor van egy négy szereplős történet (IETF, Microsoft, PHP, egy API-nak a tervezői) és kivételesen nem a PHP-t kell szidni. :)

Probléma: van egy API, ami gyakorlatilag egy RFC, URL encodeolva kell elposztolni nekik a kérésem, ami áll egy felhasználónévből, magából a kérésből és egy hashból, ami sha1(urlencode(request) + sha1(jelszó)) formában épül fel. Probléma az, hogy az az encodeolt URL-ben a %XX-nél engedélyezett a %xx is, ami ugye egészen más hasht eredményez. Ezt az ide vonatkozó RFC 1738 is világosan leírja:

In addition, octets may be encoded by a character triplet consisting
of the character "%" followed by the two hexadecimal digits (from
"0123456789ABCDEF") which forming the hexadecimal value of the octet.
(The characters "abcdef" may also be used in hexadecimal encodings.)

Na most a bökkenő az, hogy a Microsoftnál valaki úgy gondolta, hogy inkább a "may also" kezdetű részt implementálja, ahogy az a HttpEncoderUtility.cs 32. sorában látszik is, szemben a PHP-vel, akik eddig már nem olvasták el az RFC-t, és maradtak az egyszerűbb megoldásnál.

Többit ki lehet találni.

Szóval kérdés, hogy kit rúgjunk fejbe?

- az IETF-et, hogy miért kell olyan szabványt készítenie, amely többféleképp is értelmezhető?
- a Microsoftot, mert utálni kell élt a szabvány adta lehetőséggel?
- a PHP-t, mert nem úgy csinálta, mint a Microsoft azt egyébként is utáljuk?
- az API tervezőit, amiért erre nem gondoltak?

:)

Hozzászólások

> és egy hashból, ami sha1(urlencode(request) + sha1(jelszó)) formában épül fel

Ez vicc, ugye? :)

Ezzel tobb problema is van:
- Jelszot kliensoldalon nem kell "saltolni" (ez egyebkent sem salt). Szerveroldalon, tarolasnal kell.
- Minden requesttel jelszot kuldeni? Erre valok az auth tokenek.
- Teljesen mindegy, hol, de az sha1 nem jelszo hashelesere van.

Eleve nem ertem egyebkent, hogy mi a cel ezzel a sha1(query + sha1(jelszo)) dologgal.

A cél(ok) a következők lehetnek:

- Jelszó küldése hálózaton keresztül, mert kell valami, amivel azonosítani lehet az usert. (Most tök mindegy, hogy auth token, vagy név+jelszó páros).
- Lehetőleg mindezt anélkül, hogy az könnyen kideríthető lenne.
- Naplózható legyen a kérés olyan formában, hogy abból ne legyen triviális visszafejteni a jelszót. (Ugye, ha csak egy hash lenne vagy egy token, akkor az elég triviális lenne ellopni az egész requestet ismerve)
- Valószínűleg azért az sha1(jelszó) kerül hozzáfűzésre, mert ők is sha1-el hashelve tárolják a jelszót. (Egyébként tökmindegy mire van, rengetegen használják ezt és még mindig jobb, mint az md5 ilyen célra.)

Egyébként nekem egy picit úgy tűnik, hogy te erre csak szimplán ránéztél, viccnek minősítetted, azt azonban nem gondoltad végig, hogy mi lehetett vele a céljuk.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

-Nem egészen, mert egy tokennek általában van lejárata. Jobb esetben mire hozzájutnak, érvénytelen.
-Ez még simán bruteforce-olható.
-???
-Ha az SHA1-et küldözgeted, kb semmi értelme az egésznek. Aki ellopja, nem is kell visszafejtenie a jelszót, elég neki az sha1-es változat, amit ugyan úgy elküldhet. Ha így is tárolják, az szimpla öntökölszúrás, mert egy db szivárgás esetén minden autentikációhoz szükséges adat ott van, vissza sem kell fejteni.
+1: Így hogy ismert a saltoláshoz használt string, nem sokat nehezít a dolgon. Ennyiből tárolhatod plain text-ben is.

DigitalOcean 10$ kredit- Cloudatcost VPS 50%: MEQy2epUny - <3 openSUSE, Ubuntu, KDE <3

Nyilván brute forceolható ez is, de tekintve, hogy maga az adat még mindig 3-4+ nagyságrenddel nagyobb, mint a jelszó, _kevésbé_ törhető mintha csak a jelszót küldenéd. Security téren meg szerintem még mindig ott tart a tudomány, hogy hogyan tudjuk nehezebbé és nem lehetetlenné tenni a törést.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Hiába 3-4+ nagyságrenddel nagyobb, ha amúgy kódolatlanul is benne van a kérésben, ergo ismert, az sha1(urlencode(ismert_adat)+sha1($jelszó))-ból csak a $jelszó-t kell variálni a bruteforce-hoz.
Ettől nem tart még egy nagyságrenddel sem tovább.

DigitalOcean 10$ kredit- Cloudatcost VPS 50%: MEQy2epUny - <3 openSUSE, Ubuntu, KDE <3

- Rossz esetben meg nem.
- Mit akarsz bruteforce-szolni? A 160b-es szamot megtippelni az tehetseg. :)
- A tokent vegig titkos adatkent kell kezelni, egy ilyen hash-t nem.
- De nem a jelszo SHA1-et kuldozgeti, hanem a SHA1(urlencode(request) + SHA1(jelszo))-t ami allatira nem ugyanaz. Vedd eszre, hogy ez mas request eseten mas eredmenyt ad, igy a jelszo megtalalasahoz ket SHA1 preimage attack kell. Tulajdonkeppen ez egy HMAC szeru konstrukcio akar lenni, es akar biztonsagos is lehet ha a request-ben van olyan adat (pl. ido) ami kizarja a replay atack-eket.

Persze, bár ahogy arról már szó volt, ha az egész üzenet is kikerül, akkor egyszerűbb a törés. Ellenben használható a hash egyben az üzenet ellenőrzésére, hogy ugyanazt kapta-e a vevő, mint amit a feladó akart küldeni (+auth).

Bár hozzáteszem: azt én is vitatom, hogy valóban ez lenne a legjobb megoldás.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

-Rossz esetben valóban
-Jelen felállásban elég a jelszót, ami lehet egy karakter is, a policy-t nem ismerjük
-Ebben az esetben azt is jó lenne
-Elég egy requestnek nekimenni, és offline is törhető

DigitalOcean 10$ kredit- Cloudatcost VPS 50%: MEQy2epUny - <3 openSUSE, Ubuntu, KDE <3

Ne erts felre, nem csinalnek ilyet es nem is nagyon akarom vedeni ezt a megoldast, de...

> Jelen felállásban elég a jelszót, ami lehet egy karakter is, a policy-t nem ismerjük

Valoban, de nem tudod a jelszo hosszat a hash-bol, igy ha ellopsz tobb hasht mas felhasznaloktol akkor nem tudod melyiket erdemes tamadni.

> Elég egy requestnek nekimenni, és offline is törhető

Persze, de hosszu jelszo eseten ez eleg sokaig tartana. Ez mindenkeppen jobb mint a cleartext.

Nomostan ha valamit lehet kétféle módon csinálni, akkor annál számítani kell arra, hogy kétféle módon fogják csinálni.

Egyébként sem vagyok egy lúmen, de ezt most különösen nem értem. Az üzenetben nincs urlencode, csak a hash-képzésnél? Ott már minek?

Mert a "tetszőleges bináris adat" jelen esetben a saját objektumaid lenne, ami aztán végképp programnyelv függő. Az urlencode itt csak egy serializálási forma. Lehetne helyette JSON, XML, vagy akár egy adott formátumú Excel tábla is.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

És pont itt a baj. Olyan adatból akarnak hasht számolni, amely adat egy nem egyértelmű szerializációval áll elő. Ennyi, ők a hülyék. Sem az MS, sem a PHP, sem az IETF, csak az API kitalálói. Ha bárhova egy requestben szerializált adat kell, akkor egyértelműnek kell lennie a szerializálásnak mindkét (küldő és fogadó) oldalon.

Igen, ezt szerintem egyértelműen leírtam én is.

Azonban a probléma elkerülhető/minimalizálható lenne azzal, hogy ha
- az IETF nem csinálna olyan szabványt, amit kétféleképp is lehet értelmezni.
- a Microsoft nem a "may" kezdetű szakaszt implementálná.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

> Az IETF nem csinálna olyan szabványt, amit kétféleképp is lehet értelmezni.

Itt nem ket ertelmezesrol van szo, hanem ket szabalyos megoldas van. Egyik sem rosszabb mint a masik. Ettol ez meg nem lesz jo, hiszen a teljes implementacionak mind a kettot kezelnie kell.

> a Microsoft nem a "may" kezdetű szakaszt implementálná.

nade azert van a "may" kezdetu szakasz, mert ugy is lehet helyesen csinalni. A gond nem ezzel van, hiszen ez nem hibas viselkedes hanem azzal, hogy valaki nem figyelt erre es feltetelezte, hogy csak egy helyes megoldas van.

Nem egészen értjük egymást, az urlencode egy byte*->byte* típusű függvény, a jelen problémából minden további nélkül ki lehetne hagyni.

Általános esetben az alábbi módszert lehet használni, ha adott valamilyen 'X' objektum, és 'f' szerializátor (még ha nem egyértelmű is):

X' := f(X)
Üzenet := userid + X' + HASH(X' + jelszó)

Fogadó oldalon először a hash validságát kell ellenőrizni, utána kiszámolni az f inverzét X'-re.

A baj az, hogy az urlencode az nem egy, hanem két függvény valójában. A kliensek számára az van megadva a specifikációban valójában, hogy (f1 vagy f2 közül valamelyiket használd), az egyik kliens f1-et, a másik f2-t használja, a fogadó fél (aki meg ellenőriz), valójában f1-et akar, csak nem ezt specifikálta.

Nem lehet, hogy körbe-körbe járunk? Ebben a konkrét esetben az urlencode/decode simán kihagyható. Az általános esetről meg fentebb írtam:

X' := f(X)
Üzenet := userid + X' + HASH(X' + jelszó)

Fogadó oldalon először a hash validságát kell ellenőrizni, utána kiszámolni az f inverzét X'-re.

Szerk (az összehasonlítás kedvéért): most ugyebár ez van:
X' := f(X)
Üzenet := userid + X + HASH(X' + jelszó)
ez tényleg csak akkor működik, ha 'f' egyértelmű, egyébként hibásan definiált a protokoll.

4. , es nem csak ez a gyanus resz a tervben.

Amit nem lehet megirni assemblyben, azt nem lehet megirni.

Szerintem eléggé egyértelművé kellett volna már válnia mindenkinek, hogy az urlencode itt arra szolgál, hogy a saját rendszered objektumait, amik "szerteszét vannak a memóriában" az adott programnyelv belső adatszerkezete szerint egy mindkét fél által ismert formátumban tárolható, továbbítható formára hozzuk. Barátok közt egyébként ezt hívják szerializációnak.

Lehetett volna Json, XML, megfelelő struktúrájú markdown vagy akár egy jól definiált PNG is, de a készítők ezt választották.

(Feltételezem azért, mert túloldalt PHP van és így egyből megkapják $_POST tömbben az adatot és nem kell a parseolásával foglalkozni csak a validálásával, de ez totálisan részletkérdés.)

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Jó, ilyen szempontból valóban nem volt pontos a megfogalmazásom. A Request ez esetben egy HTTP szabványnak megfelelő Request, példakódban a http_build_query kimenete, ami egy arraykupacot, objektumot képes a HTTP szabványnak megfelelő kulcs

=érték párok a hozni. De ne már, hogy még mindig itt tartunk.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Nem egészen értem, az adattartalom az URL-ben van leégetve, és üres BODY -t POST-oltok? Jaj.

--
arch,debian,osmc,android,windows

En akkor is a Javascriptet utalom. Jobban mint a PHP-t.

Igen, a PHP rosszul tervezett nyelv tele hibakkal, de legalabb nem ereznek az emberek olyan eros kenyszert write-only kod irasara, mint a Javascript nyelvi eszkoztaranak "hatasara". Ennyit engedtessek meg felhoznom a PHP vedelmeben: ritka a write-only debuggolhatatlan PHP kod.

Ennek a threadnek a bonyolultsaga:

http://stackoverflow.com/questions/6597493/synchronous-database-queries…

Mar onmagaban is egy notable example.

Baromi egyszeru kerdes kene hogy legyen, es minden ertelmes valasz kilometer hosszu a nyelv hulyesegei miatt.

Aztan mikor hataridore programozol nem olvasol vegig ennyit, megcsinalod az elso modszerrel ami mukodik. Akkor kodolsz szepen, ha van ra idod (altalaban nincs), vagy ha van egy lehuto, akinek van ideje rad szolni, hogy kodolj szebben, cserebe nem sok produktiv munkat csinal, azt is lassan.

Az async-ot szerintem normaliseknal igy csinaljak:
http://www.cplusplus.com/reference/thread/thread/
Vagy igy:
http://tutorials.jenkov.com/java-concurrency/creating-and-starting-thre…

Az nem a nyelv hibája, ha nem érted, mi az, hogy async művelet. Meg azt, hogy hogyan lehet egyszálas runtimeban (a JS az egyszálas) async művelet, threadek nélkül.

Másrészt ma már (igazából Java 5 óta) Javaban nem igazán írunk le olyat, hogy new Thread, meg nem subclassolunk Threadet. Callable, Runnable és executorok.

Másrészt async kódból mindig lehet csinálni sync kódot, de ez megfordítva nem igaz.

A Javasat csak odadobtam elolvasas nelkul, azt hittem a Runnable van ott leirva. ;)

Async kod meg lehet sync tok olvashatoan es legtobbek altal konnyen felfoghatoan a legtobb nyelvben. De nem JS-ben. Tobb olyan barommal talalkoztam, aki hatarozottan allitotta hogy ne SQL-ezz JS-ben, mert arra a MongoDB valo, egymas utan futtatni az SQL utasitasokat ott pedig sose lesz szep. En pedig raszantam 3 hetet hogy hogy lenne a legszebb pl egy SQL tranzakciot implementalni NodeJS-be, es arra jutottam, hogy tobb mukodo megoldast implementalva meg kellett allapitanom: "ezt nem tudom konnyen olvashatora megcsinalni". Mas nyelven ilyen kudarc sose ert, pedig hasznalok parat, obj-c es swift async protocol delegate-jeivel meg Android Asynctaskjaval az elen, amik konkretan kurva jol kitalalt async es event megoldasok.