Az Önhöz hasonló olvasók támogatják a MUO-t. Amikor a webhelyünkön található linkek használatával vásárol, társult jutalékot kaphatunk.

Versenyfeltétel akkor fordul elő, amikor két műveletnek egy meghatározott sorrendben kell történnie, de előfordulhatnak ellenkező sorrendben is.

Például egy többszálú alkalmazásban két külön szál férhet hozzá egy közös változóhoz. Ennek eredményeként, ha az egyik szál megváltoztatja a változó értékét, a másik továbbra is a régebbi verziót használhatja, figyelmen kívül hagyva a legújabb értéket. Ez nemkívánatos eredményekhez vezet.

A modell jobb megértéséhez jó lenne alaposan megvizsgálni a processzor folyamatváltási folyamatát.

Hogyan váltja a processzor a folyamatokat

Modern operációs rendszerek több folyamatot is futtathat egyszerre, ezt többfeladatosnak nevezik. Ha ezt a folyamatot a A CPU végrehajtási ciklusa, előfordulhat, hogy a többfeladatos működés valójában nem létezik.

Ehelyett a processzorok folyamatosan váltanak a folyamatok között, hogy egyidejűleg futtassák azokat, vagy legalábbis úgy viselkedjenek, mintha ezt tennék. A CPU megszakíthat egy folyamatot, mielőtt az befejeződött volna, és egy másik folyamatot folytathat. Az operációs rendszer vezérli ezeknek a folyamatoknak a kezelését.

Például a Round Robin algoritmus, az egyik legegyszerűbb kapcsolási algoritmus, a következőképpen működik:

Általában ez az algoritmus lehetővé teszi, hogy az operációs rendszer által meghatározott időn belül minden folyamat nagyon rövid ideig futhasson. Például ez lehet egy két mikroszekundumos periódus.

A CPU sorra veszi az egyes folyamatokat, és olyan parancsokat hajt végre, amelyek két mikromásodpercig futnak. Ezután továbblép a következő folyamatra, függetlenül attól, hogy az aktuális befejeződött-e vagy sem. Így egy végfelhasználó szemszögéből úgy tűnik, hogy egynél több folyamat fut egyidejűleg. Ha azonban a kulisszák mögé nézünk, a CPU továbbra is rendben végzi a dolgokat.

Mellesleg, ahogy a fenti diagram is mutatja, a Round Robin algoritmusból hiányzik az optimalizálás vagy a feldolgozási prioritás fogalma. Ennek eredményeként ez egy meglehetősen kezdetleges módszer, amelyet ritkán használnak valós rendszerekben.

Most, hogy mindezt jobban megértsük, képzeljük el, hogy két szál fut. Ha a szálak egy közös változóhoz férnek hozzá, versenyfeltétel léphet fel.

Példa webes alkalmazásra és versenyfeltételre

Tekintse meg az alábbi egyszerű Flask alkalmazást, hogy konkrét példát mutasson mindarra, amit eddig olvasott. Ennek az alkalmazásnak az a célja, hogy a weben lezajló pénztranzakciókat kezelje. Mentse el a következőket egy nevű fájlba pénz.py:

tól től lombik import Lombik
tól től lombik.ext.sqlalchemy import SQLAlchemy

app = Lombik (__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy (alkalmazás)

osztályfiók(db. Modell):
id = db. Oszlop (db. Egész szám, elsődleges_kulcs = Igaz)
összeg = db. Oszlop (db. Húr(80), egyedi = Igaz)

def__benne__(én, gróf):
saját.összeg = összeg

def__repr__(maga):
Visszatérés '' % ön.összeg

@app.route("/")
defSzia():
account = Account.query.get(1) # Csak egy pénztárca van.
Visszatérés "Összes pénz = {}".formátum (account.amount)

@app.route("/send/")
defKüld(összeg):
account = Account.query.get(1)

ha int (számla.összeg) < összeg:
Visszatérés "Fedezethiány. Pénz visszaállítása val vel /reset!)"

account.amount = int (account.amount) - összeg
db.session.commit()
Visszatérés "Elküldött összeg = {}".formátum (összeg)

@app.route("/reset")
defVisszaállítás():
account = Account.query.get(1)
számla.összeg = 5000
db.session.commit()
Visszatérés "Money reset."

ha __name__ == "__main__":
app.secret_key = 'heLLoTHisIsSeCReTKey!'
app.run()

A kód futtatásához létre kell hoznia egy rekordot a számlatáblázatban, és ezen a rekordon kell folytatnia a tranzakciókat. Amint a kódban látható, ez egy tesztkörnyezet, tehát a tábla első rekordjával szemben hajtja végre a tranzakciókat.

tól től pénz import db
db.create_all()
tól től pénz import fiók
számla = fiók (5000)
db.ülés.add hozzá(fiókot)
db.ülés.elkövetni()

Létrehozott egy fiókot 5000 USD egyenleggel. Végül futtassa a fenti forráskódot a következő paranccsal, feltéve, hogy telepítve van a Flask és a Flask-SQLAlchemy csomag:

pitonpénz.py

Tehát megvan a Flask webalkalmazása, amely egy egyszerű kinyerési folyamatot végez. Ez az alkalmazás a következő műveleteket tudja végrehajtani a GET kérelem hivatkozásokkal. Mivel a Flask alapértelmezés szerint az 5000-es porton fut, az a cím, amelyen eléri azt 127.0.0.1:5000/. Az alkalmazás a következő végpontokat biztosítja:

  • 127.0.0.1:5000/ megjeleníti az aktuális egyenleget.
  • 127.0.0.1:5000/küldés/{összeg} összeget von le a számláról.
  • 127.0.0.1:5000/reset visszaállítja a számlát 5000 dollárra.

Most, ebben a szakaszban megvizsgálhatja, hogyan fordul elő a versenyfeltételek sebezhetősége.

A versenyfeltételek sebezhetőségének valószínűsége

A fenti webes alkalmazás egy lehetséges versenyhelyzeti sebezhetőséget tartalmaz.

Képzelje el, hogy 5000 dollárja van a kezdéshez, és hozzon létre két különböző HTTP-kérést, amelyek 1 dollárt küldenek. Ehhez két különböző HTTP kérést küldhet a hivatkozásra 127.0.0.1:5000/küldés/1. Tegyük fel, hogy amint a webszerver feldolgozza az első kérést, a CPU leállítja ezt a folyamatot és feldolgozza a második kérést. Például az első folyamat leállhat a következő kódsor futtatása után:

számla.összeg = int(számla.összeg) - összeg

Ez a kód kiszámított egy új összeget, de még nem mentette el a rekordot az adatbázisban. Amikor a második kérés elkezdődik, ugyanazt a számítást hajtja végre, levonva 1 dollárt az adatbázisban lévő értékből – 5000 dollárból – és eltárolja az eredményt. Amikor az első folyamat folytatódik, eltárolja saját értékét – 4999 USD –, amely nem tükrözi a legutóbbi számlaegyenleget.

Tehát két kérés teljesült, és mindegyiknek le kellett volna vonnia 1 USD-t a számlaegyenlegből, ami 4998 USD új egyenleget eredményezett. De attól függően, hogy a webszerver milyen sorrendben dolgozza fel őket, a végső számlaegyenleg 4999 USD lehet.

Képzelje el, hogy 128 kérelmet küld 1 dollár átutalásra a célrendszernek öt másodperces időkereten belül. A tranzakció eredményeként a várható számlakivonat 5000 USD – 128 USD = 4875 USD lesz. A verseny körülményei miatt azonban a végső egyenleg 4875 és 4999 dollár között változhat.

A programozók a biztonság egyik legfontosabb összetevője

Egy szoftverprojektben, mint programozónak jó néhány felelőssége van. A fenti példa egy egyszerű pénzátutalási alkalmazásra vonatkozik. Képzelje el, hogy egy szoftverprojekten dolgozik, amely bankszámlát vagy egy nagy e-kereskedelmi webhely hátterét kezeli.

Ismernie kell az ilyen biztonsági réseket, hogy a védelmükre írt program mentes legyen a sebezhetőségektől. Ehhez erős felelősség kell.

A versenyfeltételek sebezhetősége csak egy ezek közül. Függetlenül attól, hogy milyen technológiát használ, ügyelnie kell a megírt kód biztonsági réseire. Az egyik legfontosabb készség, amelyet programozóként megszerezhet, a szoftverbiztonság ismerete.