Pembaca seperti Anda membantu mendukung MUO. Saat Anda melakukan pembelian menggunakan tautan di situs kami, kami dapat memperoleh komisi afiliasi.

Kondisi balapan terjadi ketika dua operasi harus dilakukan dalam urutan tertentu, tetapi keduanya dapat berjalan dalam urutan yang berlawanan.

Misalnya, dalam aplikasi multithreaded, dua thread terpisah dapat mengakses variabel umum. Akibatnya, jika satu utas mengubah nilai variabel, utas lainnya mungkin masih menggunakan versi lama, mengabaikan nilai terbaru. Ini akan menyebabkan hasil yang tidak diinginkan.

Untuk lebih memahami model ini, alangkah baiknya untuk mempelajari proses perpindahan prosesor secara dekat.

Bagaimana Prosesor Mengalihkan Proses

Sistem operasi modern dapat menjalankan lebih dari satu proses secara bersamaan, disebut multitasking. Ketika Anda melihat proses ini dalam hal siklus eksekusi CPU, Anda mungkin menemukan bahwa multitasking tidak benar-benar ada.

Alih-alih, prosesor terus-menerus berpindah antar proses untuk menjalankannya secara bersamaan atau setidaknya bertindak seolah-olah mereka melakukannya. CPU dapat menghentikan proses sebelum selesai, dan melanjutkan proses yang berbeda. Sistem operasi mengontrol pengelolaan proses ini.

instagram viewer

Misalnya, algoritma Round Robin, salah satu algoritma switching yang paling sederhana, berfungsi sebagai berikut:

Umumnya, algoritme ini memungkinkan setiap proses berjalan untuk potongan waktu yang sangat kecil, seperti yang ditentukan oleh sistem operasi. Misalnya, ini bisa menjadi periode dua mikrodetik.

CPU mengambil setiap proses secara bergantian dan mengeksekusi perintah yang akan berjalan selama dua mikrodetik. Ini kemudian berlanjut ke proses berikutnya, terlepas dari apakah yang sekarang sudah selesai atau belum. Jadi, dari sudut pandang pengguna akhir, lebih dari satu proses tampaknya berjalan secara bersamaan. Namun, saat Anda melihat ke belakang layar, CPU masih melakukan semuanya secara berurutan.

Omong-omong, seperti yang ditunjukkan diagram di atas, algoritme Round Robin tidak memiliki pengoptimalan atau gagasan prioritas pemrosesan. Akibatnya, ini adalah metode yang belum sempurna yang jarang digunakan dalam sistem nyata.

Sekarang, untuk memahami semua ini dengan lebih baik, bayangkan dua utas sedang berjalan. Jika utas mengakses variabel umum, kondisi balapan mungkin muncul.

Contoh Aplikasi Web dan Kondisi Ras

Lihat aplikasi Flask sederhana di bawah ini untuk merefleksikan contoh konkret dari semua yang telah Anda baca sejauh ini. Tujuan dari aplikasi ini adalah untuk mengelola transaksi uang yang akan dilakukan di web. Simpan yang berikut ini dalam file bernama money.py:

dari labu impor Labu
dari flask.ext.sqlalchemy impor SQLAlkimia

aplikasi = Labu (__nama__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy (aplikasi)

kelasAkun(db. Model):
id = db. Kolom (db. Bilangan bulat, kunci_utama = BENAR)
jumlah = db. Kolom (db. Rangkaian(80), unik = BENAR)

def__init__(diri, hitung):
diri.jumlah = jumlah

def__repr__(diri sendiri):
kembali '' % diri.jumlah

@aplikasi.rute("/")
defHai():
akun = Akun.query.get(1) # Hanya ada satu dompet.
kembali "Total Uang = {}".format (account.amount)

@aplikasi.rute("/kirim/")
defmengirim(jumlah):
akun = Akun.query.get(1)

jika int (akun.jumlah) kembali "Kekurangan saldo. Setel ulang uang dengan /reset!)"

akun.jumlah = int (akun.jumlah) - jumlah
db.session.commit()
kembali "Jumlah terkirim = {}".format (jumlah)

@aplikasi.rute("/reset")
defmengatur ulang():
akun = Akun.query.get(1)
akun.jumlah = 5000
db.session.commit()
kembali "Uang disetel ulang."

jika __nama__ == "__main__":
app.secret_key = 'heLLoTHisIsSeCReTKey!'
aplikasi.jalankan()

Untuk menjalankan kode ini, Anda harus membuat catatan di tabel akun dan melanjutkan transaksi melalui catatan ini. Seperti yang Anda lihat di kode, ini adalah lingkungan pengujian, sehingga melakukan transaksi terhadap catatan pertama dalam tabel.

dari uang impor db
db.buat_semua()
dari uang impor Akun
akun = Akun (5000)
db.sidang.menambahkan(akun)
db.sidang.melakukan()

Anda sekarang telah membuat akun dengan saldo $5.000. Terakhir, jalankan kode sumber di atas menggunakan perintah berikut, asalkan Anda telah menginstal paket Flask dan Flask-SQLAlchemy:

pythonuang.py

Jadi Anda memiliki aplikasi web Flask yang melakukan proses ekstraksi sederhana. Aplikasi ini dapat melakukan operasi berikut dengan tautan permintaan GET. Karena Flask berjalan pada port 5000 secara default, alamat tempat Anda mengaksesnya adalah 127.0.0.1:5000/. Aplikasi ini menyediakan titik akhir berikut:

  • 127.0.0.1:5000/ menampilkan saldo saat ini.
  • 127.0.0.1:5000/kirim/{jumlah} mengurangi jumlah dari akun.
  • 127.0.0.1:5000/reset menyetel ulang akun menjadi $5.000.

Nah, pada tahap ini, Anda bisa meneliti bagaimana kerentanan kondisi ras terjadi.

Probabilitas Kerentanan Kondisi Ras

Aplikasi web di atas berisi kemungkinan kerentanan kondisi balapan.

Bayangkan Anda memiliki $5.000 untuk memulai dan membuat dua permintaan HTTP berbeda yang akan mengirimkan $1. Untuk ini, Anda dapat mengirim dua permintaan HTTP berbeda ke tautan 127.0.0.1:5000/kirim/1. Asumsikan bahwa, segera setelah server web memproses permintaan pertama, CPU menghentikan proses ini dan memproses permintaan kedua. Misalnya, proses pertama mungkin terhenti setelah menjalankan baris kode berikut:

akun.jumlah = int(akun.jumlah) - jumlah

Kode ini telah menghitung total baru tetapi belum menyimpan catatan di database. Ketika permintaan kedua dimulai, itu akan melakukan perhitungan yang sama, mengurangkan $1 dari nilai dalam database—$5.000—dan menyimpan hasilnya. Saat proses pertama dilanjutkan, proses tersebut akan menyimpan nilainya sendiri—$4.999—yang tidak akan mencerminkan saldo akun terbaru.

Jadi, dua permintaan telah selesai, dan masing-masing harus mengurangi $1 dari saldo akun, menghasilkan saldo baru sebesar $4.998. Namun, bergantung pada urutan server web memprosesnya, saldo akhir akun bisa menjadi $4.999.

Bayangkan Anda mengirim 128 permintaan untuk melakukan transfer $1 ke sistem target dalam jangka waktu lima detik. Sebagai hasil dari transaksi ini, laporan akun yang diharapkan adalah $5.000 - $128 = $4.875. Namun, karena kondisi balapan, saldo akhir mungkin bervariasi antara $4.875 dan $4.999.

Programmer Adalah Salah Satu Komponen Keamanan Yang Paling Penting

Dalam proyek perangkat lunak, sebagai programmer, Anda memiliki beberapa tanggung jawab. Contoh di atas adalah untuk aplikasi transfer uang sederhana. Bayangkan mengerjakan proyek perangkat lunak yang mengelola rekening bank atau backend situs e-niaga besar.

Anda harus terbiasa dengan kerentanan tersebut sehingga program yang Anda tulis untuk melindunginya bebas dari kerentanan. Ini membutuhkan tanggung jawab yang kuat.

Kerentanan kondisi ras hanyalah salah satunya. Apa pun teknologi yang Anda gunakan, Anda harus berhati-hati terhadap kerentanan dalam kode yang Anda tulis. Salah satu keterampilan paling penting yang dapat Anda peroleh sebagai programmer adalah mengetahui keamanan perangkat lunak.