Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Գրեթե 9 տարի առաջ Cloudflare-ը փոքր ընկերություն էր, և ես դրա համար չէի աշխատում, ես պարզապես հաճախորդ էի: Cloudflare-ը գործարկելուց մեկ ամիս անց ես ծանուցում ստացա, որ իմ կայքը jgc.orgDNS-ը կարծես թե չի աշխատում: Cloudflare-ը փոփոխություն է կատարել Արձանագրության բուֆերներ, և եղել է կոտրված DNS:

Ես անմիջապես գրեցի Մեթյու Փրինսին «Ո՞ւր է իմ DNS-ը» վերնագրով, և նա ետ ուղարկեց երկար պատասխան՝ լի տեխնիկական մանրամասներով (նամակագրությունն ամբողջությամբ կարդացեք այստեղ), ինչին ես պատասխանեցի.

Ջոն Գրեհեմ-Քամինգից
Ամսաթիվ՝ հոկտեմբերի 7, 2010, 9:14
Թեմա՝ Re: Որտե՞ղ է իմ DNS-ը:
Ում՝ Մեթյու Փրինս

Լավ զեկույց, շնորհակալություն: Եթե ​​խնդիրներ լինեն, անպայման կզանգեմ։ Հավանաբար, արժե այս մասին գրառում գրել, երբ հավաքեք ամբողջ տեխնիկական տեղեկատվությունը: Կարծում եմ՝ մարդիկ կվայելեն բաց և անկեղծ պատմությունը: Հատկապես, եթե դրան կցեք գրաֆիկներ՝ ցույց տալու համար, թե ինչպես է երթևեկությունն աճել գործարկումից հետո:

Ես լավ մոնիտորինգ ունեմ իմ կայքում, և ամեն ձախողման մասին SMS եմ ստանում։ Դիտարկումը ցույց է տալիս, որ խափանումը տեղի է ունեցել 13:03:07-ից 14:04:12-ը: Թեստերը կատարվում են յուրաքանչյուր հինգ րոպեն մեկ։

Համոզված եմ, որ դուք կհասկանաք դա: Համոզվա՞ծ եք, որ Եվրոպայում ձեր սեփական անձի կարիքը չունեք: 🙂

Եվ նա պատասխանեց.

From: Matthew Prince
Ամսաթիվ՝ հոկտեմբերի 7, 2010, 9:57
Թեմա՝ Re: Որտե՞ղ է իմ DNS-ը:
Ում՝ Ջոն Գրեհեմ-Քամինգ

Շնորհակալություն. Բոլոր գրողներին արձագանքեցինք. Ես հիմա գնում եմ գրասենյակ և ինչ-որ բան կգրենք բլոգում կամ մեր հայտարարությունների տախտակում պաշտոնական գրառում կկպցնենք: Լիովին համաձայն եմ, ազնվությունն ամեն ինչ է։

Այժմ Cloudflare-ը իսկապես մեծ ընկերություն է, ես աշխատում եմ նրա համար, և հիմա պետք է բաց գրեմ մեր սխալի, դրա հետևանքների և մեր գործողությունների մասին։

Հուլիսի 2-ի իրադարձությունները

Հուլիսի 2-ին մենք շրջանառության մեջ դրեցինք նոր կանոն WAF-ների Կառավարվող կանոններում, ինչի շնորհիվ CPU-ի ռեսուրսները սպառվում էին Cloudflare ցանցի յուրաքանչյուր պրոցեսորի միջուկի վրա, որը մշակում է HTTP/HTTPS տրաֆիկ ամբողջ աշխարհում: Մենք մշտապես բարելավում ենք WAF-ների կառավարվող կանոնները՝ ի պատասխան նոր խոցելիության և սպառնալիքների: Մայիսին, օրինակ, շտապեցինք ավելացնել կանոնSharePoint-ում լուրջ խոցելիությունից պաշտպանվելու համար: Մեր WAF-ի ամբողջ իմաստը կանոններն արագ և գլոբալ տեղակայելու ունակությունն է:

Ցավոք, անցյալ հինգշաբթի թարմացումը պարունակում էր կանոնավոր արտահայտություն, որը վատնում էր չափազանց շատ HTTP/HTTPS պրոցեսորի ռեսուրսներ հետքայլելու համար: Արդյունքում տուժել են մեր հիմնական պրոքսի, CDN և WAF գործառույթները: Գրաֆիկը ցույց է տալիս, որ HTTP/HTTPS տրաֆիկի սպասարկման պրոցեսորային ռեսուրսները հասնում են գրեթե 100% մեր ցանցի սերվերների վրա:

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին
Միջադեպի ժամանակ պրոցեսորի օգտագործումը ներկայության մեկ կետում

Արդյունքում, մեր հաճախորդները (և մեր հաճախորդների հաճախորդները) հայտնվեցին Cloudflare տիրույթներում 502 սխալի էջով: 502 սխալ է առաջացել Cloudflare-ի առջևի վեբ սերվերների կողմից, որոնք դեռևս ունեին անվճար միջուկներ, բայց չկարողացան շփվել HTTP/HTTPS տրաֆիկի հետ կարգավորող գործընթացների հետ:

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Մենք գիտենք, թե որքան անհարմարություններ են սա պատճառել մեր հաճախորդներին: Մենք ահավոր ամաչում ենք։ Եվ այս ձախողումը մեզ խանգարեց արդյունավետորեն զբաղվել միջադեպով։

Եթե ​​դուք այս հաճախորդներից մեկն էիք, հավանաբար վախեցած, զայրացած և վրդովված էիք: Ավելին, մենք չենք ունեցել Ա գլոբալ խանգարումներ. CPU-ի բարձր սպառումը պայմանավորված էր WAF-ի մեկ կանոնով՝ վատ ձևակերպված կանոնավոր արտահայտությունով, որը հանգեցրեց չափից ավելի հետընթացի: Ահա մեղավոր արտահայտությունը. (?:(?:"|'|]|}||d|(?:nan|infinity|true|false|null|undefined|symbol|math)|`|-|+)+[)]*;?((?:s|-|~|!|{}||||+)*.*(?:.*=.*)))

Թեև սա ինքնին հետաքրքիր է (և ես դրա մասին ավելի մանրամասն կխոսեմ ստորև), Cloudflare ծառայությունն անջատված էր 27 րոպեով ոչ միայն վատ կանոնավոր արտահայտման պատճառով: Մեզնից որոշ ժամանակ պահանջվեց նկարագրելու իրադարձությունների հաջորդականությունը, որոնք հանգեցրին ձախողման, ուստի մենք դանդաղ արձագանքեցինք: Գրառման վերջում ես սովորական արտահայտությամբ կնկարագրեմ հետընթացը և կասեմ, թե ինչ անել դրա հետ:

Ինչ եղավ

Սկսենք հերթականությամբ։ Այստեղ բոլոր ժամանակները UTC-ով են:

Ժամը 13:42-ին firewall թիմի ինժեները փոքր փոփոխություն կատարեց հայտնաբերման կանոններում XSS օգտագործելով ավտոմատ գործընթաց: Ըստ այդմ, ստեղծվել է փոփոխության հայտի տոմս: Նման տոմսերը մենք կառավարում ենք Jira-ի միջոցով (սքրինշոթը՝ ստորև):

3 րոպե անց հայտնվեց PagerDuty-ի առաջին էջը, որը հայտնում էր WAF-ի հետ կապված խնդրի մասին։ Սա սինթետիկ թեստ էր, որը ստուգում է WAF-ների ֆունկցիոնալությունը (մենք ունենք հարյուրավոր նման) Cloudflare-ից դուրս՝ նորմալ աշխատանքը վերահսկելու համար: Դրան անմիջապես հաջորդեցին ծանուցումների էջեր Cloudflare-ի այլ վերջնական ծառայությունների թեստերի ձախողման, գլոբալ երթևեկության խնդիրների, 502 համատարած սխալների և աշխարհի տարբեր քաղաքներում մեր ներկայության կետերից (PoP) բազմաթիվ զեկույցների մասին, որոնք վկայում էին դրա բացակայության մասին: CPU ռեսուրսների.

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Ես ստացա այս ահազանգերից մի քանիսը, ներխուժելով դուրս եկա ժողովից և գնում էի սեղանի մոտ, երբ մեր լուծումների մշակման բաժնի ղեկավարն ասաց, որ մենք կորցրել ենք մեր տրաֆիկի 80%-ը: Ես վազեցի մեր SRE ինժեներների մոտ, ովքեր արդեն աշխատում էին խնդրի վրա: Սկզբում մտածեցինք, որ դա ինչ-որ անհայտ հարձակում է:

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Cloudflare SRE-ի ինժեներները ցրված են աշխարհով մեկ և շուրջօրյա վերահսկում են իրավիճակը: Սովորաբար, այս ծանուցումները ձեզ տեղեկացնում են սահմանափակ շրջանակի հատուկ տեղական խնդիրների մասին, հետևվում են ներքին վահանակների վրա և լուծվում են օրական մի քանի անգամ: Բայց այս էջերը և ծանուցումները ցույց տվեցին իսկապես լուրջ բան, և SRE ինժեներները անմիջապես հայտարարեցին P0 խստության մակարդակը և կապ հաստատեցին ղեկավարության և համակարգի ինժեներների հետ:

Մեր լոնդոնյան ինժեներներն այդ պահին գլխավոր դահլիճում դասախոսություն էին լսում։ Դասախոսությունը պետք է ընդհատվեր, բոլորը հավաքվեցին մեծ կոնֆերանսի սենյակում, և ավելի շատ մասնագետներ կանչվեցին։ Սա տիպիկ խնդիր չէր, որով SRE-ները կարող էին ինքնուրույն լուծել: Հրատապ էր ճիշտ մասնագետների ներգրավումը։

Ժամը 14:00-ին պարզեցինք, որ խնդիրը WAF-ի հետ է, և հարձակում չի եղել: Կատարման թիմը քաշեց պրոցեսորի տվյալները և պարզ դարձավ, որ մեղավորը WAF-ն էր: Մեկ այլ աշխատակից հաստատել է այս տեսությունը՝ օգտագործելով strace: Մեկ ուրիշը տեղեկամատյաններում տեսել է, որ WAF-ի հետ կապված խնդիր կա: Ժամը 14:02-ին ամբողջ թիմը եկավ ինձ մոտ, երբ առաջարկվեց օգտագործել գլոբալ սպանություն՝ Cloudflare-ում ներկառուցված մեխանիզմ, որն անջատում է մեկ բաղադրիչ ամբողջ աշխարհում:

Թե ինչպես մենք գլոբալ սպանություն կատարեցինք WAF-ի համար, այլ պատմություն է: Դա այնքան էլ պարզ չէ։ Մենք օգտագործում ենք մեր սեփական արտադրանքը, և քանի որ մեր ծառայությունը Մուտք չաշխատեց, մենք չկարողացանք նույնականացնել և մուտք գործել ներքին կառավարման վահանակ (երբ ամեն ինչ շտկվեց, մենք իմացանք, որ թիմի որոշ անդամներ կորցրել են մուտքը անվտանգության գործառույթի պատճառով, որն անջատում է հավատարմագրերը, եթե ներքին կառավարման վահանակը չի օգտագործվում երկար ժամանակ).

Եվ մենք չկարողացանք հասնել մեր ներքին ծառայություններին, ինչպիսիք են Jira-ն կամ build համակարգը: Մեզ անհրաժեշտ էր հաղթահարման մեխանիզմ, որը մենք հազվադեպ էինք օգտագործում (սա նույնպես պետք է մշակվի): Վերջապես, մի ​​ինժեների հաջողվեց անջատել WAF-ը 14:07-ին, իսկ 14:09-ին երթևեկության և պրոցեսորի մակարդակները ամենուր նորմալ էին: Cloudflare-ի մնացած պաշտպանական մեխանիզմները նորմալ աշխատեցին:

Հետո մենք ձեռնամուխ եղանք WAF-ի վերականգնմանը: Իրավիճակը սովորականից դուրս էր, ուստի մենք բացասական թեստեր անցկացրինք (ինքնիս հարց տալով, թե արդյոք փոփոխությունն իրոք խնդիրն էր) և դրական թեստեր (համոզվելով, որ հետդարձն աշխատում է) մեկ քաղաքում՝ օգտագործելով առանձին երթևեկություն՝ այնտեղից տեղափոխելով վճարող հաճախորդներին:

Ժամը 14:52-ին մենք համոզվեցինք, որ հասկացանք պատճառը և ուղղում արեցինք և նորից միացրինք WAF-ը։

Ինչպես է աշխատում Cloudflare-ը

Cloudflare-ն ունի ինժեներների թիմ, որը նվիրված է WAF-ների կանոնների կառավարմանը: Նրանք ձգտում են բարելավել հայտնաբերման տեմպերը, նվազեցնել կեղծ պոզիտիվները և արագ արձագանքել նոր սպառնալիքներին, երբ դրանք հայտնվում են: Վերջին 60 օրվա ընթացքում 476 փոփոխության հարցում է մշակվել WAF-ի կառավարվող կանոնների համար (միջինը յուրաքանչյուր 3 ժամը մեկ):

Այս կոնկրետ փոփոխությունը պետք է տեղակայվեր սիմուլյացիոն ռեժիմում, որտեղ իրական հաճախորդի տրաֆիկը անցնում է կանոնով, բայց ոչինչ արգելափակված չէ: Մենք օգտագործում ենք այս ռեժիմը՝ կանոնների արդյունավետությունը ստուգելու և կեղծ դրական և կեղծ բացասական ցուցանիշները չափելու համար: Բայց նույնիսկ սիմուլյացիայի ռեժիմում կանոնները պետք է իրականում կատարվեն, և այս դեպքում կանոնը պարունակում էր կանոնավոր արտահայտություն, որը սպառում էր չափազանց շատ պրոցեսորի ռեսուրսներ:

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Ինչպես տեսնում եք վերը նշված փոփոխության հարցումից, մենք ունենք տեղակայման պլան, հետադարձ պլան և հղում դեպի ներքին ստանդարտ գործառնական ընթացակարգ (SOP) այս տեսակի տեղակայման համար: Կանոնը փոխելու SOP-ը թույլ է տալիս այն հրապարակել ամբողջ աշխարհում: Իրականում, Cloudflare-ում ամեն ինչ բոլորովին այլ կերպ է արվում, և SOP-ը թելադրում է, որ մենք նախ ծրագրաշարը փորձարկելու և ներքին օգտագործման համար ուղարկենք ներկայության ներքին կետ (PoP) (որն օգտագործում են մեր աշխատակիցները), այնուհետև՝ փոքր թվով հաճախորդների: մեկուսացված վայր, այնուհետև մեծ թվով հաճախորդների, և միայն դրանից հետո ամբողջ աշխարհին:

Ահա թե ինչ տեսք ունի. Մենք օգտագործում ենք git-ը ներքին BitBucket-ի միջոցով: Փոփոխությունների վրա աշխատող ինժեներները ներկայացնում են կոդը, որը կառուցված է TeamCity-ին, և երբ build-ն անցնում է, վերանայողներ են նշանակվում: Ձգման հարցումը հաստատվելուց հետո կոդը հավաքվում է և մի շարք թեստեր են իրականացվում (կրկին):

Եթե ​​կառուցումը և փորձարկումները հաջողությամբ ավարտվեն, Jira-ում փոփոխության հարցում է ստեղծվում, և համապատասխան ղեկավարը կամ առաջատարը պետք է հաստատի փոփոխությունը: Հաստատումից հետո տեղակայումը տեղի է ունենում այսպես կոչված «PoP մենեջերիայում»՝ DOG, PIG և Կանարյան (շուն, խոզ և դեղձանիկ):

DOG PoP-ը Cloudflare PoP-ն է (ինչպես մեր քաղաքներից յուրաքանչյուրը), որն օգտագործվում է միայն Cloudflare-ի աշխատակիցների կողմից: Ներքին օգտագործման համար նախատեսված PoP-ը թույլ է տալիս լուծել խնդիրները, նախքան հաճախորդների տրաֆիկի հոսքը դեպի լուծում: Օգտակար բան.

Եթե ​​DOG թեստը հաջող է, կոդը տեղափոխվում է PIG (գվինեա խոզուկ) փուլ: Սա Cloudflare PoP-ն է, որտեղ հաճախորդների անվճար տրաֆիկի փոքր քանակությունը հոսում է նոր կոդով:
Եթե ​​ամեն ինչ լավ է, կոդը գնում է Canary: Մենք ունենք երեք Canary PoP-ներ աշխարհի տարբեր մասերում: Դրանցում վճարովի և անվճար հաճախորդների տրաֆիկը անցնում է նոր կոդով, և սա սխալների վերջին ստուգումն է։

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին
Ծրագրաշարի թողարկման գործընթացը Cloudflare-ում

Եթե ​​կոդը Canary-ում կարգին է, մենք թողարկում ենք այն: Բոլոր փուլերով անցնելը՝ DOG, PIG, Canary, ամբողջ աշխարհը, տևում է մի քանի ժամ կամ օր՝ կախված կոդի փոփոխությունից։ Շնորհիվ Cloudflare-ի ցանցի և հաճախորդների բազմազանության՝ մենք մանրակրկիտ փորձարկում ենք կոդը՝ նախքան այն գլոբալ հրապարակելը բոլոր հաճախորդների համար: Բայց WAF-ը հատուկ չի հետևում այս գործընթացին, քանի որ սպառնալիքներին պետք է արագ արձագանքել:

WAF-ի սպառնալիքները
Վերջին մի քանի տարիների ընթացքում ընդհանուր հավելվածներում սպառնալիքների զգալի աճ է գրանցվել: Դա պայմանավորված է ծրագրային ապահովման փորձարկման գործիքների ավելի մեծ հասանելիությամբ: Օրինակ, մենք վերջերս գրել ենք մշուշոտ).

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին
Source: https://cvedetails.com/

Շատ հաճախ ստեղծվում է հայեցակարգի ապացույց և անմիջապես հրապարակվում Github-ում, որպեսզի հավելվածը սպասարկող թիմերը կարողանան արագ փորձարկել այն և ապահովել, որ այն պատշաճ կերպով ապահովված է: Հետևաբար, Cloudflare-ին անհրաժեշտ է նոր հարձակումներին հնարավորինս արագ արձագանքելու հնարավորություն, որպեսզի հաճախորդները հնարավորություն ունենան շտկելու իրենց ծրագրաշարը:

Cloudflare-ի արագ արձագանքման հիանալի օրինակ է SharePoint-ի խոցելիության պաշտպանությունը մայիսին (Կարդալ այստեղ). Հայտարարությունների հրապարակումից գրեթե անմիջապես հետո մենք նկատեցինք հսկայական թվով փորձեր՝ օգտագործելու խոցելիությունը մեր հաճախորդների SharePoint-ի տեղադրումներում: Մեր տղաները մշտապես վերահսկում են նոր սպառնալիքները և կանոններ են գրում մեր հաճախորդներին պաշտպանելու համար:

Հինգշաբթի օրը խնդիր առաջացրած կանոնը պետք է պաշտպաներ միջկայքային սկրիպտավորումից (XSS): Նման հարձակումները նույնպես շատ հաճախակի են դարձել վերջին տարիներին։

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին
Source: https://cvedetails.com/

WAF-ի համար կառավարվող կանոնը փոխելու ստանդարտ ընթացակարգը շարունակական ինտեգրման (CI) թեստավորումն է մինչև գլոբալ տեղակայումը: Անցյալ հինգշաբթի մենք դա արեցինք և շարադրեցինք կանոնները: Ժամը 13:31-ին ինժեները փոփոխությամբ ներկայացրել է ձգման հաստատված հարցում:

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Ժամը 13:37 TeamCity-ն հավաքեց կանոնները, անցկացրեց թեստեր և թույլ տվեց: WAF թեստային փաթեթը ստուգում է WAF-ի հիմնական ֆունկցիոնալությունը և բաղկացած է մեծ թվով միավորի թեստերից առանձին գործառույթների համար: Միավոր փորձարկումներից հետո մենք փորձարկեցինք WAF-ի կանոնները՝ օգտագործելով հսկայական թվով HTTP հարցումներ: HTTP հարցումները ստուգում են, թե որ հարցումները պետք է արգելափակվեն WAF-ի կողմից (հարձակումը կասեցնելու համար) և որոնք կարող են թույլատրվել (որպեսզի չարգելափակեն ամեն ինչ և խուսափեն կեղծ պոզիտիվներից): Բայց մենք չենք փորձարկել CPU-ի չափից ավելի օգտագործումը, և WAF-ի նախորդ կառուցումների տեղեկամատյանների ուսումնասիրությունը ցույց է տալիս, որ կանոնների թեստի կատարման ժամանակը չի ավելացել, և դժվար էր կասկածել, որ բավարար ռեսուրսներ չեն լինի:

Թեստերն անցան, և TeamCity-ն սկսեց ավտոմատ կերպով տեղակայել փոփոխությունը ժամը 13:42-ին:

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Սնդիկ

WAF-ի կանոնները կենտրոնանում են սպառնալիքների անհապաղ վերացման վրա, ուստի մենք դրանք տեղակայում ենք՝ օգտագործելով Quicksilver-ի բաշխված բանալի-արժեքի պահեստը, որը գլոբալ փոփոխությունները տարածում է վայրկյանների ընթացքում: Մեր բոլոր հաճախորդներն օգտագործում են այս տեխնոլոգիան, երբ նրանք փոխում են կոնֆիգուրացիան վահանակում կամ API-ի միջոցով, և դրա շնորհիվ է, որ մենք արձագանքում ենք փոփոխություններին կայծակնային արագությամբ:

Մենք շատ չենք խոսել Quicksilver-ի մասին: Նախկինում մենք օգտագործում էինք Կիոտոյի մագնատ որպես գլոբալ բաշխված առանցքային արժեք ունեցող խանութ, սակայն դրա հետ կապված գործառնական խնդիրներ կային, և մենք գրեցինք մեր սեփական խանութը, որը կրկնօրինակվել է ավելի քան 180 քաղաքներում: Այժմ մենք օգտագործում ենք Quicksilver-ը՝ հաճախորդներին կոնֆիգուրացիայի փոփոխությունները մղելու, WAF կանոնները թարմացնելու և հաճախորդների կողմից գրված JavaScript կոդը Cloudflare Workers-ին բաժանելու համար:

Ընդամենը մի քանի վայրկյան է տևում վահանակի վրա կոճակը սեղմելուց կամ API-ին զանգահարելուց մինչև ամբողջ աշխարհում կազմաձևման փոփոխություն կատարելը: Հաճախորդները հավանեցին տեղադրման այս արագությունը: Եվ Workers-ը նրանց տալիս է գրեթե ակնթարթային գլոբալ ծրագրային ապահովման տեղակայում: Միջին հաշվով, Quicksilver-ը մեկ վայրկյանում տարածում է մոտ 350 փոփոխություն:

Իսկ Quicksilver-ը շատ արագ է: Միջին հաշվով, մենք հասել ենք 99-րդ ցենտիլին՝ 2,29 վայրկյան՝ աշխարհի բոլոր համակարգիչների վրա փոփոխություններ տարածելու համար: Արագությունը սովորաբար լավ բան է: Ի վերջո, երբ դուք միացնում եք գործառույթը կամ մաքրում եք քեշը, դա տեղի է ունենում գրեթե ակնթարթորեն և ամենուր: Կոդ ուղարկելը Cloudflare Workers-ի միջոցով կատարվում է նույն արագությամբ: Cloudflare-ն իր հաճախորդներին խոստանում է արագ թարմացումներ ճիշտ ժամանակին:

Բայց այս դեպքում արագությունը դաժան կատակ խաղաց մեզ հետ, և ամենուր կանոնները փոխվեցին վայրկյանների ընթացքում։ Դուք կարող եք նկատել, որ WAF կոդը օգտագործում է Lua: Cloudflare-ը լայնորեն օգտագործում է Lua-ն արտադրության և մանրամասների մեջ Լուան WAF-ում մենք արդեն քննարկվել է. Lua WAF-ն օգտագործում է PCRE ներսից և կիրառում է հետընթաց՝ համապատասխանեցնելու համար: Այն չունի վերահսկողությունից դուրս եկող արտահայտություններից պաշտպանվելու մեխանիզմներ։ Ստորև ես ավելի շատ կխոսեմ այս և այն մասին, թե ինչ ենք մենք անում դրա վերաբերյալ:

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Մինչ կանոնների գործարկումը, ամեն ինչ հարթ էր ընթանում. ձգման հարցումը ստեղծվեց և հաստատվեց, CI/CD խողովակաշարը հավաքեց և փորձարկեց կոդը, փոփոխության հարցումը ներկայացվեց SOP-ի համաձայն, որը կարգավորում է տեղակայումը և հետադարձ կապը, և տեղակայումն ավարտվեց:

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին
Cloudflare WAF-ի տեղակայման գործընթաց

Ինչ որ բան այնպես չգնաց
Ինչպես ասացի, մենք ամեն շաբաթ գործարկում ենք տասնյակ նոր WAF կանոններ, և մենք ունենք բազմաթիվ համակարգեր՝ պաշտպանվելու նման տեղակայման բացասական հետևանքներից: Իսկ երբ ինչ-որ բան սխալ է լինում, սովորաբար դա միանգամից մի քանի հանգամանքների համակցություն է: Եթե ​​գտնում եք միայն մեկ պատճառ, սա, իհարկե, հուսադրող է, բայց միշտ չէ, որ ճիշտ է։ Սրանք են այն պատճառները, որոնք միասին հանգեցրել են մեր HTTP/HTTPS ծառայության ձախողմանը:

  1. Մի ինժեներ գրել է սովորական արտահայտություն, որը կարող է հանգեցնել չափազանցության հետընթաց.
  2. Մի առանձնահատկություն, որը կարող էր կանխել կանոնավոր արտահայտությունը չափազանց մեծ պրոցեսորի վատնումից, սխալմամբ հեռացվեց WAF-ի վերամշակման ժամանակ մի քանի շաբաթ առաջ. վերամշակումն անհրաժեշտ էր, որպեսզի WAF-ն ավելի քիչ ռեսուրսներ սպառի:
  3. Կանոնավոր արտահայտման շարժիչը բարդության երաշխիքներ չուներ:
  4. Փորձնական փաթեթը չկարողացավ հայտնաբերել պրոցեսորի չափազանց մեծ սպառումը:
  5. SOP-ը թույլ է տալիս կանոնների ոչ հրատապ փոփոխությունները գլոբալ տարածել առանց բազմաքայլ գործընթացի:
  6. Հետադարձ պլանը պահանջում էր երկու անգամ գործարկել ամբողջական WAF կառուցումը, ինչը երկար ժամանակ տևեց:
  7. Համաշխարհային երթևեկության խնդիրների մասին առաջին ահազանգը շատ ուշ է գործարկվել:
  8. Մենք որոշ ժամանակ պահանջեցինք կարգավիճակի էջը թարմացնելու համար:
  9. Մենք խնդիրներ ունեցանք համակարգեր մուտք գործելու հետ կապված անսարքության պատճառով, և շրջանցման կարգը լավ սահմանված չէր:
  10. SRE ինժեներները կորցրել են մուտքը որոշ համակարգեր, քանի որ նրանց հավատարմագրերի ժամկետը սպառվել է անվտանգության նկատառումներից ելնելով:
  11. Մեր հաճախորդները մուտք չունեին դեպի Cloudflare վահանակ կամ API, քանի որ նրանք անցնում են Cloudflare տարածաշրջանով:

Ինչ է փոխվել անցած հինգշաբթի օրվանից

Նախ, մենք ամբողջովին դադարեցրինք WAF-ի թողարկումների վրա աշխատանքը և անում ենք հետևյալը.

  1. Մենք կրկին ներդնում ենք CPU-ի գերօգտագործման պաշտպանությունը, որը մենք հանել ենք: (Պատրաստ է)
  2. Ձեռքով ստուգելով կառավարվող կանոնների բոլոր 3868 կանոնները, որպեսզի WAF-ը գտնի և շտկի չափից դուրս հետընթացի այլ հնարավոր դեպքերը: (Ստուգումն ավարտված է)
  3. Մենք ներառում ենք կատարողականի պրոֆիլավորում բոլոր կանոնների համար թեստային հավաքածուում: (Սպասվում է հուլիսի 19-ին)
  4. Անցում սովորական արտահայտման շարժիչին re2 կամ Ժանգոտվել - երկուսն էլ ապահովում են գործարկման ժամանակի երաշխիքներ: (Սպասվում է հուլիսի 31-ին)
  5. Մենք վերաշարադրում ենք SOP-ը, որպեսզի կանոնները գործարկեն փուլերով, ինչպես Cloudflare-ի մյուս ծրագրերը, բայց միևնույն ժամանակ հնարավորություն ունենանք շտապ գլոբալ տեղակայում, եթե հարձակումներն արդեն սկսվել են:
  6. Մենք մշակում ենք Cloudflare-ի վահանակը և API-ն Cloudflare տարածաշրջանից շտապ հեռացնելու հնարավորությունը:
  7. Էջի թարմացումների ավտոմատացում Cloudflare կարգավիճակը.

Երկարաժամկետ հեռանկարում մենք հեռանում ենք Lua WAF-ից, որը ես գրել եմ մի քանի տարի առաջ: WAF-ի տեղափոխում դեպի նոր firewall համակարգ. Այսպիսով, WAF-ն ավելի արագ կլինի և կստանա պաշտպանության լրացուցիչ մակարդակ:

Ամփոփում

Այս ձախողումը դժվարություններ առաջացրեց մեզ և մեր հաճախորդների համար: Մենք արագ գործեցինք իրավիճակը շտկելու համար և այժմ աշխատում ենք վթարի պատճառ դարձած գործընթացների թերությունների վրա, ինչպես նաև ավելի խորն ենք փորում, որպեսզի պաշտպանվենք ապագայում կանոնավոր արտահայտությունների հետ կապված հնարավոր խնդիրներից՝ նոր տեխնոլոգիաներ տեղափոխելիս:

Մենք շատ ամաչում ենք այս խափանումից և ներողություն ենք խնդրում մեր հաճախորդներից: Հուսով ենք, որ այս փոփոխությունները կապահովեն, որ նման բան այլևս չի կրկնվի:

Դիմում. Կանոնավոր արտահայտությունների հետքայլ

Հասկանալու համար, թե ինչպես է արտահայտությունը.

(?:(?:"|'|]|}||d
(?:nan|infinity|true|false|null|undefined|symbol|math)|`|-
|+)+[)]*;?((?:s|-|~|!|{}||||+)*.*(?:.*=.*)))

կերել է պրոցեսորի բոլոր ռեսուրսները, դուք պետք է մի փոքր իմանաք, թե ինչպես է աշխատում ստանդարտ սովորական արտահայտման շարժիչը: Խնդիրն այստեղ օրինաչափությունն է .*(?:.*=.*). (?: և համապատասխան ) չգրանցող խումբ է (այսինքն՝ փակագծերում տրված արտահայտությունը խմբավորված է որպես մեկ արտահայտություն)։

CPU-ի չափազանց մեծ սպառման համատեքստում այս օրինաչափությունը կարելի է բնութագրել այսպես .*.*=.*. Այս ձևով նախշը անհարկի բարդ է թվում: Բայց ավելի կարևոր է, որ իրական աշխարհում արտահայտությունները (ինչպես WAF կանոնների բարդ արտահայտությունները), որոնք շարժիչին խնդրում են համապատասխանեցնել մի հատված, որին հաջորդում է մեկ այլ հատված, կարող են հանգեցնել աղետալի հետընթացի: Եվ ահա թե ինչու։

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Կանոնավոր արտահայտությամբ . նշանակում է, որ դուք պետք է համապատասխանեք մեկ կերպարի, .* - «ագահորեն» համապատասխանեցնել զրոյական կամ ավելի նիշերը, այսինքն՝ առավելագույնը գրավել նիշերը, որպեսզի .*.*=.* նշանակում է համընկնել զրո կամ ավելի նիշերի, ապա համընկնել զրո կամ ավելի նիշերի, գտնել բառացի = նիշ, համընկնել զրո կամ ավելի նիշերի:

Եկեք վերցնենք թեստային գիծը x=x. Այն համապատասխանում է արտահայտությանը .*.*=.*. .*.* մինչև հավասարության նշանը չհամընկնի առաջինի հետ x (խմբերից մեկը .* համապատասխանում x, իսկ երկրորդը՝ զրո նիշ)։ .* հետո = հանդիպումները տևում են x.

Այս համեմատությունը պահանջում է 23 քայլ: Առաջին խումբ .* в .*.*=.* գործում է ագահորեն և համապատասխանում է ամբողջ լարին x=x. Շարժիչը տեղափոխվում է հաջորդ խումբ .*. Մենք այլևս համապատասխան կերպարներ չունենք, ուստի երկրորդ խումբը .* համընկնում է զրոյական նիշերի հետ (սա թույլատրվում է): Այնուհետեւ շարժիչը շարժվում է դեպի նշանը =. Այլևս նշաններ չկան (առաջին խումբ .* օգտագործեց ամբողջ արտահայտությունը x=x), համեմատություն չի լինում։

Եվ հետո սովորական արտահայտման շարժիչը վերադառնում է սկզբին: Նա անցնում է առաջին խումբ .* և համեմատում է այն с x= (փոխարենը) x=x), իսկ հետո վերցնում է երկրորդ խումբը .*. Երկրորդ խումբ .* համեմատվում է երկրորդի հետ x, և մեզ կրկին կերպարներ չեն մնացել։ Եվ երբ շարժիչը նորից հասնում է = в .*.*=.*, ոչինչ չի ստացվում։ Եվ նա նորից հետ է կանգնում։

Այս անգամ խումբը .* դեռ համընկնում է x=, բայց երկրորդ խումբը .* ոչ ավելին x, և զրո նիշ: Շարժիչը փորձում է բառացի բնույթ գտնել = օրինաչափության մեջ .*.*=.*, բայց դուրս չի գալիս (ի վերջո, առաջին խումբն արդեն զբաղեցրել է այն .*). Եվ նա նորից հետ է կանգնում։

Այս անգամ առաջին խումբը .* վերցնում է միայն առաջին x-ը: Բայց երկրորդ խումբը .* «ագահաբար» գրավում է =x. Արդեն գուշակե՞լ եք, թե ինչ է լինելու։ Շարժիչը փորձում է համապատասխանել բառացիին =, ձախողվում է և հերթական հետընթաց է անում։

Առաջին խումբ .* դեռ համընկնում է առաջինի հետ x. Երկրորդ .* միայն վերցնում է =. Իհարկե, շարժիչը չի կարող համապատասխանել բառացիին =, քանի որ երկրորդ խումբն արդեն արել է դա .*. Եվ կրկին հետընթաց. Եվ մենք փորձում ենք համապատասխանեցնել երեք նիշերի շարանը:

Արդյունքում առաջին խումբը .* համապատասխանում է միայն առաջինին x, երկրորդ .* - զրոյական նիշերով, և շարժիչը վերջապես համապատասխանում է բառացիին = արտահայտության մեջ с = հերթի մեջ։ Հաջորդը վերջին խումբն է .* համեմատվում է վերջինի հետ x.

23 քայլ միայն համար x=x. Դիտեք կարճ տեսանյութ Perl-ի օգտագործման մասին Regexp::Վրիպազերծիչ, որը ցույց է տալիս, թե ինչպես են տեղի ունենում քայլերն ու հետընթացը:

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Սա արդեն մեծ աշխատանք է, բայց ինչ կլիներ, եթե դրա փոխարեն x=x մենք կունենանք x=xx? Դա 33 քայլ է: Եւ եթե x=xxx? 45. Հարաբերությունները գծային չեն: Գրաֆիկը ցույց է տալիս համեմատությունը x=x դեպի x=xxxxxxxxxxxxxxxxxxxx (20 x այն բանից հետո =) Եթե ​​հետո ունենք 20 x =, շարժիչն ավարտում է համապատասխանությունը 555 քայլով: (Ավելին, եթե մենք պարտվել ենք x= իսկ տողը պարզապես բաղկացած է 20-ից x, շարժիչը կկատարի 4067 քայլ՝ հասկանալու համար, որ լուցկիներ չկան):

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Այս տեսանյութը ցույց է տալիս բոլոր հետընթացները համեմատության համար x=xxxxxxxxxxxxxxxxxxxx:

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Խնդիրն այն է, որ երբ լարերի չափը մեծանում է, համընկնման ժամանակը գերգծային է աճում: Բայց ամեն ինչ կարող է էլ ավելի վատանալ, եթե կանոնավոր արտահայտությունը մի փոքր փոփոխվի: Ասենք՝ ունեինք .*.*=.*; (այսինքն՝ նախշի վերջում եղել է բառացի ստորակետ)։ Օրինակ՝ նման արտահայտությունը համապատասխանելու համար foo=bar;.

Եվ այստեղ հետ գնալը իսկական աղետ կլիներ։ Համեմատության համար x=x դրա համար կպահանջվի ոչ թե 90, այլ 23 քայլ: Եվ այդ թիվը արագ աճում է: Համեմատել x= եւ 20- ը x, անհրաժեշտ է 5353 քայլ։ Ահա աղյուսակը: Նայեք առանցքի արժեքներին Y նախորդ գծապատկերի համեմատ։

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Եթե ​​դուք հետաքրքրված եք, ստուգեք բոլոր 5353 ձախողված համապատասխան քայլերը x=xxxxxxxxxxxxxxxxxxxx и .*.*=.*;

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Օգտագործելով ծույլ, այլ ոչ թե ագահ համընկնումը, կարելի է վերահսկել հետընթացի չափը: Եթե ​​բնօրինակ արտահայտությունը փոխենք .*?.*?=.*?, համեմատության համար x=x դրա համար կպահանջվի 11 քայլ (ոչ 23): Ինչ վերաբերում է x=xxxxxxxxxxxxxxxxxxxx. Բոլորը, քանի որ ? այն բանից հետո .* ասում է, որ շարժիչը պետք է համապատասխանի նիշերի նվազագույն քանակին, նախքան առաջ անցնելը:

Բայց ծույլ քարտեզագրումները լիովին չեն լուծում հետընթացի խնդիրը: Եթե ​​փոխարինենք աղետալի օրինակը .*.*=.*; մասին .*?.*?=.*?;, կատարման ժամանակը կմնա նույնը։ x=x դեռ պահանջում է 555 քայլ, և x= եւ 20- ը x - 5353.

Միակ բանը, որ կարելի է անել (բացի օրինաչափությունն ամբողջությամբ վերաշարադրելուց՝ ավելի մեծ յուրահատկության համար) կանոնավոր արտահայտման շարժիչից հրաժարվելն է իր հետընթաց մեխանիզմով։ Սա այն է, ինչ մենք անելու ենք առաջիկա մի քանի շաբաթվա ընթացքում:

Այս խնդրի լուծումը հայտնի է 1968 թվականից, երբ Քենթ Թոմփսոնը հոդված գրեց Ծրագրավորման տեխնիկա. Կանոնավոր արտահայտությունների որոնման ալգորիթմ («Ծրագրավորման մեթոդներ. կանոնավոր արտահայտությունների որոնման ալգորիթմ»): Հոդվածում նկարագրվում է մի մեխանիզմ, որը թույլ է տալիս կանոնավոր արտահայտությունը վերածել ոչ որոշիչ վերջավոր վիճակի մեքենաների, և ոչ որոշիչ վերջավոր վիճակի մեքենաներում վիճակի փոփոխությունից հետո օգտագործել ալգորիթմ, որի կատարման ժամանակը գծայինորեն կախված է համապատասխան տողից:

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Ծրագրավորման մեթոդներ
Կանոնավոր արտահայտությունների որոնման ալգորիթմ
Քեն Թոմփսոն

Bell Telephone Laboratories, Inc., Murray Hill, Նյու Ջերսի

Այն նկարագրում է տեքստում նիշերի որոշակի տող որոնելու մեթոդ և քննարկում է այս մեթոդի իրականացումը կոմպիլյատորի տեսքով: Կազմողն ընդունում է կանոնավոր արտահայտությունը որպես սկզբնաղբյուր և արտադրում է IBM 7094 ծրագիրը որպես օբյեկտի կոդ: Օբյեկտային ծրագիրը մուտքագրում է որոնման տեքստի տեսքով և ազդանշան է արձակում ամեն անգամ, երբ տեքստի տողը համընկնում է տվյալ կանոնավոր արտահայտության հետ: Հոդվածում ներկայացված են օրինակներ, խնդիրներ և լուծումներ:

Ալգորիթմ
Նախորդ որոնման ալգորիթմները հետ են մղում, եթե մասամբ հաջող որոնումը արդյունք չտվեց:

Կոմպիլացիոն ռեժիմում ալգորիթմը չի աշխատում սիմվոլների հետ։ Այն հրահանգներ է փոխանցում կոմպիլացված կոդին: Կատարումը շատ արագ է. տվյալներն ընթացիկ ցուցակի վերևին անցնելուց հետո այն ավտոմատ կերպով որոնում է կանոնավոր արտահայտության բոլոր հնարավոր հաջորդական նիշերը:
Կազմման և որոնման ալգորիթմը ներառված է ժամանակի փոխանակման տեքստային խմբագրիչում՝ որպես համատեքստային որոնում: Իհարկե, սա հեռու է նման որոնման ընթացակարգի միակ կիրառությունից։ Օրինակ, այս ալգորիթմի տարբերակն օգտագործվում է որպես սիմվոլի որոնում ասեմբլերի աղյուսակում:
Ենթադրվում է, որ ընթերցողը ծանոթ է կանոնավոր արտահայտություններին և IBM 7094 համակարգչային ծրագրավորման լեզվին:

Կազմող
Կոմպիլյատորը բաղկացած է երեք փուլից, որոնք ընթանում են զուգահեռաբար: Առաջին փուլը շարահյուսական զտումն է, որը թույլ է տալիս անցնել միայն շարահյուսական ճիշտ կանոնավոր արտահայտությունների միջով: Այս քայլը նաև տեղադրում է «·» օպերատորը՝ կանոնավոր արտահայտություններին համապատասխանելու համար: Երկրորդ քայլում կանոնավոր արտահայտությունը վերածվում է հետֆիքս ձևի: Երրորդ փուլում ստեղծվում է օբյեկտի կոդը: Առաջին 2 փուլերն ակնհայտ են, և մենք դրանց վրա չենք անդրադառնա։

Թոմփսոնի հոդվածը չի խոսում ոչ որոշիչ վերջավոր վիճակի մեքենաների մասին, բայց այն լավ բացատրում է գծային ժամանակի ալգորիթմը և ներկայացնում է ALGOL-60 ծրագիր, որը ստեղծում է IBM 7094-ի անսամբլի լեզվի կոդը: Իրականացումը բարդ է, բայց գաղափարը շատ պարզ է:

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

ընթացիկ որոնման ուղին: Այն ներկայացված է մեկ մուտքով և երկու ելքով ⊕ պատկերակով:
Նկար 1-ը ցույց է տալիս կոմպիլյացիայի երրորդ քայլի գործառույթները կանոնավոր արտահայտության օրինակը փոխակերպելիս: Օրինակի առաջին երեք նիշերն են a, b, c, և յուրաքանչյուրը ստեղծում է S[i] կույտի մուտքագրում և NNODE դաշտ:

NNODE գոյություն ունեցող կոդին՝ ստացված կանոնավոր արտահայտությունը մեկ կույտի մուտքագրում ստեղծելու համար (տես Նկար 5)

Ահա թե ինչ տեսք կունենա սովորական արտահայտությունը .*.*=.*, եթե պատկերացնեք, ինչպես Թոմփսոնի հոդվածի նկարներում:

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Նկ. 0 կան հինգ վիճակներ՝ սկսած 0-ից, և 3 ցիկլեր, որոնք սկսվում են 1, 2 և 3 վիճակներից։ Այս երեք ցիկլերը համապատասխանում են երեքին։ .* կանոնավոր արտահայտությամբ. Կետերով 3 օվալները համապատասխանում են մեկ նշանի։ Օվալ նշանով = համապատասխանում է բառացի բնույթին =. 4-րդ նահանգը վերջնական է. Եթե ​​հասնենք դրան, ապա կանոնավոր արտահայտությունը համընկնում է։

Տեսնելու համար, թե ինչպես կարող է նման վիճակի դիագրամը օգտագործվել կանոնավոր արտահայտությունների համապատասխանության համար .*.*=.*, մենք կանդրադառնանք տողերի համապատասխանությանը x=x. Ծրագիրը սկսվում է 0 վիճակից, ինչպես ցույց է տրված Նկ. 1.

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Որպեսզի այս ալգորիթմը աշխատի, պետական ​​մեքենան պետք է լինի միաժամանակ մի քանի վիճակներում: Ոչ որոշիչ վերջավոր մեքենան բոլոր հնարավոր անցումները կկատարի միաժամանակ:

Մինչև մուտքային տվյալները կարդալու ժամանակ կունենա, այն անցնում է երկու առաջին վիճակներին (1 և 2), ինչպես ցույց է տրված Նկ. 2.

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Նկ. 2-ը ցույց է տալիս, թե ինչ է տեղի ունենում, երբ նա նայում է առաջինին x в x=x. x կարող է քարտեզագրել դեպի վերին կետ՝ անցնելով 1-ին վիճակից և վերադառնալով 1-ին վիճակին: Կամ x կարող է քարտեզագրել ստորև բերված կետը՝ անցնելով 2-րդ վիճակից և վերադառնալով 2-րդ վիճակին:

Առաջինին համապատասխանեցնելուց հետո x в x=x մենք դեռ գտնվում ենք 1-ին և 2-րդ վիճակներում: Մենք չենք կարող հասնել 3-րդ կամ 4-րդ վիճակներին, քանի որ մեզ անհրաժեշտ է բառացի նիշ: =.

Այնուհետև ալգորիթմը դիտարկում է = в x=x. Ինչպես նախկինում x-ը, այն կարող է համընկնել վերին երկու օղակներից որևէ մեկին՝ 1-ից վիճակ 1-ին կամ 2-րդ վիճակից 2-րդ վիճակին, բայց ալգորիթմը կարող է համապատասխանել բառացիին։ = և 2-րդ վիճակից տեղափոխել 3 վիճակ (և անմիջապես 4): Սա ցույց է տրված Նկ. 3.

Cloudflare-ի անջատման մանրամասները 2 թվականի հուլիսի 2019-ին

Այնուհետև ալգորիթմը անցնում է վերջինին x в x=x. 1-ին և 2-րդ վիճակներից հնարավոր են նույն անցումները վերադառնալ 1-ին և 2-րդ վիճակներին: 3-րդ վիճակից x կարող է համապատասխանել աջ կողմում գտնվող կետին և վերադառնալ 3 վիճակին:

Այս փուլում յուրաքանչյուր կերպար x=x հաշվի առնելով, և քանի որ հասել ենք 4-րդ վիճակին, կանոնավոր արտահայտությունը համապատասխանում է այդ տողին: Յուրաքանչյուր նիշ մշակվում է մեկ անգամ, ուստի այս ալգորիթմը մուտքային տողի երկարությամբ գծային է: Եվ ոչ մի հետքայլ:

Ակնհայտ է, որ 4-րդ վիճակին հասնելուց հետո (երբ ալգորիթմը համընկնում է x=) ամբողջ կանոնավոր արտահայտությունը համընկնում է, և ալգորիթմը կարող է ավարտվել առանց այն ընդհանրապես հաշվի առնելու x.

Այս ալգորիթմը գծայինորեն կախված է մուտքային տողի չափից:

Source: www.habr.com

Добавить комментарий