Lezers zoals jij steunen MUO. Wanneer u een aankoop doet via links op onze site, kunnen we een aangesloten commissie verdienen.
Een raceconditie doet zich voor wanneer twee bewerkingen in een specifieke volgorde moeten plaatsvinden, maar ze kunnen in de tegenovergestelde volgorde worden uitgevoerd.
In een toepassing met meerdere threads kunnen bijvoorbeeld twee afzonderlijke threads toegang krijgen tot een gemeenschappelijke variabele. Als gevolg hiervan, als een thread de waarde van de variabele verandert, kan de andere nog steeds de oudere versie gebruiken en de nieuwste waarde negeren. Dit zal ongewenste resultaten veroorzaken.
Om dit model beter te begrijpen, zou het goed zijn om het processchakelproces van de processor nauwkeurig te bekijken.
Hoe een processor van proces wisselt
Moderne besturingssystemen kan meer dan één proces tegelijk uitvoeren, multitasking genaamd. Als je naar dit proces kijkt in termen van de Uitvoeringscyclus van de CPU, zult u merken dat multitasking niet echt bestaat.
In plaats daarvan schakelen processors constant tussen processen om ze tegelijkertijd uit te voeren of doen ze in ieder geval alsof ze dat doen. De CPU kan een proces onderbreken voordat het is voltooid en een ander proces hervatten. Het besturingssysteem regelt het beheer van deze processen.
Het Round Robin-algoritme, een van de eenvoudigste schakelalgoritmen, werkt bijvoorbeeld als volgt:
Over het algemeen zorgt dit algoritme ervoor dat elk proces gedurende zeer korte tijd kan worden uitgevoerd, zoals het besturingssysteem bepaalt. Dit kan bijvoorbeeld een periode van twee microseconden zijn.
De CPU neemt elk proces om de beurt en voert opdrachten uit die gedurende twee microseconden worden uitgevoerd. Het gaat dan verder naar het volgende proces, ongeacht of het huidige is voltooid of niet. Vanuit het oogpunt van een eindgebruiker lijkt er dus meer dan één proces tegelijkertijd te lopen. Als je echter achter de schermen kijkt, doet de CPU het nog steeds op orde.
Trouwens, zoals het bovenstaande diagram laat zien, mist het Round Robin-algoritme enige notie van optimalisatie of verwerkingsprioriteit. Als gevolg hiervan is het een nogal rudimentaire methode die zelden wordt gebruikt in echte systemen.
Om dit allemaal beter te begrijpen, stel je voor dat er twee threads lopen. Als de threads toegang hebben tot een gemeenschappelijke variabele, kan er een raceconditie ontstaan.
Een voorbeeld webapplicatie en raceconditie
Bekijk de eenvoudige Flask-app hieronder om na te denken over een concreet voorbeeld van alles wat je tot nu toe hebt gelezen. Het doel van deze applicatie is het beheren van geldtransacties die op internet zullen plaatsvinden. Sla het volgende op in een bestand met de naam geld.py:
van kolf importeren Fles
van kolf.ext.sqlalchemy importeren SQLAlchemyapp = Fles (__naam__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemie (app)klasRekening(db. Model):
id = db. Kolom (db. Integer, primaire_sleutel = WAAR)
hoeveelheid = db. Kolom (db. Snaar(80), uniek = WAAR)def__in het__(zelf, tel):
self.amount = bedragdef__repr__(zelf):
opbrengst '' % eigen.bedrag@app.route("/")
defHoi():
account = Account.query.get(1) # Er is maar één portemonnee.
opbrengst "Totaal geld = {}".format (account.bedrag)@app.route("/send/")
defversturen(hoeveelheid):
account = Account.query.get(1)als int (account.bedrag) < bedrag:
opbrengst "Onvoldoende saldo. Geld resetten met /reset!)"account.amount = int (account.amount) - bedrag
db.session.commit()
opbrengst "Bedrag verzonden = {}".format (bedrag)@app.route("/reset")
defresetten():
account = Account.query.get(1)
rekening.bedrag = 5000
db.session.commit()
opbrengst "Geld resetten."
als __naam__ == "__hoofd__":
app.secret_key = 'heLLoTHisIsSeCReTKey!'
app.run()
Om deze code uit te voeren, moet u een record maken in de rekeningtabel en de transacties over dit record voortzetten. Zoals u in de code kunt zien, is dit een testomgeving, dus het maakt transacties tegen het eerste record in de tabel.
van geld importeren db
db.creëer_alles()
van geld importeren Rekening
rekening = rekening (5000)
db.sessie.toevoegen(rekening)
db.sessie.verbinden()
Je hebt nu een account aangemaakt met een saldo van $5.000. Voer ten slotte de bovenstaande broncode uit met behulp van de volgende opdracht, op voorwaarde dat u de pakketten Flask en Flask-SQLAlchemy hebt geïnstalleerd:
Pythongeld.py
U hebt dus de Flask-webtoepassing die een eenvoudig extractieproces uitvoert. Deze applicatie kan de volgende bewerkingen uitvoeren met GET-verzoekkoppelingen. Aangezien Flask standaard op de 5000-poort draait, is het adres waarop u het opent 127.0.0.1:5000/. De app biedt de volgende eindpunten:
- 127.0.0.1:5000/ toont het huidige saldo.
- 127.0.0.1:5000/verzenden/{bedrag} trekt bedrag van de rekening af.
- 127.0.0.1:5000/reset reset het account naar $ 5.000.
Nu, in dit stadium, kunt u onderzoeken hoe de kwetsbaarheid voor racecondities optreedt.
Waarschijnlijkheid van een kwetsbaarheid voor racecondities
De bovenstaande webapplicatie bevat een mogelijke race condition kwetsbaarheid.
Stel je voor dat je $ 5.000 hebt om mee te beginnen en maak twee verschillende HTTP-verzoeken die $ 1 zullen verzenden. Hiervoor kunt u twee verschillende HTTP-verzoeken naar de link sturen 127.0.0.1:5000/verzenden/1. Neem aan dat, zodra de webserver het eerste verzoek verwerkt, stopt de CPU dit proces en verwerkt het tweede verzoek. Het eerste proces kan bijvoorbeeld stoppen na het uitvoeren van de volgende coderegel:
rekening.bedrag = int(account.bedrag) - bedrag
Deze code heeft een nieuw totaal berekend, maar heeft het record nog niet opgeslagen in de database. Wanneer het tweede verzoek begint, voert het dezelfde berekening uit, waarbij $ 1 wordt afgetrokken van de waarde in de database - $ 5.000 - en het resultaat wordt opgeslagen. Wanneer het eerste proces wordt hervat, slaat het zijn eigen waarde op - $ 4.999 - die niet het meest recente rekeningsaldo weergeeft.
Er zijn dus twee verzoeken voltooid en elk had $ 1 van het rekeningsaldo moeten aftrekken, resulterend in een nieuw saldo van $ 4.998. Maar afhankelijk van de volgorde waarin de webserver ze verwerkt, kan het uiteindelijke rekeningsaldo $ 4.999 zijn.
Stel je voor dat je 128 verzoeken verstuurt om een overboeking van $1 naar het doelsysteem te doen in een tijdsbestek van vijf seconden. Als gevolg van deze transactie zal het verwachte rekeningafschrift $ 5.000 - $ 128 = $ 4.875 zijn. Vanwege de raceconditie kan het eindsaldo echter variëren tussen $ 4.875 en $ 4.999.
Programmeurs zijn een van de belangrijkste onderdelen van beveiliging
In een softwareproject heb je als programmeur nogal wat verantwoordelijkheden. Het bovenstaande voorbeeld was voor een eenvoudige aanvraag voor geldoverboeking. Stel je voor dat je aan een softwareproject werkt dat een bankrekening of de backend van een grote e-commercesite beheert.
U moet bekend zijn met dergelijke kwetsbaarheden, zodat het programma dat u hebt geschreven om ze te beschermen, vrij is van kwetsbaarheden. Dit vereist een sterke verantwoordelijkheid.
Een kwetsbaarheid voor racecondities is er slechts één van. Welke technologie u ook gebruikt, u moet op uw hoede zijn voor kwetsbaarheden in de code die u schrijft. Een van de belangrijkste vaardigheden die u als programmeur kunt opdoen, is bekendheid met softwarebeveiliging.