Kaltaisesi lukijat auttavat tukemaan MUO: ta. Kun teet ostoksen käyttämällä sivustollamme olevia linkkejä, voimme ansaita kumppanipalkkion.
Kilpailutilanne syntyy, kun kaksi toimintoa on suoritettava tietyssä järjestyksessä, mutta ne voivat suorittaa päinvastaisessa järjestyksessä.
Esimerkiksi monisäikeisessä sovelluksessa kaksi erillistä säiettä voi päästä yhteiseen muuttujaan. Tämän seurauksena, jos yksi säie muuttaa muuttujan arvoa, toinen voi silti käyttää vanhempaa versiota jättäen huomioimatta uusimman arvon. Tämä aiheuttaa ei-toivottuja tuloksia.
Tämän mallin ymmärtämiseksi paremmin olisi hyvä tutkia prosessorin prosessinvaihtoprosessia tarkasti.
Kuinka prosessori vaihtaa prosesseja
Nykyaikaiset käyttöjärjestelmät voi ajaa useampaa kuin yhtä prosessia samanaikaisesti, jota kutsutaan multitaskingiksi. Kun tarkastellaan tätä prosessia kannalta CPU: n suoritussykli, saatat huomata, että moniajoa ei todellisuudessa ole olemassa.
Sen sijaan prosessorit vaihtavat jatkuvasti prosessien välillä ajaakseen niitä samanaikaisesti tai ainakin toimiakseen ikään kuin he tekisivät niin. CPU voi keskeyttää prosessin ennen kuin se on valmis ja jatkaa eri prosessia. Käyttöjärjestelmä ohjaa näiden prosessien hallintaa.
Esimerkiksi Round Robin -algoritmi, yksi yksinkertaisimmista vaihtoalgoritmeista, toimii seuraavasti:
Yleensä tämä algoritmi sallii jokaisen prosessin ajaa hyvin pieniä osia käyttöjärjestelmän määrittämästä ajasta. Tämä voi olla esimerkiksi kahden mikrosekunnin jakso.
CPU ottaa jokaisen prosessin vuorotellen ja suorittaa komentoja, jotka kestävät kaksi mikrosekuntia. Sitten se jatkaa seuraavaan prosessiin riippumatta siitä, onko nykyinen päättynyt vai ei. Näin ollen loppukäyttäjän näkökulmasta useampi kuin yksi prosessi näyttää olevan käynnissä samanaikaisesti. Kuitenkin kun katsot kulissien taakse, CPU tekee asiat edelleen järjestyksessä.
Muuten, kuten yllä oleva kaavio osoittaa, Round Robin -algoritmista puuttuu optimointi- tai käsittelyprioriteettikäsitteet. Tämän seurauksena se on melko alkeellinen menetelmä, jota käytetään harvoin todellisissa järjestelmissä.
Ymmärtääksesi tämän paremmin, kuvittele, että kaksi säiettä on käynnissä. Jos säikeet käyttävät yhteistä muuttujaa, voi syntyä kilpailutilanne.
Esimerkki verkkosovelluksesta ja kilpailutilanteesta
Katso alla oleva yksinkertainen Flask-sovellus pohtiaksesi konkreettista esimerkkiä kaikesta, mitä olet lukenut tähän mennessä. Tämän sovelluksen tarkoitus on hallita verkossa tapahtuvia rahatapahtumia. Tallenna seuraavat tiedostot nimeltä rahaa.py:
alkaen pullo tuonti Pullo
alkaen flask.ext.sqlalchemy tuonti SQLAlchemyapp = Kolvi (__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy (sovellus)luokkaaTili(db. Malli):
id = db. Sarake (db. Kokonaisluku, ensisijainen_avain = Totta)
määrä = db. Sarake (db. merkkijono(80), ainutlaatuinen = Totta)def__sen sisällä__(itse, laske):
itse.määrä = määrädef__repr__(itse):
palata '' % omamäärä@app.route("/")
defHei():
tili = Account.query.get(1) # Lompakko on vain yksi.
palata "Raha yhteensä = {}".muoto (account.amount)@app.route("/send/")
deflähettää(määrä):
tili = Account.query.get(1)jos int (account.amount) < summa:
palata "Riittämätön tasapaino. Nollaa rahat kanssa /reset!)"account.amount = int (account.amount) - summa
db.session.commit()
palata "Lähetetty määrä = {}".muoto (summa)@app.route("/reset")
defnollaa():
tili = Account.query.get(1)
tili.summa = 5000
db.session.commit()
palata "Rahat nollattiin."
jos __name__ == "__main__":
app.secret_key = 'heLLoTHisIsSeCReTKey!'
app.run()
Tämän koodin suorittamiseksi sinun on luotava tietue tilitaulukkoon ja jatkettava tapahtumia tämän tietueen kautta. Kuten koodista näkyy, tämä on testiympäristö, joten se suorittaa tapahtumia taulukon ensimmäistä tietuetta vastaan.
alkaen raha tuonti db
db.create_all()
alkaen raha tuonti Tili
tili = tili (5000)
db.istunto.lisätä(tili)
db.istunto.tehdä()
Olet nyt luonut tilin, jonka saldo on 5 000 dollaria. Suorita lopuksi yllä oleva lähdekoodi seuraavalla komennolla, jos sinulla on Flask- ja Flask-SQLAlchemy-paketit asennettuna:
pythonraha.py
Joten sinulla on Flask-verkkosovellus, joka tekee yksinkertaisen purkuprosessin. Tämä sovellus voi suorittaa seuraavat toiminnot GET-pyyntölinkeillä. Koska Flask toimii oletuksena 5000-portissa, osoite, josta käytät sitä, on 127.0.0.1:5000/. Sovellus tarjoaa seuraavat päätepisteet:
- 127.0.0.1:5000/ näyttää nykyisen saldon.
- 127.0.0.1:5000/lähetys/{summa} vähentää summan tililtä.
- 127.0.0.1:5000/nollaus nollaa tilin 5 000 dollariin.
Nyt tässä vaiheessa voit tutkia, kuinka kilpailutilanteen haavoittuvuus ilmenee.
Kilpailutilanteen haavoittuvuuden todennäköisyys
Yllä oleva verkkosovellus sisältää mahdollisen kilpailutilanteen haavoittuvuuden.
Kuvittele, että sinulla on aluksi 5 000 dollaria ja luo kaksi erilaista HTTP-pyyntöä, jotka lähettävät 1 dollarin. Tätä varten voit lähettää kaksi eri HTTP-pyyntöä linkkiin 127.0.0.1:5000/lähetys/1. Oletetaan, että heti kun verkkopalvelin käsittelee ensimmäisen pyynnön, CPU pysäyttää tämän prosessin ja käsittelee toisen pyynnön. Esimerkiksi ensimmäinen prosessi voi pysähtyä seuraavan koodirivin suorittamisen jälkeen:
tili.summa = int(account.amount) - summa
Tämä koodi on laskenut uuden summan, mutta ei ole vielä tallentanut tietuetta tietokantaan. Kun toinen pyyntö alkaa, se suorittaa saman laskutoimituksen, vähentää 1 dollarin tietokannan arvosta – 5 000 dollaria – ja tallentaa tuloksen. Kun ensimmäinen prosessi jatkuu, se tallentaa oman arvonsa – 4 999 dollaria – mikä ei vastaa viimeisintä tilin saldoa.
Joten kaksi pyyntöä on suoritettu, ja kummankin olisi pitänyt vähentää 1 dollari tilin saldosta, jolloin uusi saldo on 4 998 dollaria. Mutta riippuen järjestyksessä, jossa verkkopalvelin käsittelee ne, tilin lopullinen saldo voi olla 4 999 dollaria.
Kuvittele, että lähetät 128 pyyntöä tehdä 1 dollarin siirto kohdejärjestelmään viiden sekunnin kuluessa. Tämän tapahtuman seurauksena odotettu tiliote on $ 5 000 - $ 128 = $ 4 875. Kilpailutilanteesta johtuen lopullinen saldo voi kuitenkin vaihdella 4 875 ja 4 999 dollarin välillä.
Ohjelmoijat ovat yksi turvallisuuden tärkeimmistä osista
Ohjelmistoprojektissa sinulla on ohjelmoijana melkoisesti vastuuta. Yllä oleva esimerkki koskee yksinkertaista rahansiirtosovellusta. Kuvittele työskenteleväsi ohjelmistoprojektissa, joka hallinnoi pankkitiliä tai suuren verkkokauppasivuston taustaohjelmaa.
Sinun on tunnettava tällaiset haavoittuvuudet, jotta niiden suojaamiseksi kirjoittamasi ohjelma on vapaa haavoittuvuuksista. Tämä vaatii vahvaa vastuuta.
Kilpailutilanteen haavoittuvuus on vain yksi niistä. Riippumatta siitä, mitä tekniikkaa käytät, sinun on varottava kirjoittamasi koodin haavoittuvuuksia. Yksi tärkeimmistä taidoista, jotka voit hankkia ohjelmoijana, on ohjelmistoturvallisuuden tuntemus.