رفتن به محتوا
مبانی کامپیوتر و اینترنتسرور، ابر و امنیت پایهدرس ۱۴ از ۱۶

رمز عبور، هش و رمزنگاری

چرا رمز عبور نباید ذخیره شود و به‌جایش چه نگه داشته می‌شود: هش به‌عنوان اثر انگشت یک‌طرفه با sha256sum، بررسی سلامت فایل دانلودی، چرا هش ساده برای رمز کافی نیست، نمک (salt) و هش کند، فرمت ‎/etc/shadow، فرق encoding و هش و رمزنگاری، رمزنگاری متقارن با openssl، کلید عمومی و خصوصی، و حساب کردن قدرت یک رمز.

  • حدود ۲۴ دقیقه مطالعه
  • ۷ مثال اجراشده
  • ۳ تمرین با جواب
  • مقدماتی (از صفر مطلق)
  • به‌روزرسانی: ۲۹ مهر ۱۴۰۵

توی این درس یاد می‌گیری سایت‌ها چطور رمز تو را چک می‌کنند بدون اینکه خود رمز را نگه دارند. با هش آشنا می‌شوی (اثر انگشت یک‌طرفه‌ی هر داده) و با sha256sum با آن کار می‌کنی، می‌فهمی چرا هش ساده برای رمز کافی نیست و نمک (salt) و هش کند چه مشکلی را حل می‌کنند، سه چیزی را که همه قاطی می‌کنند از هم جدا می‌کنی (encoding، هش و رمزنگاری)، یک فایل را با openssl رمزنگاری و باز می‌کنی و ایده‌ی کلید عمومی و خصوصی را که پایه‌ی HTTPS و SSH است می‌شناسی. در آخر حساب می‌کنی یک رمز واقعاً چقدر قوی است.

مسئله: دیتابیسی که لو می‌رود

Section titled “مسئله: دیتابیسی که لو می‌رود”

هر چند وقت یک بار خبر می‌رسد: «اطلاعات میلیون‌ها کاربر فلان سایت فاش شد». فرض کن دیتابیس سایتی که در آن عضوی، کامل دست کسی بیفتد. اگر رمزها همان‌طور که تایپ شده‌اند ذخیره شده باشند، مهاجم رمز همه را دارد و چون خیلی‌ها یک رمز را همه‌جا استفاده می‌کنند، با همان رمز سراغ ایمیل و بانک و شبکه‌های اجتماعی‌شان می‌رود. سؤال این است: سایت چطور می‌تواند بفهمد رمزی که الان وارد کردی درست است، بدون اینکه رمز درست را جایی نوشته باشد؟

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

سایت‌ها با رمز همین کار را می‌کنند: موقع ثبت‌نام هش رمز را ذخیره می‌کنند، و موقع ورود، از رمزی که تایپ کردی دوباره هش می‌گیرند و دو هش را مقایسه می‌کنند. خود رمز هیچ‌جا نیست.

سایت فقط هش رمز را نگه می‌دارد؛ هنگام ورود، هش رمز واردشده را با هش ذخیره‌شده مقایسه می‌کند.
Terminal window
printf 'سلام' | sha256sum
printf 'سلام' | sha256sum
printf 'سلام!' | sha256sum
printf 'a' | sha256sum
خروجی
bda1fa48345336618741fd2c4bc02809eb099c49a9b02fb5056401ab6d4dc3e6 -
bda1fa48345336618741fd2c4bc02809eb099c49a9b02fb5056401ab6d4dc3e6 -
903c0515c0763a585585cdbe653ad9217a1b330dd35239e4c5a589190eb24969 -
ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb -

(printf متن را بدون خط جدید آخر می‌دهد و | آن را به sha256sum می‌دهد. - یعنی ورودی از pipe آمد، نه فایل.) SHA-256 یکی از رایج‌ترین تابع‌های هش است. چهار ویژگی را همین‌جا می‌بینی:

  1. همیشه یکسان: یک ورودی، همیشه همان هش (خط ۱ و ۲).
  2. اندازه‌ی ثابت: ۶۴ رقم هگز = ۳۲ بایت = ۲۵۶ بیت (اسمش از همین است؛ درس بیت و بایت)، چه ورودی یک حرف باشد چه یک فیلم.
  3. اثر بهمنی: یک ! اضافه، هشی کاملاً متفاوت ساخت. هیچ شباهتی نمانده که نشان دهد ورودی‌ها نزدیک بودند.
  4. یک‌طرفه: از bda1fa48... هیچ راهی برای رسیدن به «سلام» نیست، جز حدس زدن ورودی‌ها و هش گرفتن از هر کدام.

مثال ۲: هش یک فایل، و بررسی دانلود

Section titled “مثال ۲: هش یک فایل، و بررسی دانلود”

هش فقط برای رمز نیست. یک فایل ۱۰ مگابایتی بساز و هشش را بگیر:

Terminal window
head -c 10000000 /dev/zero > big.bin
ls -l big.bin
sha256sum big.bin
خروجی
-rw-r--r-- 1 ali ali 10000000 Oct 22 00:30 big.bin
f5e02aa71e67f41d79023a128ca35bad86cf7b6656967bfe0884b3a3c4325eaf big.bin

(/dev/zero یک «فایل» بی‌انتهای صفر است و head -c ده میلیون بایت از آن برمی‌دارد.) ده میلیون بایت، باز هم ۶۴ رقم. اگر حتی یک بیت از فایل عوض شود، هش کاملاً عوض می‌شود. برای همین سایت‌هایی که فایل نصب (مثلاً ISO اوبونتو) می‌دهند، هش آن را هم کنارش می‌نویسند (فایلی به اسم SHA256SUMS). بعد از دانلود هش بگیر و مقایسه کن: اگر یکی بود، فایل سالم و دست‌نخورده به تو رسیده؛ نه خراب شده، نه کسی وسط راه چیزی در آن جا داده.

مثال ۳: چرا هش ساده برای رمز کافی نیست

Section titled “مثال ۳: چرا هش ساده برای رمز کافی نیست”
Terminal window
printf '123456' | sha256sum
خروجی
8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92 -

این هش را در یک موتور جست‌وجو بزن: در ثانیه‌ی اول می‌بینی مال 123456 است. مهاجم‌ها جدول‌های عظیمی از «رمزهای رایج و هششان» دارند. دو مشکل دیگر هم هست:

  • همه‌ی کسانی که رمز 123456 دارند، هش یکسان دارند. مهاجم با یک نگاه به دیتابیس می‌فهمد ده هزار نفر یک رمز دارند و با شکستن یکی، همه را دارد.
  • SHA-256 خیلی سریع است. برای فایل خوب است، برای رمز بد. ببین یک کامپیوتر معمولی (و فقط با پایتون، که کند است) در یک ثانیه چند هش می‌سازد:
Terminal window
python3 -c "
import hashlib, time
n = 1_000_000
t = time.perf_counter()
for i in range(n):
hashlib.sha256(str(i).encode()).hexdigest()
print(f'{n} sha256 in {time.perf_counter() - t:.2f} s')
"
خروجی
1000000 sha256 in 0.96 s

یک میلیون حدس در یک ثانیه، با پایتون روی یک هسته. کارت گرافیک‌هایی که برای شکستن رمز استفاده می‌شوند، ده‌ها میلیارد در ثانیه می‌زنند. با این سرعت، هر رمز ۸ حرفی در چند ساعت امتحان می‌شود (مثال ۷).

دو راه‌حل، با هم:

  • نمک (salt): یک رشته‌ی تصادفی که برای هر کاربر جدا ساخته می‌شود و قبل از هش به رمز چسبانده می‌شود. حالا دو کاربر با رمز 123456 دو هش متفاوت دارند و جدول‌های آماده‌ی مهاجم بی‌فایده‌اند. نمک محرمانه نیست؛ کنار هش ذخیره می‌شود. کارش فقط یکتا کردن است.
  • هش کند: تابع‌هایی که عمداً کند و حافظه‌خورند (bcrypt، scrypt، Argon2، yescrypt). برای کاربر، صبر کردن ۰٫۱ ثانیه موقع ورود اهمیتی ندارد؛ برای مهاجمی که میلیاردها حدس لازم دارد، یعنی میلیون‌ها برابر کندتر.

openssl passwd هش نمک‌دار به همان شکلی که لینوکس استفاده می‌کند می‌سازد:

Terminal window
openssl passwd -6 '123456'
openssl passwd -6 '123456'
خروجی
$6$Bm.s0qhRapEHxeU0$Wz5rMnOhvvxxJ50P3XsWUFNFRKZ7U/KwCI51Ekbdm.dQucDQ5G/99CrW4molKvPdJfy9Q76RUXJSsSsSq99Dk1
$6$qGXQRnnwESYKKPiE$jShlpqk8FwFY.OBQfj6X4SIQW6IFri/rQp3BQsiA3FvH5r19MuhCCzzwd6mfwuVSyB.UK7/563r.FrLTZRDZc0

یک رمز، دو هش کاملاً متفاوت (برای تو هم متفاوت‌اند؛ نمک تصادفی است). قالب با $ سه بخش دارد: 6 نوع الگوریتم (SHA-512 با هزاران دور تکرار)، Bm.s0qhRapEHxeU0 نمک، و بقیه خود هش. برای چک کردن رمز، سیستم نمک را از همین رشته برمی‌دارد، رمز واردشده را با همان نمک هش می‌کند و مقایسه می‌کند. اگر نمک را دستی بدهی، نتیجه همیشه همان است:

Terminal window
openssl passwd -6 -salt Xk3pQ9aB '123456'
openssl passwd -6 -salt Xk3pQ9aB '123456'
خروجی
$6$Xk3pQ9aB$tKCyKhygrHw4fGfGAlzht.vDSi8zNiAHWSfoZ/Wbhko48uuTgJcHZJgJKXU.Erd.Xh.LS4XMblXL4yMkXNoxY1
$6$Xk3pQ9aB$tKCyKhygrHw4fGfGAlzht.vDSi8zNiAHWSfoZ/Wbhko48uuTgJcHZJgJKXU.Erd.Xh.LS4XMblXL4yMkXNoxY1

و یک هش واقعاً کند، scrypt:

Terminal window
python3 -c "
import hashlib, time
t = time.perf_counter()
hashlib.scrypt(b'123456', salt=b'random-salt-1234', n=2**14, r=8, p=1)
print(f'1 scrypt in {time.perf_counter() - t:.3f} s')
"
خروجی
1 scrypt in 0.049 s

یک هش در ۵۰ میلی‌ثانیه، در برابر یک میلیون SHA-256 در یک ثانیه: حدود ۵۰ هزار برابر کندتر، و چون هر کدام ۱۶ مگابایت حافظه می‌خواهد، کارت گرافیک هم کمک زیادی نمی‌کند. همین عدد را تنظیم می‌کنی تا با سخت‌افزار جدیدتر هم کند بماند.

مثال ۵: رمزهای لینوکس کجا هستند؟

Section titled “مثال ۵: رمزهای لینوکس کجا هستند؟”

لینوکس رمز کاربرها را در /etc/shadow نگه می‌دارد، فایلی که فقط مدیر سیستم می‌تواند بخواند (درس سیستم‌عامل دیدی cat /etc/shadow برای کاربر معمولی Permission denied می‌دهد):

Terminal window
sudo grep "^$USER:" /etc/shadow
نمونه
ali:$y$j9T$Hq3s0x8pR0ZcVvXo1rN2n/$Jt8CqgN7mU0w8b3Wl6yC2vF0xSx9QnB4pA1dE5r7kQ.:20380:0:99999:7:::

همان قالب $نوع$نمک$هش، این بار با y یعنی yescrypt: هش کند و حافظه‌خوری که اوبونتو از نسخه‌ی ۲۲٫۰۴ به بعد استفاده می‌کند. (ستون‌های بعد از : تاریخ آخرین تغییر رمز و قوانین انقضا هستند؛ دوره‌ی لینوکس.) حتی مدیر سیستم هم رمز تو را نمی‌بیند؛ فقط می‌تواند آن را عوض کند.

⚡ بررسی سریع

دو کاربر رمز یکسان دارند ولی در /etc/shadow هش‌هایشان کاملاً متفاوت است. چرا؟

مثال ۶: encoding، هش، رمزنگاری؛ سه چیز متفاوت

Section titled “مثال ۶: encoding، هش، رمزنگاری؛ سه چیز متفاوت”

این سه را خیلی‌ها قاطی می‌کنند و اشتباه گرفتنشان باعث نشت داده می‌شود:

Terminal window
echo -n "salam" | base64
echo "c2FsYW0=" | base64 -d; echo
خروجی
c2FsYW0=
salam

Base64 یک encoding است (مثل UTF-8 در درس متن): داده را به حرف‌های قابل‌چاپ تبدیل می‌کند تا از جاهایی که فقط متن قبول می‌کنند (ایمیل، JSON، URL) رد شود. هیچ امنیتی ندارد: هر کس با یک دستور برش می‌گرداند. اگر در یک فایل تنظیمات «رمز» را به شکل UzNjdXJlLVBhc3M= دیدی، آن رمز رمزنگاری نشده؛ فقط لباس عوض کرده.

رمزنگاری (encryption) داده را با یک کلید طوری درهم می‌کند که فقط کسی که کلید را دارد بتواند برش گرداند. یک فایل محرمانه را با رمزنگاری AES (رایج‌ترین الگوریتم متقارن) قفل کن:

Terminal window
echo "قرارداد محرمانه: مبلغ ۴۰۰ میلیون" > secret.txt
openssl enc -aes-256-cbc -pbkdf2 -salt -in secret.txt -out secret.enc -pass pass:'Long-Pass-2026'
ls -l secret.txt secret.enc
file secret.enc
head -c 32 secret.enc | od -c | head -2
خروجی
-rw-r--r-- 1 ali ali 80 Oct 22 00:30 secret.enc
-rw-r--r-- 1 ali ali 60 Oct 22 00:30 secret.txt
secret.enc: openssl enc'd data with salted password
0000000 S a l t e d _ _ 352 363 ^ 242 016 a 8 `
0000020 ( 7 302 m i \f 256 352 ] 374 361 001 ( Y 030 g

فایل رمزنگاری‌شده با Salted__ و نمک شروع می‌شود و بقیه‌اش بایت‌های بی‌معنی است (od -c بایت‌ها را نشان می‌دهد؛ عددها برای تو فرق می‌کنند). -pbkdf2 یعنی از رمز تو با یک هش کند کلید واقعی AES ساخته شود. باز کردنش:

Terminal window
openssl enc -d -aes-256-cbc -pbkdf2 -in secret.enc -pass pass:'Long-Pass-2026'
openssl enc -d -aes-256-cbc -pbkdf2 -in secret.enc -out /dev/null -pass pass:'wrong'
echo "exit=$?"
خروجی
قرارداد محرمانه: مبلغ ۴۰۰ میلیون
bad decrypt
4077F77DF67F0000:error:1C800064:Provider routines:ossl_cipher_unpadblock:bad decrypt:../providers/implementations/ciphers/ciphercommon_block.c:124:
exit=1

با کلید درست، متن برگشت؛ با کلید غلط، bad decrypt. (در عمل رمز را در خط فرمان ننویس؛ در تاریخچه‌ی ترمینال می‌ماند. بدون -pass، openssl رمز را بی‌صدا می‌پرسد.)

encoding برای سازگاری است و برگشت‌پذیر بدون کلید؛ هش یک‌طرفه است؛ رمزنگاری برگشت‌پذیر است ولی فقط با کلید.
برمی‌گردد؟ کلید لازم؟ کاربرد
Encoding (Base64، UTF-8) بله، برای همه نه سازگاری؛ امنیت صفر
هش (SHA-256، yescrypt) نه نه رمز عبور، بررسی سلامت
رمزنگاری (AES، RSA) بله، فقط با کلید بله محرمانه نگه داشتن

مثال ۷: یک رمز چقدر قوی است؟

Section titled “مثال ۷: یک رمز چقدر قوی است؟”

قدرت رمز یعنی تعداد حالت‌هایی که مهاجم باید امتحان کند: (تعداد حرف‌های ممکن) به توان (طول). این برنامه‌ی کوچک (crack.py) بدترین حالت را برای دو سرعت حساب می‌کند: هش سریع با ده میلیارد حدس در ثانیه، و هش کند با ده هزار:

crack.py
import math
def human(seconds):
for unit, size in [("سال", 365 * 86400), ("روز", 86400), ("ساعت", 3600), ("دقیقه", 60)]:
if seconds >= size:
return f"{seconds / size:,.0f} {unit}"
return "کمتر از یک دقیقه"
cases = [
("PIN چهاررقمی", 10, 4),
("۸ حرف کوچک", 26, 8),
("۸ حرف بزرگ و کوچک و رقم", 62, 8),
("۱۲ حرف بزرگ و کوچک و رقم", 62, 12),
("۵ کلمه‌ی تصادفی از ۷۷۷۶", 7776, 5),
]
print(f"{'رمز':28} {'بیت':>5} {'هش سریع':>16} {'هش کند':>18}")
for name, alphabet, length in cases:
combos = alphabet ** length
print(f"{name:28} {math.log2(combos):5.1f} {human(combos / 1e10):>16} {human(combos / 1e4):>18}")
Terminal window
python3 crack.py
خروجی
رمز بیت هش سریع هش کند
PIN چهاررقمی 13.3 کمتر از یک دقیقه کمتر از یک دقیقه
۸ حرف کوچک 37.6 کمتر از یک دقیقه 242 روز
۸ حرف بزرگ و کوچک و رقم 47.6 6 ساعت 692 سال
۱۲ حرف بزرگ و کوچک و رقم 71.5 10,230 سال 10,230,424,792 سال
۵ کلمه‌ی تصادفی از ۷۷۷۶ 64.6 90 سال 90,151,852 سال

درس‌های این جدول:

  • طول از هر چیز مهم‌تر است. از ۸ به ۱۲ حرف رفتن، شش ساعت را به ده هزار سال رساند. هر حرف اضافه، حالت‌ها را ۶۲ برابر می‌کند (توان!).
  • هش کند (کار سایت) همان رمز ضعیف را از چند ساعت به چند صد سال می‌رساند. ولی رمز خیلی ضعیف (PIN) را هیچ چیز نجات نمی‌دهد.
  • ستون «بیت» همان عدد را به زبان درس بیت و بایت می‌گوید: log2 تعداد حالت‌ها. ۸۰ بیت به بالا امروز قوی حساب می‌شود.
  • این‌ها برای رمز تصادفی است. Ali1370 هشت حرف است، ولی در فهرست‌های رمزهای رایج و «اسم + سال تولد» در چند ثانیه پیدا می‌شود. آدم‌ها در ساختن رمز تصادفی خیلی بدند؛ برای همین مدیر رمز (password manager) رمز را می‌سازد و نگه می‌دارد.

پشت پرده: کلید عمومی و خصوصی

Section titled “پشت پرده: کلید عمومی و خصوصی”

رمزنگاری مثال ۶ متقارن است: یک کلید برای قفل و باز کردن. مشکلش این است که کلید را چطور به طرف مقابل برسانی؟ اگر از همان شبکه بفرستی، هر کس وسط راه کلید را می‌بیند.

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

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

این دو ایده را در درس‌های بعدی و دوره‌های دیگر مدام می‌بینی:

  • SSH: کلید عمومی‌ات را روی سرور می‌گذاری؛ سرور با آن ثابت می‌کند که کلید خصوصی دست توست، بدون اینکه رمزی رد و بدل شود (دوره‌ی لینوکس، درس SSH).
  • HTTPS: سرور با کلید خصوصی‌اش ثابت می‌کند واقعاً bank.ir است و با کمک کلید عمومی، یک کلید متقارن موقت با مرورگر توافق می‌کند تا بقیه‌ی گفت‌وگو سریع رمزنگاری شود (درس بعد).
دستور کار
sha256sum file هش یک فایل
printf 'text' | sha256sum هش یک متن
sha256sum -c SHA256SUMS بررسی هش فایل‌های دانلودی
openssl passwd -6 'pass' هش نمک‌دار به قالب لینوکس
base64 / base64 -d encoding (نه امنیت!)
openssl enc -aes-256-cbc -pbkdf2 -in f -out f.enc رمزنگاری فایل
openssl enc -d -aes-256-cbc -pbkdf2 -in f.enc باز کردن
اصطلاح معنی
hash اثر انگشت یک‌طرفه و ثابت‌اندازه
salt رشته‌ی تصادفی برای یکتا کردن هش هر کاربر
bcrypt / scrypt / Argon2 / yescrypt هش‌های عمداً کند برای رمز
symmetric یک کلید برای قفل و باز کردن (AES)
asymmetric جفت کلید عمومی و خصوصی (RSA، Ed25519)
signature امضا با کلید خصوصی، بررسی با کلید عمومی

۱) ذخیره‌ی رمز به‌صورت متن یا Base64

Section titled “۱) ذخیره‌ی رمز به‌صورت متن یا Base64”

سناریوی درس. راه‌حل: فقط هش کند و نمک‌دار؛ هیچ‌وقت خود رمز، حتی «رمزنگاری‌شده».

۲) هش سریع (MD5، SHA-256) برای رمز

Section titled “۲) هش سریع (MD5، SHA-256) برای رمز”

برای فایل خوب، برای رمز بد (مثال ۳). راه‌حل: bcrypt، Argon2 یا scrypt؛ هر زبان برنامه‌نویسی کتابخانه‌ی آماده دارد. هرگز الگوریتم خودت را اختراع نکن.

۳) «رمزنگاری» به‌جای «هش» برای رمز عبور

Section titled “۳) «رمزنگاری» به‌جای «هش» برای رمز عبور”

اگر رمزها با یک کلید رمزنگاری شده باشند، هر کس کلید را بدزدد (معمولاً کنار همان دیتابیس است)، همه‌ی رمزها را دارد. راه‌حل: رمز عبور را هرگز نباید برگرداند؛ پس هش، نه رمزنگاری.

یک سایت ضعیف لو برود، همه‌ی حساب‌هایت لو رفته‌اند. راه‌حل: مدیر رمز با رمز تصادفی جدا برای هر سایت، و تأیید دومرحله‌ای (2FA) برای حساب‌های مهم.

۵) رمز در خط فرمان و فایل‌ها

Section titled “۵) رمز در خط فرمان و فایل‌ها”

-pass pass:... در تاریخچه‌ی bash (~/.bash_history) می‌ماند و در فهرست پروسه‌ها برای بقیه‌ی کاربرها دیده می‌شود. راه‌حل: بگذار برنامه رمز را بپرسد، یا از فایل با مجوز محدود بخواند (دوره‌ی لینوکس، مجوزها).

تمرینآسان

یک فایل متنی notes.txt بساز، هشش را بگیر، یک حرف از آن را عوض کن و دوباره هش بگیر. دو هش چقدر به هم شبیه‌اند؟ بعد هش را در فایل notes.sha256 ذخیره کن و با sha256sum -c بررسی کن.

دیدن جواب
Terminal window
echo "خرید: نان، شیر" > notes.txt
sha256sum notes.txt
sha256sum notes.txt > notes.sha256
sha256sum -c notes.sha256
echo "خرید: نان، پنیر" > notes.txt
sha256sum notes.txt
sha256sum -c notes.sha256
خروجی
ecfde1d6d218b423395fca0575dacf40e11ce1fe0d22016dd3eebf3a89f10f10 notes.txt
notes.txt: OK
8acaebf11878aabc89e8923c3d04e83e92b626db22f5dbb5d3120f37078c52a6 notes.txt
notes.txt: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match

هش دوم هیچ شباهتی به اولی ندارد. sha256sum -c هش ذخیره‌شده را با هش فعلی فایل مقایسه می‌کند: OK یعنی دست‌نخورده، FAILED یعنی تغییر کرده. همین کار را برای ISO اوبونتو با فایل SHA256SUMS سایتش انجام می‌دهی.

تمرینمتوسط

نشان بده چرا نمک مهم است: برای یک رمز (Tehran1405) با openssl passwd -6 سه هش بدون دادن نمک بساز و یک بار هم با نمک ثابت AbCd1234 دو بار. بعد توضیح بده سیستم چطور در زمان ورود رمز را چک می‌کند، در حالی که هش‌ها هر بار عوض می‌شوند.

دیدن جواب
Terminal window
for i in 1 2 3; do openssl passwd -6 'Tehran1405'; done
openssl passwd -6 -salt AbCd1234 'Tehran1405'
openssl passwd -6 -salt AbCd1234 'Tehran1405'
نمونه
$6$Lq0Uo3m5bX2JdG8k$...
$6$7vVnA1zQe9PpR0sW$...
$6$cH2mZt8Kq4YjL6aN$...
$6$AbCd1234$1i9N1Y/w3m8C4DWIorTpvKCAJqP9pUtsK/Du5Y.d0sLkuO9mSjSX.4I3tmBgHgJKYZajl4A72OJikGrrKpntC1
$6$AbCd1234$1i9N1Y/w3m8C4DWIorTpvKCAJqP9pUtsK/Du5Y.d0sLkuO9mSjSX.4I3tmBgHgJKYZajl4A72OJikGrrKpntC1

بدون نمک دستی، هر بار یک نمک تصادفی جدید ساخته شد و هش عوض شد. با نمک ثابت، هش ثابت. موقع ثبت‌نام، سیستم یکی از این رشته‌ها را (با نمکش) ذخیره می‌کند. موقع ورود، نمک را از خود رشته‌ی ذخیره‌شده (بخش بین $ دوم و سوم) برمی‌دارد، رمز تایپ‌شده را با همان نمک هش می‌کند و نتیجه را با بخش آخر مقایسه می‌کند. یکی بود: رمز درست است.

تمرینسخت

به crack.py دو ردیف اضافه کن: «۱۶ حرف کوچک» و «۱۰ حرف با همه‌ی ۹۵ نماد صفحه‌کلید». کدام قوی‌تر است؟ بعد حساب کن یک رمز ۸ حرفی از ۶۲ حرف، در بدترین حالت، با هش سریع چند ساعت طول می‌کشد و چرا «به‌طور متوسط» نصف آن است.

دیدن جواب
crack.py (ردیف‌های اضافه)
("۱۶ حرف کوچک", 26, 16),
("۱۰ حرف از ۹۵ نماد", 95, 10),
خروجی (دو ردیف جدید)
۱۶ حرف کوچک 75.2 138,282 سال 138,282,416,601 سال
۱۰ حرف از ۹۵ نماد 65.7 190 سال 189,858,238 سال

۱۶ حرف کوچک (۷۵ بیت) خیلی قوی‌تر از ۱۰ حرف پیچیده (۶۶ بیت) است و حفظ کردنش هم راحت‌تر (مثلاً چند کلمه کنار هم). طول برنده است. برای ۸ حرف از ۶۲: ۶۲۸ ≈ ۲٫۱۸ × ۱۰۱۴ حالت؛ تقسیم بر ۱۰۱۰ در ثانیه ≈ ۲۱٬۸۰۰ ثانیه ≈ ۶ ساعت (همان عدد جدول). به‌طور متوسط مهاجم رمز را وسط راه پیدا می‌کند (گاهی زود، گاهی دیر؛ میانگین وسط فهرست است)، پس حدود ۳ ساعت.

آزمونک
  1. هش چیست؟

  2. سایت درست کار می‌کند اگر برای رمز کاربر چه ذخیره کند؟

  3. نمک (salt) چه مشکلی را حل می‌کند؟

  4. رشته‌ی UzNjdXJlLVBhc3M= در فایل تنظیمات چیست؟

  5. کدام تغییر بیشترین اثر را روی قدرت رمز تصادفی دارد؟

  6. در رمزنگاری نامتقارن، چه چیزی را می‌شود آزادانه به همه داد؟

  • هش اثر انگشت یک‌طرفه است: همیشه یکسان، اندازه‌ی ثابت، اثر بهمنی، بدون راه برگشت. برای بررسی سلامت فایل و ذخیره‌ی رمز.
  • رمز عبور: هرگز خود رمز؛ هش کند + نمک (bcrypt، Argon2، scrypt، yescrypt). SHA-256 برای رمز خیلی سریع است.
  • encoding (Base64) امنیت ندارد؛ رمزنگاری با کلید برمی‌گردد؛ هش برنمی‌گردد.
  • رمزنگاری متقارن (AES) یک کلید دارد؛ نامتقارن جفت کلید عمومی/خصوصی، پایه‌ی SSH و HTTPS و امضای دیجیتال.
  • قدرت رمز = تعداد حالت‌ها؛ طول مهم‌ترین عامل است؛ مدیر رمز و 2FA.
برگه‌ی تقلب این درس
دستورکاری که می‌کند
sha256sum fileهش فایل
sha256sum -c SHA256SUMSبررسی دانلود
openssl passwd -6 'pass'هش نمک‌دار به قالب لینوکس
$6$salt$hash / $y$...قالب هش در /etc/shadow
base64 / base64 -dencoding، نه امنیت
openssl enc -aes-256-cbc -pbkdf2 -in f -out f.encرمزنگاری فایل
openssl enc -d -aes-256-cbc -pbkdf2 -in f.encباز کردن فایل
طول > پیچیدگیقانون رمز قوی