आप जैसे पाठक MUO का समर्थन करने में मदद करते हैं। जब आप हमारी साइट पर लिंक का उपयोग करके खरीदारी करते हैं, तो हम संबद्ध कमीशन अर्जित कर सकते हैं।

दौड़ की स्थिति तब होती है जब दो ऑपरेशन एक विशिष्ट क्रम में होने चाहिए, लेकिन वे विपरीत क्रम में चल सकते हैं।

उदाहरण के लिए, एक बहुप्रचारित अनुप्रयोग में, दो अलग-अलग धागे एक सामान्य चर का उपयोग कर सकते हैं। परिणामस्वरूप, यदि एक थ्रेड चर के मान को बदलता है, तो दूसरा अभी भी पुराने संस्करण का उपयोग कर सकता है, नवीनतम मान को अनदेखा कर सकता है। इससे अवांछनीय परिणाम होंगे।

इस मॉडल को बेहतर ढंग से समझने के लिए, प्रोसेसर की प्रोसेस स्विचिंग प्रक्रिया की बारीकी से जांच करना अच्छा होगा।

कैसे एक प्रोसेसर प्रक्रियाओं को स्विच करता है

आधुनिक ऑपरेटिंग सिस्टम एक साथ एक से अधिक प्रक्रियाएँ चला सकता है, जिसे मल्टीटास्किंग कहा जाता है। जब आप इस प्रक्रिया को के संदर्भ में देखते हैं सीपीयू का निष्पादन चक्र, आप पा सकते हैं कि मल्टीटास्किंग वास्तव में मौजूद नहीं है।

इसके बजाय, प्रोसेसर उन्हें एक साथ चलाने के लिए या कम से कम कार्य करने के लिए प्रक्रियाओं के बीच लगातार स्विच कर रहे हैं जैसे कि वे ऐसा कर रहे हैं। सीपीयू एक प्रक्रिया को पूरा होने से पहले बाधित कर सकता है और एक अलग प्रक्रिया को फिर से शुरू कर सकता है। ऑपरेटिंग सिस्टम इन प्रक्रियाओं के प्रबंधन को नियंत्रित करता है।

उदाहरण के लिए, राउंड रॉबिन एल्गोरिथम, सबसे सरल स्विचिंग एल्गोरिदम में से एक, निम्नानुसार काम करता है:

आम तौर पर, यह एल्गोरिथ्म प्रत्येक प्रक्रिया को बहुत कम समय के लिए चलाने की अनुमति देता है, जैसा कि ऑपरेटिंग सिस्टम निर्धारित करता है। उदाहरण के लिए, यह दो माइक्रोसेकंड की अवधि हो सकती है।

सीपीयू प्रत्येक प्रक्रिया को बारी-बारी से लेता है और दो माइक्रोसेकंड के लिए चलने वाले आदेशों को निष्पादित करता है। यह तब अगली प्रक्रिया के लिए जारी रहता है, भले ही वर्तमान प्रक्रिया समाप्त हो गई हो या नहीं। इस प्रकार, एक एंड-यूज़र के दृष्टिकोण से, एक से अधिक प्रक्रियाएँ एक साथ चलती हुई प्रतीत होती हैं। हालाँकि, जब आप पर्दे के पीछे देखते हैं, तो सीपीयू अभी भी क्रम में काम कर रहा है।

वैसे, जैसा कि ऊपर दिए गए आरेख में दिखाया गया है, राउंड रॉबिन एल्गोरिथ्म में किसी भी अनुकूलन या प्रसंस्करण प्राथमिकता धारणा का अभाव है। नतीजतन, यह एक बल्कि प्राथमिक तरीका है जो वास्तविक प्रणालियों में शायद ही कभी उपयोग किया जाता है।

अब, यह सब बेहतर समझने के लिए, कल्पना कीजिए कि दो धागे चल रहे हैं। यदि थ्रेड्स एक सामान्य चर का उपयोग करते हैं, तो दौड़ की स्थिति उत्पन्न हो सकती है।

एक उदाहरण वेब अनुप्रयोग और रेस स्थिति

अब तक आपने जो कुछ भी पढ़ा है, उसके ठोस उदाहरण पर विचार करने के लिए नीचे दिया गया सरल फ्लास्क ऐप देखें। इस एप्लिकेशन का उद्देश्य वेब पर होने वाले पैसे के लेन-देन का प्रबंधन करना है। निम्नलिखित को नाम की फाइल में सेव करें money.py:

से फ्लास्क आयात फ्लास्क
से कुप्पी.ext.sqlalchemy आयात SQLAlchemy

ऐप = फ्लास्क (__name__)
app.config ['SQLALCHEMY_DATABASE_URI'] = 'sqlite: ////tmp/test.db'
डीबी = SQLAlchemy (ऐप)

कक्षाखाता(डीबी. नमूना):
आईडी = डीबी. कॉलम (डीबी। पूर्णांक, प्राथमिक_की = सत्य)
राशि = डीबी। कॉलम (डीबी। डोरी(80), अद्वितीय = सत्य)

डीईएफ़__इस में__(स्वयं, गिनती):
स्वयं राशि = राशि

डीईएफ़__repr__(खुद):
वापस करना '' % स्व.राशि

@app.route("/")
डीईएफ़नमस्ते():
खाता = Account.query.get(1) # केवल एक बटुआ है।
वापस करना "कुल धन = {}" स्वरूप (खाता.राशि)

@app.route("/send/")
डीईएफ़भेजना(मात्रा):
खाता = Account.query.get(1)

अगर int (account.amount) वापस करना "अपर्याप्त शेषराशि। पैसा रीसेट करें साथ /reset!)"

account.amount = int (account.amount) - राशि
db.session.commit ()
वापस करना "भेजी गई राशि = {}"। प्रारूप (राशि)

@app.route("/reset")
डीईएफ़रीसेट():
खाता = Account.query.get(1)
खाता राशि = 5000
db.session.commit ()
वापस करना "मनी रीसेट।"

अगर __नाम__ == "__मुख्य__":
app.secret_key = 'heLLoTHisIsSeCReTKey!'
ऐप.रन ()

इस कोड को चलाने के लिए, आपको खाता तालिका में एक रिकॉर्ड बनाना होगा और इस रिकॉर्ड पर लेन-देन जारी रखना होगा। जैसा कि आप कोड में देख सकते हैं, यह एक परीक्षण वातावरण है, इसलिए यह तालिका में पहले रिकॉर्ड के विरुद्ध लेन-देन करता है।

से धन आयात डाटाबेस
डाटाबेस.create_all()
से धन आयात खाता
खाता = खाता (5000)
डाटाबेस।सत्र।जोड़ना(खाता)
डाटाबेस।सत्र।वादा करना()

अब आपने $5,000 की शेष राशि के साथ एक खाता बना लिया है। अंत में, उपरोक्त स्रोत कोड को निम्नलिखित कमांड का उपयोग करके चलाएं, बशर्ते आपके पास फ्लास्क और फ्लास्क-स्क्लाक्लेमी पैकेज स्थापित हों:

अजगरधन.py

तो आपके पास फ्लास्क वेब एप्लिकेशन है जो एक सरल निष्कर्षण प्रक्रिया करता है। यह एप्लिकेशन GET अनुरोध लिंक के साथ निम्नलिखित कार्य कर सकता है। चूंकि फ्लास्क डिफ़ॉल्ट रूप से 5000 पोर्ट पर चलता है, जिस पते पर आप इसे एक्सेस करते हैं वह है 127.0.0.1:5000/. ऐप निम्नलिखित समापन बिंदु प्रदान करता है:

  • 127.0.0.1:5000/ वर्तमान संतुलन प्रदर्शित करता है।
  • 127.0.0.1:5000/भेजें/{राशि} खाते से राशि काट लेता है।
  • 127.0.0.1:5000/रीसेट खाते को $5,000 पर रीसेट करता है।

अब, इस स्तर पर, आप जांच कर सकते हैं कि दौड़ की स्थिति भेद्यता कैसे होती है।

दौड़ की स्थिति भेद्यता की संभावना

उपरोक्त वेब एप्लिकेशन में एक संभावित दौड़ स्थिति भेद्यता शामिल है।

कल्पना करें कि आपके पास शुरू करने के लिए $5,000 हैं और दो अलग-अलग HTTP अनुरोध बनाएं जो $1 भेजेंगे। इसके लिए आप लिंक पर दो अलग-अलग HTTP रिक्वेस्ट भेज सकते हैं 127.0.0.1:5000/भेजें/1. मान लीजिए, जैसे ही वेब सर्वर पहले अनुरोध को संसाधित करता है, CPU इस प्रक्रिया को रोक देता है और दूसरे अनुरोध को संसाधित करता है। उदाहरण के लिए, कोड की निम्न पंक्ति चलाने के बाद पहली प्रक्रिया रुक सकती है:

खाता राशि = int यहाँ(खाता। राशि) - राशि

इस कोड ने एक नए योग की गणना की है लेकिन अभी तक डेटाबेस में रिकॉर्ड को सहेजा नहीं है। जब दूसरा अनुरोध शुरू होता है, तो यह समान गणना करेगा, डेटाबेस में मूल्य से $ 1 घटाकर - $ 5,000 - और परिणाम संग्रहीत करेगा। जब पहली प्रक्रिया फिर से शुरू होती है, तो यह अपना मूल्य—$4,999—संग्रहित कर लेगी—जो सबसे हालिया खाता शेष को प्रतिबिंबित नहीं करेगा।

इसलिए, दो अनुरोध पूरे हो गए हैं, और प्रत्येक को खाते की शेष राशि से $1 घटाना चाहिए, जिसके परिणामस्वरूप $4,998 की एक नई शेष राशि प्राप्त होगी। लेकिन, जिस क्रम में वेब सर्वर उन्हें संसाधित करता है, उसके आधार पर, अंतिम खाता शेष $4,999 हो सकता है।

कल्पना करें कि आप पांच सेकंड की समय सीमा में लक्ष्य प्रणाली में $1 हस्तांतरण करने के लिए 128 अनुरोध भेजते हैं। इस लेन-देन के परिणामस्वरूप, खाते का अपेक्षित विवरण $5,000 - $128 = $4,875 होगा। हालांकि, दौड़ की स्थिति के कारण, अंतिम शेष राशि $4,875 और $4,999 के बीच कुछ भी भिन्न हो सकती है।

प्रोग्रामर सुरक्षा के सबसे महत्वपूर्ण घटकों में से एक हैं

एक सॉफ्टवेयर प्रोजेक्ट में, एक प्रोग्रामर के रूप में, आपकी काफी कुछ जिम्मेदारियां होती हैं। उपरोक्त उदाहरण एक साधारण मनी ट्रांसफर एप्लिकेशन के लिए था। किसी ऐसे सॉफ़्टवेयर प्रोजेक्ट पर काम करने की कल्पना करें जो किसी बैंक खाते या किसी बड़ी ई-कॉमर्स साइट के बैकएंड का प्रबंधन करता हो।

आपको ऐसी कमजोरियों से परिचित होना चाहिए ताकि आपने उन्हें बचाने के लिए जो कार्यक्रम लिखा है वह कमजोरियों से मुक्त हो। इसके लिए एक मजबूत जिम्मेदारी की जरूरत है।

दौड़ की स्थिति भेद्यता उनमें से केवल एक है। कोई फर्क नहीं पड़ता कि आप किस तकनीक का उपयोग करते हैं, आपको अपने द्वारा लिखे गए कोड में कमजोरियों पर ध्यान देने की आवश्यकता है। एक प्रोग्रामर के रूप में आप जो सबसे महत्वपूर्ण कौशल हासिल कर सकते हैं, वह सॉफ्टवेयर सुरक्षा से परिचित होना है।