خبر و ترفند روز

خبر و ترفند های روز را اینجا بخوانید!

آسیب پذیری شرایط مسابقه چیست؟

فهمیدن شرایط مسابقه ممکن است دشوار باشد، اما درک مفاهیم آنها بسیار مهم است.

شرایط مسابقه زمانی اتفاق می‌افتد که دو عملیات باید به ترتیب خاصی انجام شوند، اما ممکن است در جهت مخالف اجرا شوند.

به عنوان مثال، در یک برنامه چند رشته ای، دو رشته مجزا ممکن است به یک متغیر مشترک دسترسی داشته باشند. در نتیجه، اگر یک رشته مقدار متغیر را تغییر دهد، دیگری ممکن است همچنان از نسخه قدیمی استفاده کند و جدیدترین مقدار را نادیده بگیرد. این باعث نتایج نامطلوب خواهد شد.

برای درک بهتر این مدل، خوب است که فرآیند تعویض فرآیند پردازنده را از نزدیک بررسی کنیم.

چگونه یک پردازنده فرآیندها را تغییر می دهد

سیستم عامل های مدرن می توانند بیش از یک فرآیند را به طور همزمان اجرا کنند که به آن مولتی تسکینگ گفته می شود. وقتی به این فرآیند از نظر چرخه اجرای CPU نگاه می کنید، ممکن است متوجه شوید که مولتی تسکینگ واقعا وجود ندارد.

در عوض، پردازنده‌ها دائماً بین فرآیندها سوئیچ می‌کنند تا آنها را به طور همزمان اجرا کنند یا حداقل طوری عمل می‌کنند که انگار این کار را انجام می‌دهند. CPU ممکن است یک فرآیند را قبل از اتمام آن قطع کند و یک فرآیند دیگر را از سر بگیرد. سیستم عامل مدیریت این فرآیندها را کنترل می کند.

به عنوان مثال، الگوریتم Round Robin، یکی از ساده ترین الگوریتم های سوئیچینگ، به صورت زیر عمل می کند:

نموداری که 3 پردازش در صف و خواب را نشان می دهد 1 فرآیند فعال که CPU در حال حاضر در حال اجرا است.

به طور کلی، این الگوریتم به هر فرآیند اجازه می دهد تا برای بخش های بسیار کمی از زمان، همانطور که سیستم عامل تعیین می کند، اجرا شود. به عنوان مثال، این می تواند یک دوره دو میکروثانیه باشد.

CPU هر فرآیند را به نوبت انجام می دهد و دستوراتی را اجرا می کند که برای دو میکروثانیه اجرا می شوند. سپس بدون در نظر گرفتن اینکه روند فعلی تمام شده است یا خیر، به روند بعدی ادامه می دهد. بنابراین، از دیدگاه یک کاربر نهایی، به نظر می رسد که بیش از یک فرآیند به طور همزمان در حال اجرا باشد. با این حال، هنگامی که به پشت صحنه نگاه می کنید، CPU هنوز کارها را به ترتیب انجام می دهد.

مطلب مرتبط:   5 API مدرن برای افزایش شارژ برنامه وب شما

به هر حال، همانطور که نمودار بالا نشان می دهد، الگوریتم Round Robin فاقد هرگونه ایده اولویت پردازشی یا بهینه سازی است. در نتیجه، این یک روش نسبتا ابتدایی است که به ندرت در سیستم های واقعی استفاده می شود.

حال، برای درک بهتر همه اینها، تصور کنید که دو رشته در حال اجرا هستند. اگر thread ها به یک متغیر مشترک دسترسی پیدا کنند، ممکن است یک شرط مسابقه ایجاد شود.

یک نمونه برنامه وب و شرایط مسابقه

برنامه ساده Flask زیر را بررسی کنید تا در مورد یک مثال عینی از همه چیزهایی که تاکنون خوانده اید فکر کنید. هدف این اپلیکیشن مدیریت تراکنش های پولی است که در وب انجام می شود. موارد زیر را در فایلی به نام money.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()

برای اجرای این کد، باید یک رکورد در جدول حساب ایجاد کنید و تراکنش ها را روی این رکورد ادامه دهید. همانطور که در کد مشاهده می کنید، این یک محیط آزمایشی است، بنابراین تراکنش ها را بر اساس اولین رکورد جدول انجام می دهد.

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

اکنون یک حساب کاربری با موجودی 5000 دلار ایجاد کرده اید. در نهایت، کد منبع بالا را با استفاده از دستور زیر اجرا کنید، مشروط بر اینکه بسته های Flask و Flask-SQLAlchemy را نصب کرده باشید:

python money.py

بنابراین شما برنامه وب Flask را دارید که یک فرآیند استخراج ساده را انجام می دهد. این برنامه می تواند عملیات زیر را با پیوندهای درخواست GET انجام دهد. از آنجایی که Flask به طور پیش فرض روی پورت 5000 اجرا می شود، آدرسی که به آن دسترسی دارید 127.0.0.1:5000/ است. این برنامه نقاط پایانی زیر را ارائه می دهد:

  • 127.0.0.1:5000/ موجودی فعلی را نمایش می دهد.
  • 127.0.0.1:5000/send/{amount} مقدار را از حساب کم می کند.
  • 127.0.0.1:5000/reset حساب را به 5000 دلار بازنشانی می کند.
مطلب مرتبط:   آموزش ایجاد کلاس در سی شارپ

اکنون، در این مرحله، می‌توانید نحوه ایجاد آسیب‌پذیری شرط نژاد را بررسی کنید.

احتمال آسیب پذیری شرایط مسابقه

برنامه وب فوق حاوی یک آسیب پذیری احتمالی شرط نژاد است.

تصور کنید 5000 دلار برای شروع دارید و دو درخواست مختلف HTTP ایجاد می کنید که 1 دلار ارسال می کند. برای این کار می توانید دو درخواست مختلف HTTP را به لینک 127.0.0.1:5000/send/1 ارسال کنید. فرض کنید، به محض اینکه وب سرور درخواست اول را پردازش می کند، CPU این فرآیند را متوقف می کند و درخواست دوم را پردازش می کند. به عنوان مثال، اولین فرآیند ممکن است پس از اجرای خط کد زیر متوقف شود:

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

این کد یک کل جدید را محاسبه کرده است اما هنوز رکورد را در پایگاه داده ذخیره نکرده است. هنگامی که درخواست دوم شروع می شود، همان محاسبه را انجام می دهد و 1 دلار را از مقدار موجود در پایگاه داده کم می کند – 5000 دلار – و نتیجه را ذخیره می کند. هنگامی که اولین فرآیند از سر گرفته می شود، ارزش خود را ذخیره می کند – 4999 دلار – که منعکس کننده آخرین موجودی حساب نیست.

بنابراین، دو درخواست تکمیل شده است، و هر کدام باید 1 دلار از موجودی حساب کم می‌کردند که منجر به موجودی جدید 4998 دلار می‌شد. اما بسته به ترتیبی که وب سرور آنها را پردازش می کند، مانده حساب نهایی می تواند 4999 دلار باشد.

تصور کنید که 128 درخواست برای انتقال 1 دلار به سیستم مورد نظر در بازه زمانی پنج ثانیه ارسال می کنید. در نتیجه این تراکنش، صورت حساب مورد انتظار 5000 دلار – 128 دلار = 4875 دلار خواهد بود. با این حال، با توجه به شرایط مسابقه، موجودی نهایی ممکن است بین 4875 تا 4999 دلار متفاوت باشد.

مطلب مرتبط:   راهنمای کار با سازه های زنگ

برنامه نویسان یکی از مهم ترین اجزای امنیت هستند

در یک پروژه نرم افزاری، شما به عنوان یک برنامه نویس، مسئولیت های کمی دارید. مثال بالا برای یک برنامه انتقال پول ساده بود. تصور کنید که روی یک پروژه نرم افزاری کار می کنید که یک حساب بانکی یا پشتیبان یک سایت تجارت الکترونیک بزرگ را مدیریت می کند.

شما باید با چنین آسیب پذیری هایی آشنا باشید تا برنامه ای که برای محافظت از آنها نوشته اید عاری از آسیب پذیری باشد. این مستلزم یک مسئولیت قوی است.

آسیب پذیری شرایط نژادی تنها یکی از آنهاست. مهم نیست از چه فناوری استفاده می کنید، باید مراقب آسیب پذیری های کدی که می نویسید باشید. یکی از مهم ترین مهارت هایی که می توانید به عنوان یک برنامه نویس کسب کنید، آشنایی با امنیت نرم افزار است.