Che cos'è una vulnerabilità legata a una condizione di razza?

Che cos'è una vulnerabilità legata a una condizione di razza?
I lettori come te aiutano a supportare MUO. Quando effettui un acquisto utilizzando i link sul nostro sito, potremmo guadagnare una commissione di affiliazione.

Una race condition si verifica quando due operazioni devono verificarsi in un ordine specifico, ma possono essere eseguite nell'ordine opposto.





Ad esempio, in un'applicazione multithread, due thread separati potrebbero accedere a una variabile comune. Di conseguenza, se un thread modifica il valore della variabile, l'altro potrebbe ancora utilizzare la versione precedente, ignorando il valore più recente. Ciò causerà risultati indesiderati.





FARE USO DEL VIDEO DEL GIORNO

Per comprendere meglio questo modello, sarebbe bene esaminare da vicino il processo di commutazione del processo del processore.





Come un processore cambia i processi

Sistemi operativi moderni può eseguire più di un processo contemporaneamente, chiamato multitasking. Quando guardi questo processo in termini di Ciclo di esecuzione della CPU , potresti scoprire che il multitasking non esiste davvero.

siti di streaming tv gratuiti nessuna registrazione

Invece, i processori passano costantemente da un processo all'altro per eseguirli contemporaneamente o almeno agire come se lo stessero facendo. La CPU può interrompere un processo prima che sia stato completato e riprendere un processo diverso. Il sistema operativo controlla la gestione di questi processi.



Ad esempio, l'algoritmo Round Robin, uno degli algoritmi di commutazione più semplici, funziona come segue:

  Un diagramma che mostra 3 processi in coda, in sospensione, 1 processo attivo che la CPU è attualmente in esecuzione

In genere, questo algoritmo consente a ciascun processo di essere eseguito per periodi di tempo molto piccoli, come determinato dal sistema operativo. Ad esempio, questo potrebbe essere un periodo di due microsecondi.





La CPU prende ogni processo a turno ed esegue comandi che verranno eseguiti per due microsecondi. Quindi continua con il processo successivo, indipendentemente dal fatto che quello attuale sia terminato o meno. Pertanto, dal punto di vista di un utente finale, sembra che più di un processo sia in esecuzione contemporaneamente. Tuttavia, quando guardi dietro le quinte, la CPU sta ancora facendo le cose in ordine.

A proposito, come mostra il diagramma sopra, l'algoritmo Round Robin non ha alcuna nozione di ottimizzazione o priorità di elaborazione. Di conseguenza, è un metodo piuttosto rudimentale che è usato raramente nei sistemi reali.





Ora, per capire meglio tutto questo, immagina che due thread siano in esecuzione. Se i thread accedono a una variabile comune, potrebbe verificarsi una race condition.

Un'applicazione Web di esempio e una condizione di gara

Dai un'occhiata alla semplice app Flask qui sotto per riflettere su un esempio concreto di tutto ciò che hai letto finora. Lo scopo di questa applicazione è gestire le transazioni di denaro che avverranno sul web. Salva quanto segue in un file chiamato soldi.py :

from flask import Flask 
from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)

class Account(db.Model):
id = db.Column(db.Integer, primary_key = True)
amount = db.Column(db.String(80), unique = True)

def __init__(self, count):
self.amount = amount

def __repr__(self):
return '' % self.amount

@app.route("/")
def hi():
account = Account.query.get(1) # There is only one wallet.
return "Total Money = {}".format(account.amount)

@app.route("/send/")
def send(amount):
account = Account.query.get(1)

if int(account.amount) < amount:
return "Insufficient balance. Reset money with /reset!)"

account.amount = int(account.amount) - amount
db.session.commit()
return "Amount sent = {}".format(amount)

@app.route("/reset")
def reset():
account = Account.query.get(1)
account.amount = 5000
db.session.commit()
return "Money reset."

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

Per eseguire questo codice, dovrai creare un record nella tabella dei conti e continuare le transazioni su questo record. Come puoi vedere nel codice, questo è un ambiente di test, quindi effettua transazioni rispetto al primo record nella tabella.

from money import db 
db.create_all()
from money import Account
account = Account(5000)
db.session.add(account)
db.session.commit()

Ora hai creato un account con un saldo di $ 5.000. Infine, esegui il codice sorgente sopra usando il comando seguente, a condizione che tu abbia installato i pacchetti Flask e Flask-SQLAlchemy:

python money.py 

Quindi hai l'applicazione Web Flask che esegue un semplice processo di estrazione. Questa applicazione può eseguire le seguenti operazioni con i collegamenti di richiesta GET. Poiché Flask viene eseguito sulla porta 5000 per impostazione predefinita, l'indirizzo a cui si accede è 127.0.0.1:5000/ . L'app fornisce i seguenti endpoint:

come inoltrare un testo su iphone
  • 127.0.0.1:5000/ visualizza il saldo attuale.
  • 127.0.0.1:5000/invio/{importo} sottrae importo dal conto.
  • 127.0.0.1:5000/ripristinare reimposta l'account a $ 5.000.

Ora, in questa fase, puoi esaminare come si verifica la vulnerabilità della race condition.

come velocizzare Windows 10 per i giochi?

Probabilità di una vulnerabilità legata a una condizione di razza

L'applicazione web di cui sopra contiene una possibile vulnerabilità di race condition.

Immagina di avere $ 5.000 per iniziare e di creare due diverse richieste HTTP che invieranno $ 1. Per questo, puoi inviare due diverse richieste HTTP al link 127.0.0.1:5000/invia/1 . Supponiamo che, non appena il server web elabora la prima richiesta, la CPU interrompe questo processo ed elabora la seconda richiesta. Ad esempio, il primo processo potrebbe interrompersi dopo l'esecuzione della seguente riga di codice:

account.amount = int(account.amount) - amount 

Questo codice ha calcolato un nuovo totale ma non ha ancora salvato il record nel database. Quando inizia la seconda richiesta, eseguirà lo stesso calcolo, sottraendo $ 1 dal valore nel database — $ 5.000 — e memorizzando il risultato. Quando il primo processo riprende, memorizzerà il proprio valore, $ 4.999, che non rifletterà il saldo del conto più recente.

Quindi, due richieste sono state completate e ciascuna avrebbe dovuto sottrarre $ 1 dal saldo del conto, risultando in un nuovo saldo di $ 4.998. Ma, a seconda dell'ordine in cui il server web li elabora, il saldo finale del conto può essere di $ 4.999.

Immagina di inviare 128 richieste per effettuare un trasferimento di $ 1 al sistema di destinazione in un intervallo di tempo di cinque secondi. Come risultato di questa transazione, l'estratto conto previsto sarà di $ 5.000 - $ 128 = $ 4.875. Tuttavia, a causa delle condizioni della gara, il saldo finale potrebbe variare tra $ 4.875 e $ 4.999.

I programmatori sono uno dei componenti più importanti della sicurezza

In un progetto software, come programmatore, hai alcune responsabilità. L'esempio sopra era per una semplice applicazione di trasferimento di denaro. Immagina di lavorare a un progetto software che gestisce un conto bancario o il back-end di un grande sito di e-commerce.

Devi avere familiarità con tali vulnerabilità in modo che il programma che hai scritto per proteggerle sia privo di vulnerabilità. Ciò richiede una forte responsabilità.

Una vulnerabilità di race condition è solo una di queste. Indipendentemente dalla tecnologia che utilizzi, devi fare attenzione alle vulnerabilità nel codice che scrivi. Una delle abilità più importanti che puoi acquisire come programmatore è la familiarità con la sicurezza del software.