Internetam ir liela C/C++ problēma, un programmētāji netiek ar to galā

Kas ir kopīgs Heartbleed, WannaCry un miljonus dolāru izmaksājošām iPhone kļūdām?

Viena kļūda ietekmē iPhone, cita ietekmē Windows, trešā ietekmē Linux serverus. Pirmajā skatienā kļūdas izskatās nesaistītas, bet patiesībā visas trīs iespējamas ir padarījis kods, kas tika sarakstīts programmēšanas valodās, kuras pieļauj nedrošu atmiņas pielietošanu. Atļaujot šādas ievainojamības, C un C++ valodas sekmēja nebeidzamu virkni ar kritiskām drošības kļūdām daudzu gadu garumā.

Iedomājieties, ka jums ir programma ar 10 numuru sarakstu. Kam būtu jānotiek pēc vienpadsmitā numura pieprasīšanas? Lielākā daļa no mums teiktu, ka datoram jāizvada kļūda, un atmiņas drošā valodā (piemēram, Python vai Java) tā arī notiktu. Atmiņas nedrošā valodā dators mēģinās nolasīt vietu atmiņā, kur būtu jāatrodas vienpadsmitajam numuram, ja tas tur būtu. Dažreiz tas programmai liks avarēt, bet diezgan bieži tiks atgriezti citi dati, kuri tur atrodas lasīšanas brīdī, pat ja datiem nav nekāda sakara ar mūsu sarakstu. Šāda ievainojamība tiek saukta par bufera pārplūdi (buffer overflow) un tā ir viena no biežāk sastopamajām atmiņas nedrošības ievainojamībām. HeartBleed, kas ietekmēja 17 procentus no drošajiem web serveriem internetā, bija bufera pārplūdes ekspluatētājs. Tas atļāva nolasīt 60 kilobaitus pēc saraksta beigām, ieskaitot paroles un citus lietotāju datus.

Tas gan nav viss, C/C++ valodās ir arī citi atmiņas nedrošības ievainojamību veidi.

Vēl piemēri ir tipu apjukums (sajauc, kāda tipa dati atrodas noteiktā vietā atmiņā), lietošana pēc atbrīvošanas vai “use after free” (pielieto daļu atmiņas pēc paziņošanas operētājsistēmai, ka tā vairs netiks lietota), nepalaistas atmiņas pielietošana vai “use of uninitialized memory” (pielieto daļu atmiņas pirms programma tur ir rakstījusi datus). Šīs ir visbiežāk sastopamās atmiņas ievainojamības tādās populārās programmās kā Firefox, Chrome, Windows, Android, iOS. Ja paseko līdzi šajās programmās atrastajām drošības kļūdām, var redzēt, ka vairāk par pusi kļūdu ir saistītas ar nedrošu atmiņas izmantošanu. Vēl vairāk satrauc tas, ka augsta un kritiska līmeņa ievainojamības (tās, kuras hakerim var atļaut izpildīt kodu attālināti, saglabāt, novilkt, palaist jebkuru programmu lietotājam nemanot) gandrīz vienmēr rodas atmiņas nedrošības dēļ. Piemēram, Firefox programmētājs un drošības pētnieks Alekss Geinors (Alex Gaynor) pēdējā gada laikā populārajās atvērtā koda attēlu apstrādāšanas bibliotēkās ImageMagic un Graphicsmagic atrada 400 atmiņas nedrošības ievainojamības.

Ja šīs ievainojamības ir sastopamas tik bieži un rada tik lielus drošības draudus, un ir valodas, kurām nav tādu problēmu, kāpēc šīs nedrošās valodas vēl joprojām ir tik populāras? Pirmkārt, tagad ir pieejamas daudzas atmiņas drošas valodas, bet tā nav bijis vienmēr. C un C++ ir vairākas desmitgades vecas un ļoti populāras valodas. Otrkārt, zema līmeņa programmēšanai pielāgotas programmēšanas valodas ar atmiņas drošību, kuras varētu izmantot interna pārlūkprogrammu un operētājsistēmu programmēšanai, piemēram Rust un Swift, tikai tagad sāk kļūt populāras.

Liela problēma ir tajā, ka izvēloties valodu jaunam projektam, programmētāji izvēli izdara, visvairāk ņemot vērā komandai zināmās valodas, ātrdarbīgumu un bibliotēku ekosistēmu. Mazāka vērība tiek pievērsta valodu drošībai. Tas nozīmē, ka drošību uzsverošām valodām ir handikaps.

Turklāt daudzi no svarīgākajiem interneta drošības projektiem nav jauni, tie tika uzsākti jau pirms 10 vai vairāk gadiem. Piemēram, Linux, OpenSSL, Apache serveris ir vairāk nekā 20 gadus veci projekti. Šādu masīvu projektu pārrakstīšana jaunā valodā nevar notikt īstermiņā, tos ir jāmigrē pamazām. Tas nozīmē, ka migrācijas laikā atjauninājumus jāraksta divās valodās, kas būtiski palielina darba sarežģītību. Tas arī var prasīt lielas komandas pārkvalificēšanu, kas aizņem laiku un naudu.

Visbeidzot, lielākā problēma ir tajā, ka daudzi izstrādātāji nemaz nedomā, ka problēma eksistē. Daudzi programmu inženieri domā, ka problēma nav C/C++ valodās, kuras sekmē šīs kritiskās ievainojamības, bet gan citu programmētāju prasmē programmēt. Saskaņā ar šo teoriju, problēma nav tajā, ka 11. elementa iegūšanas mēģinājums no 10 elementu saraksta rada kritisku ievainojamību, bet gan tajā, ka kāds uzrakstījis kodu ar šādu funkciju, tajā, ka programmētājs nav pietiekami labs inženieris vai nav pietiekami disciplinēts. Citiem vārdiem sakot, tiek uzskatīts, ka problēma nav valodā, bet ka cilvēki vienkārši nemāk to lietot pietiekami labi.

Drošībai vajadzētu būt vienam no kritērijiem valodas izvēlē

Daudziem programmu izstrādātājiem šī pozīcija ir pārliecinoša, par spīti lielajam daudzumam pierādījumu par pretējo – šīs ievainojamības ir visuresošas, ietekmē pat uzņēmumus ar lieliem datorsistēmu drošības budžetiem un pasaules talantīgākajiem programmētājiem. Daudz tiek diskutēts par iepriekš minētajām lietām un kā varētu uzlabot atmiņas pielietošanā drošu valodu mācīšanu, bet pēc milzīgā daudzuma ievainojamību atklāšanas, kādu nav projektos ar labākām programmēšanas valodām, ir skaidrs, ka pūles un centieni neradīt daudz kļūdu nav veiksmīga stratēģija.

Tomēr ir arī nedaudz labu ziņu. Ne visi ignorē šo problēmu. Rust (galvenais sponsors ir Mozilla) ir salīdzinoši jauna programmēšanas valoda, kuras mērķis ir aizstāt C, C++ valodas un būt drošai atmiņas lietošanā, un izvairīties no iepriekš minētajām atmiņas ievainojamībām. Rust pamazām gūst arvien vairāk popularitātes, šobrīd valodu lieto Mozilla, Google, Dropbox, Facebook. Izskatās, ka daudzi cilvēki sāk meklēt sistēmiskus risinājumus atmiņas nedrošības problēmai. Arī jaunā Apple Swift valoda nodrošina atmiņas drošību, iepriekšējā Objective-C nenodrošināja.

Ir vairākas lietas, kuras var darīt, lai paātrinātu risinājumu atrašanu šai drošības katastrofai, kas ir atmiņas nedrošība. Vispirms var noteikt, cik daudz zaudējumu rada atmiņas nedrošība. CVE projekts, nozares datubāze ar zināmām ievainojamībām, varētu izsekot, cik ievainojamības rodas atmiņas pielietošanas nedrošības dēļ un vai atmiņas drošā valodā notiktu tāda kļūda. Tas palīdzētu uzzināt, kuri projekti gūtu visvairāk no programmēšanas valodas maiņas.

Otrkārt, vajadzētu izpētīt, kā labāk migrēt esošos lielos projektus uz valodām ar atmiņas drošību. Šobrīd ideja par tāda liela projekta kā Linux migrācija uz citu valodu šķiet gandrīz neiedomājama.

Treškārt, ir vajadzīgs mainīt programmēšanas kultūru. Mācoties programmēt, skolā tiek sagaidīts, ka programma bieži avarēs. Bet netiek runāts par to, ka nozīmīga daļa no tām avārijām ir potenciāla drošības ievainojamība. Izpratnes trūkums par sakarību starp avārijām un drošības problēmām jau no programmētāja karjeras sākuma norāda uz to, ka drošība nav primāra programmēšanā un tās mācīšanā. Kad tiek veidots jauns projekts, vienam no programmēšanas valodas izvēles kritērijiem vajadzētu būt drošībai.

Valodas bez atmiņas drošības šobrīd ir liela problēma nozarē. Bet nevajadzētu būt tā, ka katrā Windows un Firefox atjauninājumā tiek labotas daudzas izbēgamas drošības ievainojamības. Jāizbeidz pret katru drošības ievainojamības atklāšanas gadījumu izturēties kā pret izolētu notikumu, vajadzētu pret to izturēties kā pret dziļi iesakņojušos sistēmisku problēmu, kāda tā ir. Tālāk vajadzētu izpētīt, kā izveidot labākus rīkus, kas palīdzēs tikt galā ar problēmu. Ja tas notiktu, uzlabotos datoru drošība visiem lietotājiem, HeartBleed, WannaCry un līdzīgas ievainojamības parādītos daudz retāk.

Avots: motherboard.vice.com

Dalies :

Facebook
Twitter
LinkedIn
Pinterest

4 Responses

  1. Tieši tāpēc es balsoju par Rust valodu! Nekādu iziešanu ārpus masīva robežām, nekādu null pointeru danglingi un nekādi lieki datu objekti nepiesārņo atmiņu, kad to mainīgo dzīves cikls ir izbeidzies.

  2. C vienkārši ir zemāka līmeņa valoda. Drošības ieviešana ir tavās rokās. Nav nekādu aizkavējumu vai resursu atbrīvošanas mehānismu. Protams, ir grūtāk tādā rakstīt, bet var būt nepieciešams, kad ātrumam liela nozīme vai tuvāk konkrētam dzelzim jātiek.

    1. Tur jau tā lieta, ka Rust gadījumā tie pasākumi neko no ātrdarbības un resursiem vairāk nepaņem. Viss tiek apzināts jau kompilācijas laikā (kompilātors vienkārši neļauj tev izpildīt tādas neķītrības, kādas vari atļauties citās valodās, līdz ar to, tas strikti kontrolē resursu izveidi un to iznīcināšanas kārtību). Izņēmums ir masīvu (un citu sekvenču datu) indeksu čekošana runtimā lai tas neiziet ārpus masīva robežām. Bet tieši to pašu tu dabūn C valodā, tikai ar to atšķirību, ka C tas tev pašam jākodē ar rokām.
      Vienkārš izklāsts par Rust https://medium.com/paritytech/why-rust-846fd3320d3f

Atbildēt

Jaunākie apskati
Tev varētu interesēt