اگر شما یک توسعه دهنده وب هستید، احتمالا تا به حال برای ساختن یک سیستم حساب کاربری اقدام کرده اید. مهم ترین جنبه یک سیستم حساب کاربری نحوه محافظت از کلمات عبور می باشد. پایگاه های داده حساب کاربری غالبا هک می شوند، بنابراین شما باید برای حفاظت از کلمات عبور کاربران خود بهترین راه را انتخاب کنید .(رمز عبور + مقداری نمک)...

بسیاری از ایده ها و تصورات غلط متناقض در مورد نحوه انجام هش رمز عبور وجود دارد ، احتمالا به علت فراوانی اطلاعات غلط در وب ! هش کردن رمز عبور یکی از آن چیزهایی است که خیلی ساده است، اما هنوز بسیاری از مردم در این مورد دچار اشتباه می شوند. در این مقاله امیدوارم نه تنها راه درست اینکار ! اما راهی برای بهتر شدن نحوه هش را بررسی کنیم .

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

مشکل ذخیره سازی کلمات عبور در حال حاضر حل شده است. می توانید به phpass مراجعه کنید .

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

1
2
3
4
5
6
hash("hello") =
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hbllo") =
58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366
hash("waltz") =
c0e81794384491161f1777c232bc6bd9ec38f616560b120fda8e90f383853542

الگوریتم های هش توابع یک طرفه هستند. آنها هر مقدار از داده ها را به طول ثابت غیر برگشتی تبدیل می کنند. همچنین حتی با کمترین تغییرات ورودی ، رشته هش نهایی کاملا متفاوت است (مثال بالا را ببینید). این فوق العاده است برای محافظت از کلمات عبور ، چرا که ما می خواهیم کلمات عبور در فرم ها را ذخیره و بعد از بررسی و مطابقت با رمز عبور کاربر از آن استفاده نماییم.

گردش کار به طور کلی برای ثبت نام حساب و تصدیق هویت در یک سیستم حساب کاربری مبتنی بر هش به شرح زیر است:

1 - کاربر یک حساب کاربری ایجاد می کند.

2 - رمز عبور هش شده در پایگاه داده ذخیره می شود. در هیچ نقطه از فرم ثبت نام (کلاینت ساید) سمت کاربر رمز عبور هش و یا دچار تغییرات نمی شود .

3 - هنگامی که کاربر اقدام به ورود می کند، رمز عبور وارد شده توسط کاربر با رمز عبورهش شده مورد بررسی قرار می گیرد و در صورت تصدیق هر دو (بازیابی از پایگاه داده) قادر به ورود می باشد.

4 - اگر رشته ورودی و رمز عبور هش شده با هم مطابقت داشته باشد، به کاربر دسترسی داده میشود. اگر نه به کاربر گفته میشود ورود نا معتبر است.

5 - مراحل 3 و 4 برای ورود به حساب کاربری در هر زمان تکرار می شود.

در مرحله 4، هیچ گاه به کاربر نگویید رمز عبور یا نام حساب کاربری وارد شده اشتباه است . همیشه در هر حالت ورود اشتباه رمز یا نام کاربری یک پیام عمومی مانند نمایش "نام کاربری یا رمز عبور اشتباه است." را نمایش دهید . این مانع از حمله از شمارش نام کاربری معتبر بدون دانستن کلمه عبور در سیستم شما می شود .

لازم به ذکر است که توابع هش مورد استفاده برای حفاظت از کلمات عبور با توابعی که در کلاس های عمومی پایگاه داده آموزش دیده اید یکسان نیستند. توابع هش استفاده شده برای پیاده سازی ساختمان داده مانند جداول برای طراحی سریع به کار می رود، اما ایمن نیست. تنها توابع هش رمزنگاری (کرایپتوگراف) برای پیاده سازی رمز عبور مانند SHA256، SHA512، RIPEMD، و WHIRLPOOL مورد استفاده قرار می گیرد.

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

در این قسمت به برخی از حملات رایج مورد استفاده برای کرک هش رمز عبور ساده می پردازیم.

چگونه هش کرک می شود.

دیکشنری و حملات Brute Force

چگونه هش کرک می شود

ساده ترین راه برای شکستن یک رشته هش حدس زدن رمز عبور است ، هش کردن هر حدس، و چک کردن : اگر هش برابر است با هشی که کرک شده. در صورت برابری رشته هش ، "حدس" کلمه عبور است. دو راه رایج برای حدس زدن کلمه عبور حملات دیکشنری و حملات Brute Force هستند.

حملات دیکشنری با استفاده از یک فایل که حاوی کلمات، عبارات، کلمات عبور مشترک، و رشته های دیگر که به احتمال زیاد به عنوان رمز عبور مورد استفاده قرار می گیرند است. هر کلمه در فایل هش شده است، و هش آن با هش رمز عبور مقایسه می شود. اگر آنها مطابقت داشته باشند، که کلمه رمز عبور است . این فایل مورد استفاده در دیکشنری، با استخراج کلمات از وب سایت های زیادی و حتی از کلمات عبور مورد استفاده در پایگاه داده های واقعی برای تاثیر گذاری بیشتر ساخته شده، به عنوا مثال کلمه " hello " برابر است با " h3110 "

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

1
2
3
4
5
Searching:5f4dcc3b5aa765d61d8327deb882cf99: FOUND: password5
Searching: 6cbe615c106f422d23669b610b564800: not in database
Searching: 630bf032efe4507f2c57b280995925a9: FOUND: letMEin12
Searching: 386f43fab5d096a7a66d67c8f213e5ec: FOUND: mcd0nalds
Searching: d5ec75d5fe70d428685510fae36492d9: FOUND: p@ssw0rd!

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

اگر به ساختار حملات دیکشنری دقت کرده باشید این حملات به این دلیل کار می کنند که دقیقا رمز عبور هش شده با لیست حمله کننده برابر است. اگر کاربری در سیستم شما رمز عبور 123 داشته باشد، هش رمز عبور شما با هش لیست حمله کننده برابر باشد ؟ پس رمز کاربر شما از دست خواهد رفت .

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

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

در این قسمت، ما به چگونگی استفاده از نمک (salt) می پردازیم .

راه اشتباه : salt کوتاه و یا استفاده مجدد:

شایع ترین اشتباهات استفاده از salt استفاده مجدد از salt مشابه در رشته هش چندگانه، و یا استفاده از salt بیش از حد کوتاه است.

استفاده مجدد از salt

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

salt تصادفی جدید باید در هر زمان که کاربر یک حساب کاربری ایجاد و یا رمز عبور خود را تغییر می دهد تغییر کند. Salt کوتاه

اگر Salt خیلی کوتاه است، مهاجم می تواند یک جدول مراجعه برای هر Salt ممکن ایجاد کند. برای مثال، اگر Salt تنها شامل سه کاراکتر اسکی باشد (95x95x95=857,375) نمک مورد استفاده به دست می آید.

از نام کاربری برای salt استفاده نکنید ، حمله کننده با بررسی نوع رمزنگاری نام کاربری شما می تواند جدولی برای حمله به رمز عبور شما ایجاد کند .

نمک، باید طولانی باشد. یک قانون خوب برای استفاده از نمک این است که به همان اندازه به عنوان خروجی تابع هش مورد استفاده قرار گیرد. به عنوان مثال، خروجی SHA256 256 بیت (32 بایت) است، بنابراین نمک باید حداقل 32 بایت و به صورت تصادفی باشد.

راه اشتباه: استفاده از هش های دوبل

دراین قسمت یکی دیگر از شایع ترین تصورات غلط هش کردن رمز عبور را بررسی می کنیم.

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

در زیر چند نمونه از توابع هش ترکیبی ضعیف که در وب سایت ها و انجمن های مختلف توصیه می شود را مشاهده می کنید :

1
2
3
4
5
md5(sha1(password))
md5(md5(salt) + md5(password))
sha1(sha1(password))
sha1(str_rot13(password + salt))
md5(sha1(md5(md5(password) + sha1(password)) + md5(password)))

از هیچ کدام از موارد بالا استفاده نکنید .

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

یک حمله کننده زمانی که الگوریتم یک رمزنگاری را نداند قادر به حمله نیست ، اما توجه داشته باشید حمله کننده معمولا دسترسی به کد منبع (به خصوص اگر سیستم های مدیریت محتوای متن باز مورد استفاده قرار گرفته شده باشد) خواهد داشت، و با توجه به داشتن چند کلمه عبورهش شده از سیستم هدف، مهندسی معکوس الگوریتم دشوار نیست. این کار ممکن است زمان بیشتری برای محاسبه توابع هش ترکیبی در برگیرد، اما تنها در یک ضریب ثابت کوچک است. استفاده از یک الگوریتم به تنهایی بهتر است اما به درستی (این موارد در ادامه مورد بحث قرار گرفته شده).

اگر شما واقعا می خواهید به استفاده از "توابع هش ترکیبی" مانند HMAC بپردازید، هیچ مشکلی ندارد. اما اگر دلیل شما برای انجام این کار این است که محاسبه هش آهسته تر انجام شود، بخش زیر در مورد کلید کشش را بخوانید .

مقایسه این منافع جزئی به خطرات ناشی از اجرای به طور تصادفی یک تابع هش به طور کامل نا امن و مشکلات ایجاد قابلیت همکاری هش های ترکیبی نمی ارزد . به وضوح بهترین استفاده از یک الگوریتم استاندارد و به خوبی تست شده است.

تصادم (Collision) هش

از آنجا که نقشه توابع هش مقادیر دلخواه از اطلاعات را به یک رشته با طول ثابت تبدیل می کنند، ورودی به همان رشته هش باید وجود داشته باشد. توابع هش رمزنگاری (کرایپتوگراف) به طوری فوق العاده و دشوار برای پیدا کردن طراحی شده اند. از زمان شروع پیدایش "حملات Collision " در توابع هش . به عنوان مثال تابع هش MD5 ، در کدام یک از حملات توابع هش رمزگشایی شد؟

حملات Collision به بررسی احتمال زیاد برای یک رشته دیگر از رمز عبور و نام کاربر با همان هش می پردازد. با این حال، پیدا کردن Collision در حتی یک تابع هش ضعیف مانند MD5 نیاز به مقدار زیادی منابع قدرتمند محاسباتی و اختصاصی دارد، که بسیار بعید است وعملا به صورت "اتفاقی" است.

استفاده از رمز عبور هش با استفاده از MD5 و نمک ، برای تمام اهداف عملی است، فقط به عنوان امن تر شدن اگر آن را با SHA256 و salt مخلوط کنید بهتر است. با این وجود در اینجا بهتر است از چند توابع امن SHA256، SHA512، RIPEMD، یا WHIRLPOOL استفاده کرد.

راه درست: نحوه ایجاد هش مناسب

این قسمت به نحوه هش کردن کلمات عبور می پردازیم. اولین بخش اصول اولیه را پوشش می دهد –(هر چیزی که کاملا ضروری است) . در بخش های بعدی توضیح داده شده که چگونه اصول اولیه می تواند به ایجاد هش بهتر و کرک سخت تر کمک کند.

اصول اولیه : هش + نمک (salt)

هشدار: فقط به خواندن این بخش اکتفا نکنید. شما کاملا باید مسائل را در بخش های بعدی مطالعه کنید که شامل "ساخت رمز عبور و کرک سخت تر است : توابع هش آهسته ".

تا به اینجا با نحوه حمله و شکستن رمز عبور توسط مهاجمین آشنا شدیم و دیدیم رشته های هش ساده به سرعت با استفاده از جداول مراجعه قابل کرک می باشند. ما یاد گرفته ایم که تصادفی هش کردن و استفاده از نمک راه حلی برای این مشکل است.

اما ما چگونه salt تولید کنیم ، و چگونه در رمز عبور استفاده کنیم ؟

نمک باید با استفاده از یک شبه تولید کننده شماره رمز نویسی تصادفی امن (CSPRNG) تولید شود. CSPRNGs بسیار متفاوت تر از از تولید کننده عدد تصادفی عادی، مانند تابع rand() در زبان C می باشد. همانطور که از نام نشان می دهد، CSPRNGs طراحی شده برای رمز نویسی امن، به این معنی که به ارائه سطح بالایی از رندم و کاملا غیر قابل پیش بینی می پردازند. ما نمی خواهیم نمک ما قابل پیش بینی باشد، بنابراین ما باید از CSPRNG استفاده کنیم. در جدول زیر لیست برخی از CSPRNG ها که برای برخی از زبان های برنامه نویسی محبوب وجود دارد مشاهده میکنید.

1
2
3
4
5
6
7
8
Python : os.urandom
C/C++ (Windows API) : CryptGenRandom
Any language on GNU/Linux or Unix : Read from /dev/random or /dev/urandom

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

برای ذخیره رمز عبور

تولید نمک طولانی تصادفی با استفاده از یک CSPRNG.

اضافه کردن نمک به رمز عبور و هش آن با یک تابع استاندارد هش رمزنگاری مانند SHA256.

هر دو نمک و هش را درجدول حساب کاربری ذخیره کنید.

اعتبار سنجی رمز عبور

بازیابی نمک کاربر و هش از پایگاه داده .

اضافه کردن نمک داده شده به کاربر به رمز عبور داده شده و هش آن با استفاده از همان تابع هش.

مقایسه هش رمز عبور داده شده با هش پایگاه داده. اگر آنها مطابقت داشتند، رمز عبور صحیح است. در غیر این صورت، رمز عبور نادرست است.

در پایین این مقاله، نحوه پیاده سازی salt+هش کردن رمز عبور را بررسی می کنیم.

در یک برنامه تحت وب، عملیات هش همیشه سمت سرور انجام می شود

اگر شما در حال نوشتن یک برنامه تحت وب می باشید ، حتی اگر شما در حال هش کلمه عبور کاربر با استفاده از جاوا اسکریپت هستید، شما هنوز هم باید هش را سمت سرور انجام دهید!

مشکل این است که هش های سمت سرویس گیرنده رمز عبور کاربر می باشد. همه کاربران نیاز به انجام تصدیق رمز عبور و نام کارربری خود هستند. اگر شخصی به هر دلیل به هش کاربر دسترسی داشته باشد فرد بدون دانستن رمز عبور قادر به تصدیق احراز هویت از سمت وب سایت شما می شود!

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

هش کردن رمز عبور سمت سرویس گیرنده یک جایگزین برای HTTPS (SSL / TLS) نیست. اگر ارتباط بین مرورگر و سرور ناامن است، مهاجم با استفاده از حملات man-in-the-middle می تواند کد جاوا اسکریپت را دانلود و به حذف قابلیت هش کردن و گرفتن رمز عبور کاربر بپردازد.

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

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

ساخت رمز عبور با قابلیت کرک شدن سخت تر: توابع هش آهسته

نمک تضمین می کند که حمله کننده نتواند از حملات تخصصی مانند جداول مراجعه و جداول رنگین کمان و استفاده برای کرک مجموعه زیادی از رشته های هش به سرعت اقدام کند، اما اینها از اجرا ی حملات دیکشنری و یا حملات brute-force جلوگیری نمی کند. کارت های گرافیک بالا (GPU ها) و سخت افزار سفارشی می تواند میلیاردها رشته هش را در هر ثانیه محاسبه کند، بنابراین این حملات هنوز هم بسیار موثر است. برای اینکه این حملات کمتر موثر باشند، شما می توانید از یک تکنیک شناخته شده (key stretching) کشش کلیدی استفاده کنید.

ایده این است که تابع هش بسیار آهسته عمل کند، به طوری که حتی با یک GPU سریع یا سخت افزار سفارشی، حملات دیکشنری و یا حملات brute-force آهسته انجام شود، اما هنوز هم به اندازه کافی سریع و هیج تاخیری برای کاربرایجاد نکند.

کشش کلیدی قابل اجرا با استفاده از نوع خاصی از CPU-intensive تابع هش است. سعی نکنید به اختراع هش شخصی بپردازید، زیرا هش رمز عبور به تنهایی کافی نیست ، و همچنین احتمالا سخت افزار شما مناسب ایجاد یک هش و تست آن نیست . از یک الگوریتم استاندارد مانند PBKDF2 یا bcrypt استفاده کنید. شما می توانید یک اجرای پی اچ پی از PBKDF2 اینجا پیدا کنید.

این الگوریتم با استفاده از یک فاکتور امنیتی و تعداد تکرار به عنوان آرگومان بهره می برد. این مقدار(value) تعیین می کند چگونه تابع هش آهسته عمل کند. برای نرم افزارهای دسکتاپ و یا اپلیکیشن های تلفن های هوشمند، بهترین راه انتخاب پارامتر اجرای یک معیار کوتاه بر روی دستگاه برای پیدا کردن مقدار (value) مناسب می باشد . که می توانید در کمتر از نیم ثانیه نتیجه را ببینید. به این ترتیب، پس برنامه شما می تواند بدون تجربه کاربری امن شود.

اگر شما از یک کلید کشش (key stretching) هش در برنامه تحت وب استفاده می کنید، آگاه باشید که شما منابع اضافی محاسباتی برای پردازش حجم زیادی از درخواست های احراز هویت لازم دارید و در اینصورت (key stretching) ممکن است برای اجرای حملات اخلال در سرویس (DOS) به وب سایت شما کمک زیادی به مهاجمین کند . من هنوز هم استفاده از (key stretching) را توصیه می کنم ، اما با یک تعداد تکرار پایین تر. شما باید تعداد تکرار را بر اساس منابع خود و نرخ حداکثر درخواست های احراز هویت محاسبه کنید. حملات اخلال در سرویس دهنده را نیز می توان با استفاده از ساخت کد CAPTCHA و احراز کاربر در هر بار جلوگیری کرد (در مقالات آتی به جایگزین های برای کد های کپتچا می پردازیم). همیشه سیستم خود را به گونه ای طراحی کنید که تعداد تکرار بتواند افزایش یافته و یا در آینده کاهش یابد.

اگر شما در مورد بار محاسباتی نگران هستید، اما هنوز هم می خواهید از key stretching در یک برنامه وب استفاده کنید، در نظربگیرید در حال اجرای الگوریتم کلید کشش در مرورگر کاربر با جاوا اسکریپت هستید .استنفورد جاوا اسکریپت کتابخانه رمزنگاری PBKDF2 را فراخوانی می کند.تعداد تکرار باید کم ، به اندازه کافی قابل استفاده برای کاربران کندتر مانند دستگاه های تلفن همراه وغیره....باشد، همچنین سیستم باید به محاسبات سمت سرور نیز بپردازد اگر مرورگر کاربر جاواسکریپت را پشتیبانی نمی کند. کلید های سمت سرویس گیرنده key stretching نیاز حذف شدن ندارند اگر این کار را سمت سرور انجام می دهید. هش های تولید شده سمت کاربر باید به همان شیوه نرمال همیشگی هش شوند .

کرک هش غیر ممکن : رشته های هش و هش سخت افزاری

تا زمانی که مهاجم بتواند یک رشته هش برای بررسی اینکه آیا یک رمز عبور درست یا غلط است استفاده کند، آنها می توانند یک حمله دیکشنری یا brute-force بر روی هش اجرا کنند. گام بعدی اضافه کردن یک کلید مخفی به هش می باشد ، به طوری که تنها کسی که کلید را می داند بتواند اعتبارسنجی یک رمز عبور را انجام دهد. این را می توان به دو روش انجام داد. در هر دو صورت هش را می توان با استفاده از یک رمزگذاری مانند AES ، و یا کلید های مخفی را می توان در هش با استفاده از یک الگوریتم هش مانند HMAC گنجاند.

کلید مخفی باید حتی در صورت وجود اختلال در سیستم نیز مخفی بماند ، اگر مهاجم دسترسی کامل به سیستم شما داشته باشد این مهم نیست که کلید در کجا ذخیره کرده اید در هر صورت قادر به پیدا کردن آن خواهد بود .کلید باید در یک سیستم خارجی ذخیره شود . مانند سرورهای اختصاصی جداگانه که نیاز به احراز هویت دارند ، و یا یک دستگاه سخت افزاری خاص متصل به سرور مانند YubiHSM

من به شدت این شیوه را به تمام افرادی که در حال حاضر بالای 100 هزار کاربر دارند توصیه می کنم ، و همچنین این امر برای سرویس هایی که بالای 1 ملیون کاربر دارند ضروری است .

اگر شما نمی توانید سرور های اختصاصی متعدد و یا دستگاه های سخت افزاری خاص را تهیه کنید، شما هنوز هم می توانید برخی از مزایای هش در یک وب سرور استاندارد استفاده کنید. اکثر پایگاه های داده با استفاده از حملات تزریق SQL مورد حمله قرار می گیرند،چیزی که در اینجا مهم است دسترسی به فایل سیستم محلی است (غیر فعال کردن دسترسی به فایل سیستم محلی در سرور SQL ، اگر سرور شما از این ویژگی را در اختیار شما قرار می دهد).

اگر کلید تصادفی تولید شده شما در یک فایل و از طریق وب قابل دسترس نیست، و شامل salt + هش ، در اینصورت شما نیازی به نگرانی ندارید حتی اگر پایگاه داده شما با استفاده از یک حمله تزریق SQL ساده نقض شود ، حساب های کاربری شما امن خواهد ماند . از کلید ثابت استفاده نکنید، آن را به طور تصادفی تولید کنید.در هر صورت استفاده از یک سیستم مجزا برای انجام هش کردن رمز عبور نیز به تنهایی نمی تواند امن باشد، چرا که اگر آسیب پذیری تزریق SQL در یک برنامه وب وجود دارد، احتمالا انواع دیگری از آسیب پذیری ها وجود خواهد داشت، که مهاجم می تواند حتی با حق دسترسی read کلید شما را بخواند که بهتر از هیچ چیز است ....

لطفا توجه داشته باشید که رشته هش را حذف نکنید برای salt به آن نیاز داریم. مهاجمین هوشمند در نهایت راه هایی برای مصالحه کلید پیدا می کنند ، بنابراین هنوز مهم است که رشته هش با استفاده از نمک و key stretching محافظت می شود.

اقدامات امنیتی دیگر

نقض امنیت هش کردن رمز عبور در صورت محافظت کلمات عبور.

امنیت کاربران به امنیت اپلیکشن ربطی ندارد. بیشترین زمان باید برای جلوگیری از رشته هش کلمه عبور (و سایر داده های کاربر) صرف شود . زیرا در وحله اول توسط مهاجمین به سرقت خواهد رفت.

حتی توسعه دهندگان با تجربه باید در مورد امنیت به منظور نوشتن برنامه های کاربردی امن تحقیقات بیشتری کنند. یک منبع بزرگ برای یادگیری در موارد آسیب پذیری های برنامه های تحت وب ، گسترش وب ، پروژه امنیت (OWASP) است. در مقدمه OWASP با 10 لیست آسیب پذیری مطرح آشنا خواهید شد. اگر مواردی امنیتی که به آن اشاره شده برای درک شما سخت است ، برنامه هایی با داده های حساس ایجاد نکنید . زیرا شما مسئولیت پاسخگویی به کارفرما را دارید .

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

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

پرسش و پاسخ تا به اینجا

از چه نوع الگوریتمی می توانیم استفاده کنیم ؟

از اینها استفاده کنید :

PHP source code , Java source code, C# source code , Ruby source code

Portable PHP password hashing framework

هر الگوریتم هش رمزنگاری مدرن که به خوبی مورد آزمایش قرارگرفته ، مانند SHA256, SHA512, RipeMD, WHIRLPOOL, SHA3 و غیره ...

طراحی های خوب الگوریتم key stretching مانند: PBKDF2، bcrypt، و scrypt.

نسخه امن crypt ($2y$, $5$, $6$)

از اینها استفاده نکنید :

توابع هش منسوخ شده مانند MD5 یا SHA1.

نسخه نا امن crypt ($1$, $2$, $2x$, $3$)

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

حتی اگر هیچ حمله رمزنگاری در MD5 یا SHA1 وجود ندارد به دلیل قدیمی بودن کرک کردن آنها ساده تر خواهد بود . بنابراین من توصیه ای به استفاده از اینها نمی کنم .به استثناء استفاده از PBKDF2، که اغلب با استفاده از SHA1 به عنوان تابع هش زمینه اجرا می شود.

چگونه باید اجازه دهیم کاربرانی که رمز عبور خود را فراموش کرده اند قادر به بازیابی رمز عبور باشند؟

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

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

انقضای Token باید تنظیم شود برابر با 15 دقیقه یا بعد از استفاده آن ، هر کدام که اول می آید. این ایده خوبی است : منقضی شدن هر Token زمانی که کاربر وارد سیستم شده است (آنها رمز عبور جدید خود را به خاطر می آورند) و یا درخواست دیگری برای رمز جدید ارسال می کنند. اگر نشانه (token) منقضی نشود، می توان آن را برای همیشه برای شکستن یک حساب کاربری استفاده کرد. ایمیل (SMTP) یک پروتکل ساده متن است، و ممکن است روتر های مخرب در اینترنت ترافیک ایمیل را ضبط کنند. و، حساب ایمیل کاربر (از جمله لینک بازنشانی) بعد از تغییر رمز عبور به مدت طولانی باز هم به خطر بیافتد. ایجاد زمان انقضا برای token رمز عبور در معرض قرار گرفتن کاربر برای این حملات را کاهش می دهد.

حمله کننده قادر خواهد بود برای تغییر token اقدام کند، پس اطلاعات حساب کاربری و یا اطلاعات زمان ورود و خروج کاربر را در آن ذخیره نکنید. برای اینکار باید بلوب های باینری تصادفی غیر قابل پیش بینی استفاده شود که فقط به شناسایی یک رکورد در یک جدول پایگاه داده اختصاص داده شده است .

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

سیاست رمز عبور من چگونه باشد؟ باید کلمات عبور قوی اجرا کنم؟

اگر خدمات شما نیازمند امنیت سخت نمی باشد ، نیازی به محدود کردن کاربران خود ندارید. توصیه می شود میزان امنیت رمز کاربر در هنکام انتخاب رمز عبور برای کاربر نمایش داده شود و همچنین توصیه هایی برای انتخاب نوع پسورد از کاراکتر ها ی مختلف برای مثال : حداقل 2 حرف 2 کاراکتر و 2 عدد .

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

اگر یک مهاجم دسترسی به پایگاه داده من داشته باشد، آیا می تواند فقط با جایگزین هش رمز عبور خود با هش موجود در پایگاه داده وارد سایت شود؟

بله، اما اگر کسی دسترسی به پایگاه داده شما داشته باشد، احتمالا در حال حاضر دسترسی به همه چیزبر روی سرور نیز دارد، مهاجمین برای آنچه که می خواهند نیازی به ورود به حساب کاربری شما ندارند. هدف از هش کردن رمز عبور (در زمینه وب سایت) محافظت از وب سایت از نقض امنیتی است، در صورتی که با مشکلات نقض امنیتی روبرو شوید حداقل پسوردهای شما در امان خواهند ماند .

شما می توانید رشته هش را که طی یک حمله تزریق SQL با اتصال به پایگاه داده برای جایگزینی دو کاربر با مجوز های مختلف ارسال می شود جلوگیری کنید.در هنگام ایجاد کد "ایجاد حساب کاربری" قادر به خواندن و نوشتن در جدول کاربر است، اما برای 'ورود به سایت' باید فقط قادر به خواندن باشد.

چرا باید از یک الگوریتم خاص مانند HMAC استفاده کنیم؟ چرا نمی توانم فقط رمز عبور را در کلید مخفی اضافه کنم؟

توابع هش مانند MD5، SHA1، و SHA2 از Merkle–Damgård construction استفاده می کنند، که آنها به دلیل شناخته شدن تعداد کاراکتر شناخته شده و پسوند آسیب پذیرترند. این به این معنی است که با داشتن یک رشته هش H (X)، مهاجم می تواند از ارزش H(pad(X) + Y) برای بدست آوردن هر استرینگ دیگر بدون دانستن پد X. (X) اقدام کند، برای پیدا کردن هر رشته دیگر Y . ( تابع پد pad(X) استفاده شده برای توابع هش) .

این به این معنی است که با توجه به H هش (پیام +کلید)، مهاجم می تواند H (پد (کلید + پیام) + پسوند) ،را بدون دانستن کلید محاسبه کند. اگر هش با استفاده از یک پیام کد تأیید هویت ، مورد استفاده قرار گرفت، استفاده از کلید برای جلوگیری از حمله و قادر بودن به تغییر پیام و جایگزین کردن آن با یک رشته هش مفید خواهد بود، حمله دچار شکست خواهد شد ، حتی اگر مهاجم یک رشته هش معتبر از پیام + پسوند داشته باشد.

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

از نمک می توان قبل یا بعد از رمز عبور استفاده کرد ؟

مهم نیست، اما یکی را انتخاب کنید و از همان شیوه پیروی کنید.با این حال استفاده ازنمک قبل از رمز عبور به نظر می رسد بیشتر رایج است.

چرا کد هش در این صفحه با "طول ثابت" رشته هش در طول زمان مقایسه شده؟

مقایسه رشته هش در"طول ثابت" و زمان تضمین می کند که نفوذگر نتواند هش رمز عبور در یک سیستم را به صورت آنلاین اجرا کند و سپس مجبور به کرک آن به صورت آفلاین باشد.

روش استاندارد برای بررسی دو توالی از بایت (رشته) شبیه به مقایسه بایت اول، سپس دوم، پس از آن سوم، و غیره... به محض این که شما یک بایت پیدا کنید که برای هر دو رشته یکسان نیست ، شما می دانید که آنها متفاوت هستند و می تواند بلافاصله ریکوئست منفی بازگشت ارسال کنید. اگر شما هر دو استرینگ را بدون تغییر هر گونه بایت استفاده کنید می دانید که استرینگ ها مشابه یکدیگر هستنند و ونتیجه مثبت باز خواهد گشت . این بدان معنی است که مقایسه 2 رشته همانند تفاوت زمانی زیادی نیاز دارد تا بفهمید چقدر این 2 رشته با یکدیگر همخوانی دارند .

به عنوان مثال، برای یک مقایسه استاندارد از رشته "xyzabc" و "abcxyz" بلافاصله می توانید ببینید که اولین کاراکتر های ما با یدیگر مشابهتی ندارند و نیازی به مقایسه نیست. از سوی دیگر، زمانی که رشته "aaaaaaaaaaB" و "aaaaaaaaaaZ" مقایسه می شود، اسکن الگوریتم مقایسه را از طریق بلوک "a" انجام می دهد . بدون آن که توجه کند رشته ها نابرابر هستند

فرض کنید یک مهاجم می خواهد اقدام به شکستن یک سیستم احراز حویت آنلاین که محدودیت سرعت تلاش احراز هویت به یک تلاش در هر ثانیه است بپردازد. همچنین فرض کنید که مهاجم همه پارامترهای مربوط به هش رمز عبور (نمک، نوع هش، و غیره)، به جز خود هش و رمز عبور را می داند. اگر مهاجم بتواند اندازه گیری کند سیستم به طور آنلاین چه مدت طول می کشد به مقایسه هش از رمز عبور واقعی با هش از یک رمز عبور توسط مهاجم بپردازد ، او می تواند از حملات زمان بندی شده برای استخراج بخشی از هش استفاده و به صورت آفلاین به کرک آن ، با دور زدن یا bypass نوع محدودیت سیستم بپردازد.

مهاجم برای پیدا کردن 256 رشته هش را با هر بایت ممکن شروع می کند. او هر رشته ای را به سیستم آنلاین ارسال می کند، و مقدار زمان که طول می کشد سیستم پاسخ دهد را ذخیره می کند. رشته ای که طولانی ترین زمان را دربرگیرد منطبق اولین بایت هش واقعی است. مهاجم در حال حاضر اولین بایت را پیدا کرده، و می تواند از حمله ای به شیوه مشابه برای پیدا کردن بایت دوم استفاده کند، ادامه و سپس سوم، و غیره....

زمانی که مهاجم رشته های هش را به اندازه کافی شناسایی کرد می تواند از سیستم خود برای کرک بدون هیچ محدودیتی به صورت آفلاین استفاده کند.

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

SlowEquals چگونه کار می کند؟

سوال قبلی توضیح میدهد که چرا SlowEquals لازم است، این یکی توضیح می دهد که چگونه کد در واقع کار می کند.

1
2
3
4
5
6
7
private static boolean slowEquals(byte[] a, byte[] b)
{
int diff = a.length ^ b.length;
for(int i = 0; i < a.length && i < b.length; i++)
diff |= a[i] ^ b[i];
return diff == 0;
}

کد با استفاده از XOR "^" اپراتور مقایسه اعداد صحیح برای برابری، به جای اپراتور "==" مشخص شده است. به همین دلیل است که در زیر توضیح داده شده. نتیجه XORing دو عدد صحیح صفر خواهد بود حتی اگر آنها دقیقا همانند باشند. دلیل این است که

0 XOR 0 = 0, 1 XOR 1 = 0, 0 XOR 1 = 1, 1 XOR 0 = 1

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

بنابراین، در خط اول، اگر a.length برابر b.length است، متغیر diff یک مقدار صفر را دریافت میکند، اما اگر نه، آن ارزشی غیر از صفر خواهد گرفت. بعد از آن، ما به مقایسه بایت ها با استفاده از XOR، و یا or نتیجه را به diff ریختیم. این diff را به یک مقدار غیر صفر تغییر خواهد داد اگر بایت در ادامه متفاوت باشد. از آنجا که ORing هرگز بیت را un-set نمی کند، تنها راه اینکه diff در پایان حلقه صفر باشد این است که در شروع حلقه نیز صفر بوده باشد . (a.length == b.length) و همه بایت ها در دو آرایه (هیچ یک از نتایج XORs منجر به ارزش غیر صفر نمی شود).

و چرا زحمت هش کردن رمز عبور؟

کاربران شما در زمان ورود رمز عبور خود را به وب سایت شما وارد می کنند. آنها به شما اعتماد و امنیت وب سایت شما اطمینان می کنند. اگر پایگاه داده شما هک شود وحساب های کاربری شما محافظت نشده باشند ، در این صورت هکر می تواند حساب های کاربری شما را در وب سایت های دیگر نیز مورد سوء استفاده قرار دهد (بسیاری از افراد از رمز عبور مشابه در همه جا استفاده می کنند). این فقط امنیت وب سایت شما نیست که در معرض خطر است،. شما مسئول امنیت کاربران خود نیز می باشید.

هش رمز عبور درPHP با استفاده از PBKDF2

کد زیر یک مرحله برای هش امن با استفاده از PBKDF2 در php را نشان می دهد ، می توانید تست ها ، و شاخه های مرتبط را در صفحه زیر پیدا کنید :

Defuse Security's PBKDF2 for PHP

دانلود PasswordHash.php

کد زیر یک مرحله برای هش امن با استفاده از PBKDF2 در جاوا می باشد

دانلود PasswordHash.java

کد زیر یک مرحله برای هش امن با استفاده از PBKDF2 در ASP.NET (C#) می باشد

دانلود PasswordHash.cs

Ruby (on Rails)

دانلود PasswordHash.rb

برگرفته از Defuse Security

گروه طراحی سایت بستا مفتخر است شما را در طراحی سایت به صورت استاندارد در تمامی مراحل از پیاده سازی تا اجرا همراهی نماید