Čtenáři jako vy pomáhají podporovat MUO. Když provedete nákup pomocí odkazů na našich stránkách, můžeme získat provizi přidružené společnosti.
Spor nastane, když musí proběhnout dvě operace v určitém pořadí, ale mohou se spustit v opačném pořadí.
Například ve vícevláknové aplikaci mohou ke společné proměnné přistupovat dvě samostatná vlákna. Výsledkem je, že pokud jedno vlákno změní hodnotu proměnné, druhé může stále používat starší verzi a ignorovat nejnovější hodnotu. To způsobí nežádoucí výsledky.
Pro lepší pochopení tohoto modelu by bylo dobré podrobně prozkoumat proces přepínání procesů procesoru.
Jak procesor přepíná procesy
Moderní operační systémy může spouštět více než jeden proces současně, nazývaný multitasking. Když se podíváte na tento proces z hlediska cyklus provádění CPU, možná zjistíte, že multitasking ve skutečnosti neexistuje.
Místo toho procesory neustále přepínají mezi procesy, aby je spouštěly současně nebo alespoň jednaly, jako by to dělaly. CPU může přerušit proces před jeho dokončením a obnovit jiný proces. Operační systém řídí správu těchto procesů.
Například algoritmus Round Robin, jeden z nejjednodušších přepínacích algoritmů, funguje následovně:
Obecně tento algoritmus umožňuje, aby každý proces běžel po velmi malé časové úseky, jak určí operační systém. Může to být například doba dvou mikrosekund.
CPU přebírá každý proces postupně a provádí příkazy, které poběží po dobu dvou mikrosekund. Poté pokračuje dalším procesem bez ohledu na to, zda ten aktuální skončil nebo ne. Z pohledu koncového uživatele se tedy zdá, že současně běží více než jeden proces. Když se však podíváte do zákulisí, CPU stále dělá věci v pořádku.
Mimochodem, jak ukazuje výše uvedený diagram, algoritmus Round Robin postrádá jakoukoli optimalizaci nebo prioritu zpracování. V důsledku toho jde o poměrně rudimentární metodu, která se v reálných systémech používá jen zřídka.
Abyste tomu všemu lépe porozuměli, představte si, že běží dvě vlákna. Pokud vlákna přistupují ke společné proměnné, může dojít ke sporu.
Příklad webové aplikace a podmínky závodu
Podívejte se na jednoduchou aplikaci Flask níže a zamyslete se nad konkrétním příkladem všeho, co jste dosud četli. Účelem této aplikace je spravovat peněžní transakce, které budou probíhat na webu. Uložte následující do souboru s názvem peníze.py:
z baňka import Baňka
z flask.ext.sqlalchemy import SQLAlchemyapp = Flask (__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy (aplikace)třídaÚčet(db. Modelka):
id = db. Sloupec (db. Celé číslo, primární_klíč = Skutečný)
množství = db. Sloupec (db. Tětiva(80), jedinečný = Skutečný)def__init__(sebe, počítat):
vlastní.částka = částkadef__repr__(já):
vrátit se '' % vlastní.částka@app.route("/")
defAhoj():
účet = Account.query.get(1) # Peněženka je jen jedna.
vrátit se "Celkové peníze = {}".formát (účet.částka)@app.route("/odeslat/")
defposlat(množství):
účet = Account.query.get(1)-li int (account.amount) < částka:
vrátit se „Nedostatečná rovnováha. Resetovat peníze s /reset!)"account.amount = int (account.amount) - částka
db.session.commit()
vrátit se "Zaslaná částka = {}".formát (částka)@app.route("/reset")
defresetovat():
účet = Account.query.get(1)
účet.částka = 5000
db.session.commit()
vrátit se "Reset peněz."
-li __name__ == "__main__":
app.secret_key = 'helloTHisIsSeCReTKey!'
app.run()
Chcete-li spustit tento kód, budete muset vytvořit záznam v tabulce účtů a pokračovat v transakcích nad tímto záznamem. Jak vidíte v kódu, jedná se o testovací prostředí, takže provádí transakce proti prvnímu záznamu v tabulce.
z peníze import db
db.vytvořit_vše()
z peníze import Účet
účet = Účet (5000)
db.zasedání.přidat(účet)
db.zasedání.spáchat()
Nyní jste vytvořili účet se zůstatkem 5 000 $. Nakonec spusťte výše uvedený zdrojový kód pomocí následujícího příkazu za předpokladu, že máte nainstalované balíčky Flask a Flask-SQLAlchemy:
krajtapeníze.py
Takže máte webovou aplikaci Flask, která provádí jednoduchý proces extrakce. Tato aplikace může provádět následující operace s odkazy požadavku GET. Protože Flask standardně běží na portu 5000, adresa, na které k němu přistupujete, je 127.0.0.1:5000/. Aplikace poskytuje následující koncové body:
- 127.0.0.1:5000/ zobrazí aktuální zůstatek.
- 127.0.0.1:5000/odeslat/{částka} odečte částku z účtu.
- 127.0.0.1:5000/reset resetuje účet na 5 000 $.
Nyní, v této fázi, můžete prozkoumat, jak k chybě zabezpečení dochází.
Pravděpodobnost zranitelnosti rasových podmínek
Výše uvedená webová aplikace obsahuje možnou chybu zabezpečení typu race condition.
Představte si, že máte pro začátek 5 000 USD a vytvořte dva různé požadavky HTTP, které pošlou 1 USD. Za tímto účelem můžete na odkaz odeslat dva různé požadavky HTTP 127.0.0.1:5000/odeslat/1. Předpokládejme, že co nejdříve webový server zpracuje první požadavek, CPU tento proces zastaví a zpracuje druhý požadavek. První proces se může například zastavit po spuštění následujícího řádku kódu:
účet.částka = int(účet.částka) - částka
Tento kód vypočítal nový součet, ale ještě neuložil záznam do databáze. Když začne druhý požadavek, provede stejný výpočet, odečte 1 $ od hodnoty v databázi – 5 000 $ – a uloží výsledek. Když se první proces obnoví, uloží svou vlastní hodnotu – 4 999 USD – která nebude odrážet poslední zůstatek na účtu.
Takže byly dokončeny dvě žádosti a každá by měla odečíst 1 $ od zůstatku účtu, což má za následek nový zůstatek 4 998 $. Ale v závislosti na pořadí, ve kterém je webový server zpracovává, může být konečný zůstatek na účtu 4 999 $.
Představte si, že odešlete 128 požadavků na provedení převodu 1 $ do cílového systému v časovém rámci pěti sekund. V důsledku této transakce bude očekávaný výpis z účtu 5 000 USD – 128 USD = 4 875 USD. Kvůli podmínkám závodu se však konečný zůstatek může lišit od 4 875 do 4 999 $.
Programátoři jsou jednou z nejdůležitějších součástí zabezpečení
V softwarovém projektu máte jako programátor poměrně dost povinností. Výše uvedený příklad byl pro jednoduchou aplikaci pro převod peněz. Představte si, že pracujete na softwarovém projektu, který spravuje bankovní účet nebo backend velkého webu elektronického obchodu.
Musíte být obeznámeni s takovými zranitelnostmi, aby program, který jste napsali, abyste je chránili, byl bez zranitelností. To vyžaduje silnou odpovědnost.
Zranitelnost typu race condition je pouze jednou z nich. Bez ohledu na to, jakou technologii používáte, musíte si dávat pozor na zranitelnosti v kódu, který píšete. Jednou z nejdůležitějších dovedností, které můžete jako programátor získat, je znalost softwarového zabezpečení.