Aktuálně: Tak nám hackli GitHub…

Krátce poté, co zde vyšel seriál Jdu hacknout váš server, máme další článek na stejné téma. Tentokrát ale „žhavě aktuální“ o tom, jak jeden ruský programátor hacknul github (a poukázal na chybu v Rails, která se projevuje i na dalších serverech). A přitom stačilo, aby tým vývojářů Rails naslouchal…
Nálepky:
Vše začalo v pátek, kdy @homakov vytvořil issue request, ve kterém navrhoval změnit standardní nastavení Active Record v Rails tak, aby vyžadoval od programátorů whitelist na Mass Assignmentu.
Jedná se přesně o to, co se řeší v PHP už velice dlouho – kontrola dat, které dostává skript od uživatelů ve formuláři. V Active Recordu (= „Doctrine pro Ruby“) můžete nastavit všechny parametry jednou metodou. V podstatě jde o to, že v rámci Ruby on Rails většina programátorů dělá v controlleru:
# save user data Users.find(params[:id]).update_attributes(params[:user])
Pokud v rámci modelu Users nemáte nastaveno attr_accesible
, pak můžete nastavit jakýkoliv parametr modelu, včetně (například) administrator
.
Homakov reportoval issue, pohádal se s vedoucími developery Rails, a ti se nechali slyšet, že výhody standardního nastavení (kdy attr_accessible
není použito) vyvažují jakékoli nevýhody plynoucí z vynucení. Homakov byl přesvědčen, že problém má ve skutečnosti obludné rozměry, a začal si hrát s Githubem, který je nad Ruby on Rails postaven.
V rámci přesvědčování Rails dev týmu vytvořil issue I’m bender from future, který byl založen v roce 3012. Udělal to jednoduše – ve firebugu přidal <input type="hidden" name="created" />
a, ke svému vlastnímu překvapení, zjistil, že to funguje. Proof of concept zaslal Githubu v pátek, a GitHub chybu ihned opravil.
Rails tým reagoval slovy „good one.“
Homakov pokračoval v experimentech. Napsal komentář jménem DHH (jeden z hlavních vývojářů Rails.) To byla docela legrace.
Potom mohl vymazat obsah jakéhokoliv příspěvku. To už nebyla sranda, to bylo docela nebezpečné.
Pak zjistil, že může přiřadit svůj SSH klíč k jakémukoliv projektu. Jackpot.
Rails tým stále ignoroval Homakovův požadavek i informace o závažnosti problému. Nakonec se tedy rozhodl, že udělá push do master větve ruby on rails. Nic nerozbil, jenom přidal jeden soubor a problém poté reportoval Githubu.
O github mu nešlo – šlo mu o standardní politiku Rails, která vede k bezpečnostním dírám. Github vydal roztomilé prohlášení, kde se rozplývají nad tím, jak problém proaktivně zjistili, smazali dotyčný SSH klíč a suspendovali účet tomu, kdo na exploit přišel.
Dozvuky
Rails komunita se okamžitě rozdělila na dva tábory – jeden tleskal, druhý Homakova odsuzoval. Faktem je, že i když mohl přistupovat k jakýmkoliv repozitářům, jediné, co udělal, bylo, že commitoval do rails/master
. Mohl se přitom dostat k repositories, která jsou private, mohl tímto způsobem dělat s celým githubem, co by se mu zlíbilo. Na druhou stranu problém „prachsprostě využil“ a neoznámil jej nejdříve Githubu. Osobně si myslím, že udělal správnou věc – kdyby ho oznámil, díra v Rails aplikacích leží dodnes.
Hodinu po zmíněném pushi do masteru upravil Rails tým generátory tak, že je standardní politika restriktivní. Veškeré argumenty, které celou dobu stavěli proti, najednou ignorovali.
Dosah celé věci je mnohem závažnější, i když není vidět na první pohled – takto způsobenou díru obsahuje Posterous, Scribd, Speakerdeck a řada dalších služeb. A jedná se i o firmy, které mají velké finanční zázemí a mají dobré vývojáře! Popadaných webů bude v tomto týdnu asi nemálo. Máme se na co těšit, zatím je to docela show.
Nejsmutnější na celé věci je, že o chybě se ví minimálně od května 2007. A o celých pět let později to využije devatenáctiletý mladík k tomu, aby dokázal Rails týmu, že se jedná o skutečný problém.
Oprava bezpečnostní díry
Nejsem Ruby developer, a tak vás odkážu na tento článek. V podstatě by mělo do všech modelů stačit doplnit parametr attr_accessible
, jak je vysvětleno v dokumentaci. Pokud jste o něm nikdy neslyšeli, nechtěl bych teď být ve vaší kůži.
pekne :D
Zajímavé mi na tomhle přijde nezvládnutí ega vývojářů githubu. Možná se pletu, ale celé to na mě působí dojmem, že si vývojři řekli : „Přece nám tady nebude radit nějaký usmrkaný klučina s bezpečností“, protože jinak si neumim vysvětlit, že ten problém nechali dojít až do stavu commitovaní do hlavní větvě railsů…
Všeobecně je celá kauza nasáklá egoismem. O problému se střídavě mluvilo od roku 2007, a vyjádření Rails devs bylo „not a rails problem.“ Argumentovali tím, že je pak rails pro nováčky jednodušší.
Tohle opomenutí vedlo k tomu, že spousta „nováčků“ v githubu, posterous atp. imho vůbec netušilo, že vůbec nějaké attr_accessible je. A máme z toho takovouhle bombu.
Nedivím se, že to rails pushnul. Na jeho místě bych byl tak moc překvapen, že si nekontrolují oprávnění při ukládání SSH klíčů (!!), že bych to prostě prubnul. A vývojáři githubu, i když dostali několik reportů na tento konkrétní problém, si neprošli to nejzásadnější s tím, „že tam určitě problém nebude.“
Fix v rails je nakonec jen pro nové aplikace, a ještě k tomu jde vypnout jedním (!) řádkem v configu globálně. Trochu se obávám, že teď si spousta vývojářů své aplikace patchne, ale za pět let máme stejný problém – se službou, která bude tehdy trendy.
Ono kde co nese označení „not a rails problem“. Rails devs jsou z větší části banda idiotů, s kterejma se nedá absolutně mluvit.
Až tak útočný bych nebyl, ale (naivně) jsem si myslel, že vývojáři na jejich úrovni, už nebudou mít problém přiznat chybu, opravit ji a nebo se o ni normálně pobavit…
:-) no kdo to nezkusil, tak by asi tak utocny nebyl, to je fakt. a o jake urovni se bavime? kdyz si proctete na githubu nahlasene chyby a reakce na ne od rails vyvojaru, tak je to uz jasny. opravdu dobrych je mezi nima jen par.
Pěkné :-)
Jak to vlastně funguje? Definuji ve frameworku formulář, kde vyjmenuji atributy a všechno kolem se udělá samo. Nebo na straně serveru přijímám vstup z libovolného formuláře (který si třeba napíšu sám, tudíž framework neví, jaké atributy tam chci mít) a na straně serveru jen nechám nasypat POST parametry do vlastností objektu?
V prvním případě je to chyba frameworku, protože mohl vědět, které atributy tam chci – v druhém případě je to chyba aplikace a framework je v tom nevinně, protože nemohl tušit, které atributy vývojář chce nastavit a které ne.
Celý problém je druhá varianta – vývojáři (většina devs –> nemyslím, že github má zrovna newbie programátory..) prostě vezmou celý POST a narvou ho do objektu. Konstrukce z jejich pohledu je taková, že mám:
– input name=“user[name]“
– input name=“user[surname]“
atp. No a pak když ho chci uložit, tak můžu použít právě ono hromadné přiřazení – a drtivá většina to tak skutečně dělá. Rails devs si toho byli vědomi ve chvíli, kdy funkci psali. Jsou dvě možnosti jak si aplikaci zabezpečit:
– attr_accessible – whitelist
– attr_restricted – blacklist
Funkce hromadného přiřazení se pak dívá do white/black listu a podle toho se chová. Nicméně základní problém, na který chtěl právě Homakov upozornit, je ten, že standartně není nastaveno ani jedno. Každý model je defaultně nezabezpečený s tím, „že si ho musíte zabezpečit sami.“
Což o to. Hlavně si to ale musíte pamatovat.
Ve chvíli, kdy funkci všichni používají (bez ohledu na fakt, jestli je k tomu určena či nikoli) k načítání dat z POSTu, pak musí být defaultní white/black list implementován s tím, že programátor MUSÍ vědět, co dělá, když její chování nastavuje. Tomu osobně říkám restricted-by-default. A to je to, co chtěl Homakov.
A nakonec věděl proč. Hoši z Githubu, Posterous, Scribd a jiných si své modely nezabezpečili. Pokud to neudělali oni – v případě githubu u software, jehož licence začíná na 5000 dolarech – kolik jiných rails devs má své aplikace zabezpečeno? Imho to bude tak do 10%.
Např. v Javě (JSP) jde udělat stejná věc, ale nemyslím si, že by to byla chyba – tohle je podle mého odpovědnost programátora aplikace. Programátor si přece může vyrobit DTOčko, do kterého půjdou nastavovat jen vybrané atributy, nebo je může nastavovat individuálně místo hromadně. Ale když místo toho zavolá funkci „nastav všechny atributy podle POST parametrů“, tak si framework myslí, že to je přesně to, co programátor chce. Je to přece stejné, jako když zavolám funkci/metodu na smazání entity – framework/jazyk/platforma, taky nemůže tušit, že mazat ve skutečnosti nechci a volám tu funkci omylem.
Další věc je, že aplikace nebývají často jen pouhým rozhraním k databázi a mají nějakou logiku – a součástí ní je třeba i to, kteří uživatelé/role mohou nastavovat které atributy kterým entitám. Některé atributy půjdou nastavovat třeba jen v určité hodiny, nebo při připojení z určité sítě nebo na základě jiných atributů (např. článku, který neprošel korekturou nepůjde nastavit stav na „vydáno“) atd. atd. Takže tam stejně nějaký „filtr“ vytvořený programátorem být musí. Je fajn, když tahle pravidla jdou vyjádřit deklarativně. Ale tak jako tak je to odpovědnost programátora. Přijde mi, že se spousta lidí nechalo unést tím, jak snadno se dá dělat software, aniž by četli dokumentaci nebo přemýšleli, co která funkce dělá – a takhle se jim to ošklivě vymstilo.
Mna to prekvapilo aj tak. Yii framework v PHP, cista kopia RoR touto chybou out-of-box netrpi. Plati tam jednoduche pravidlo – field bez validatora (aj prachobycjany „required“) nie je mozne nastavovat masivnym priradenim.
Scaffolder validacne pravidla pekne do modelov pripravi z definicie tabuliek. Formulare si musi programator postrazit sam. Developer sa tak od zaciatku uci dobrym navykom.
Maly priklad – z beznej tabulky, povedzme ‚articles‘ sa nastavia validacne pravidla ‚required‘ pre stlpce s NOT NULL. Stlpec s AUTO INCREMENT sa ale vynecha – nie je mozne z vonka zmenit ID entity. Jasne, takato jednoducha logika nezabrani priradit rolu ‚admin‘ ak ma ten field validator. To uz si musi postrazit logika aplikacie.
Protože Xue u toho přemejšlí. A taky sleduje ostatní frameworky (nejen PHP) a snaží se vyhnout jejich chybám. Asiat no :D
Přesně to mě napadlo, že tenhle problém elegantně řeší nějaký view model, který bude mapovat a bindovat jen ty property, které chci. Je to sice práce navíc, ale osobně se mi to u .net mvc mnohokrát oplatilo.
P.S. K čemu bude dobré, když whitelist/blacklist bude výchozí chování?
IMHO více méně k ničemu, protože tím akorát omezím aktualizace atributů, které se nikdy nemění – např. primárního klíče nebo okamžiku vytvoření entity. Ale co všechny ty ostatní atributy? U nich totiž nemůžeme zakázat aktualizace, protože někdy je upravovat potřebujeme – např. administrátor může měnit role jiných uživatelů a jejich e-maily, běžný uživatel může měnit svůj e-mail ale ne jiných uživatelů atd.
Může ten whitelist/blacklist být vázaný (alespoň) na role aktuálně přihlášeného uživatele? Pokud ne, tak je to na nic. Ne, tohle není řešení a stejně tam musí někde ta logika (kdo co může) být zapsaná.
Ale co všechny ty ostatní atributy? U nich totiž nemůžeme zakázat aktualizace, protože někdy je upravovat potřebujeme – např. administrátor může měnit role jiných uživatelů a jejich e-maily, běžný uživatel může měnit svůj e-mail ale ne jiných uživatelů atd.
No, to jistě. Ale od toho tam jsou role. :-) Např. ten administrátor. :-)
jj, to už jsem taky zjistil, více viz tehle komentář.
Good one :-)
Kaju se, přesně tu samou chybu mám taky, shame on me…
prvý článok na zadrojáku ktorý som prečítal od začiatku do konca :P palec hore
Přesně stejná věc je i ve frameworku grails, akorát se to tam jmenuje jinak – attribut „.properties“.
DHH k tématu poslal: https://gist.github.com/1975644
Celkem rozumím tomu, proč to řeší v controlleru a ne v modelu.
Z pohledu IT člověka se reakce GitHubu může zdát dětinská, ale z pohledu marketingu a legislativy neměli moc na výběr. Evidentně dlouhou dobu bagatelizovali problém a najednu jim někdo ukázal, že problém existuje. V té chvíli musí provozovatel udělat dvě věci – chybu promptně opravit a ukonejšit laickou veřejnost, že nešlo o vážný problém. A to konejšení laické veřejnosti je právě to zablokování účtu dotyčného a ještě větši bagatelizování ve smyslu „i kdyby snad někdo tu díru použil, my na to přijdeme a zjednáme nápravu“. Znalý člověk si sice poklepe na čelo, že tady logika hapruje, ale akcionář a zákazník si bude myslet „jo, těm nic neunikne“. Nejde tedy ani tak o projev uraženého ega, jako o snahu udržet si zdroj peněz. No a nebo, a to je můj osobní názor, jde o kombinaci obojího.
Tohle funguje presne do okamziku, kdy sedi na strane zakaznika managor, kterej nicemu nerozumi a nesleduje ani co se deje. Ovsem az si (i ten blbej managor) precte (trebas) zdejsi clanek, tak vyhodnoti tohle chovani jako velmi neduveryhodne a da od podobnyho partnera ruce pryc.
Delat chyby, je totiz normalni, ale nepriznat je, je vetsi pruser nez ta najvetsi chyba. Driv nebo pozdejs se to totiz stejne provali a pak to nekdo nalezite rozmazne.
„Delat chyby, je totiz normalni, ale nepriznat je, je vetsi pruser nez ta najvetsi chyba“
Tesat do kamene. Z mého pohledu měli tu chybu opravit, zveřejnit na svém blogu, jak staré projekty aktualizovat.
Nemyslim si, ze by byl GitHub pouzivan z vetsi casti prave „laickou verejnosti“… Spis bych rekl, ze laik o GitHub nezavadi, popripade je procento takovych uzivatelu mrzce nizke.
Tak to jsou v GitHub docela améři, míchat vnitřní atributy a ty co dostanou z formuláře, to se v php nedoporučovalo už před sto lety, klasickej příklad byl vždycky nastavení user_id na adnimistrátora :D
no, jo, je to o par let mladsi jazyk a chcou byt proti proudu, tak si musi hloupost svych „registerGlobals“ poznat sami, protoze zkusenosti jsou temer neprenosne…
Ruby i PHP jsou pro verejnost z roku 1995, Ruby vyvoj zacal o rok drive nez php
Wiki
http://cs.wikipedia.org/wiki/Ruby_(programovac%C3%AD_jazyk)
„Práce na něm započaly v roce 1993, první verze byla uveřejněna v roce 1995 „
http://cs.wikipedia.org/wiki/PHP
„Vše začalo v roce 1994“
Až na to že ten problém není v Ruby ale ve frameworku Ruby on Rails … a ten měl první release v roce 2004.
To že RoR chybí nějaká vlastnost ještě neznemená, že to programátora nepraští do očí a něco si tam nedobastlí, aby to neměl děravé jak cedník, proto mne překvapuje, že to exprti na github ignorovali.
Ono to ale není tak že by „RoR“ nějaká vlastnost chyběla. Možnost filtrovat fieldy které lze přes mass assignment modifikovat tam je (whitelisting i blacklisting), akorát je to holt v defaultu vypnuté protože RoR vývojáři razí myšlenku že to v defaultní instalaci má být použitelné i pro naprosté začátečníky a tímhle by se to komplikovalo …
Ano, máte pravdu že programátoři githubu (a dalšího asi milionu projektů které RoR používají) to měli změnit a nastavit. Současně to pěkně ilustruje že bezpečnostní princip „defaultně zakázat, povolit jen vyjmenované“ má svůj smysl.
Z té myšlenky „že to v defaultní instalaci má být použitelné i pro naprosté začátečníky a tímhle by se to komplikovalo“ mě úplně jímá hrůza. Použitelnost pro naprosté začátečníky je skvělá věc, ale za žádných okolností to nesmí být na úkor bezpečnosti.
Proč by weby začátečníků měly být děravé? Protože jsou začátečníci? Právě naopak, začátečník se v bezpečnosti neorientuje a na framework spoléhá. Tímhle ho ale podvedl.
konec dobrý, všechno dobré :)
Pochopili, změnili… osobně jsem rád, protože když jsem to při prozkoumávání RoR sám zjistil, tak jsem se tomuto přístupu hodně divil.
Chapu spravne, ze clovek ktery vymyslel v sequelu metodu set_fields byl genius protoze vyvojare Railsu tohle nenapadlo pet let? ( http://sequel.rubyforge.org/rdoc/classes/Sequel/Model/InstanceMethods.html#method-i-set_fields )
Ne. Nechápete to dobře. Jak už tady bylo zmiňované několikrát – vývojáře Railsu to pochopitelně napadlo. Jde jen o defaultní chování a jejich preference.
Jde o to, ze narozdil od uvedeneho attr_protected muze tahle funkce mit pri kazdem volani jine parametry.
zkratka „tak jak sem to udelal, je to nejlepsi a nikdo nema pravo mi do toho zvanit.“
V rámci přesvědčování Rails dev týmu vytvořil issue I'm bender from future, který byl založen v roce 3012. Udělal to jednoduše – ve firebugu přidal <input type="hidden" name="created" /> a, ke svému vlastnímu překvapení, zjistil, že to funguje. Proof of concept zaslal Githubu v pátek, a GitHub chybu ihned opravil.
Rok 3012?
„homakov opened this issue in 1001 years“
Ale pozitivní je, že počítali s tím, že někdo může zadat příspěvek v budoucnu – připraveni na všechno :-)
Presne, ked som skusal rails (cca 3 r. dozadu) tak v niektorom zo screencastov na toto poukazovali, a odvtedy si pamatam tuto nebezpecnu dieru avsak rails som nechal tak a ostal pri PHP (nie preto).
V zende je to riesene cez formulare. Naplnim si formular parametrami a tie (ak je validny) vytiahnem. Pritom formular vrati iba tie parametre, ktore su v nom definovane (moznost nastavit filtre na hodnoty). Ak je vo formulari select tak pri zadani hodnoty ktora v nom nie je formular vrati chybu atd.
http://railscasts.com/episodes/26-hackers-love-mass-assignment
Ryan vydal „revised“ verzi … http://railscasts.com/episodes/26-hackers-love-mass-assignment-revised