نگاره‌هایی پیرامون امنیت، شبکه و رمزنگاری

15 ژوئن 2021

کتابخانه OpenSSL یکی از محبوب‌ترین کتابخانه‌های رمزنگاری موجود هست که رایج‌ترین استفاده اون پیاده سازی پروتکل‌های SSL/TLS هست. پروتکل SSL/TLS امکان ارتباط امن بین سرور و کلاینت رو فراهم می‌کنه، به این صورت که قبل از تبادل اطلاعات بین سرور و کلاینت، اون‌هارو رمزگذاری می‌کنه و به این ترتیب اطلاعات محرمانه ار قبیل رمز ورود، اطلاعات بانکی و … غیرقابل شناسایی خواهند بود.

پروتکل SSL/TLS چیست؟

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

  1. سرور یک گواهی امنیتی (security certificate) برای کلاینت ارسال می‌کنه که حاوی کلید عمومی (public key) هست.
  2. کلاینت بعد از تأیید گواهی امنیتی سرور، با استفاده از کلید عمومی (public key) سرور، یک کلید (secret key) ایجاد کرده و برای سرور ارسال می‌کنه. چون این کلید با کلید عمومی خود سرور ایجاد شده، فقط سرور توانایی رمزگشایی اون رو خواهد داشت.
  3. حالا هر دو طرف ارتباط به یک جفت کلید خصوصی (private key) دسترسی دارن که مختص خودشون هست و می‌تونن با استفاده از اون اطلاعات مبادله شده بین همدیگه رو رمرگذاری کنن.

پروتکل SSL/TLS یکی از چندین پروتکل مورد استفاده برای این منظور هست که برای ایجاد چنین پروتکل‌هایی نیاز به کتابخانه‌هایی همچون OpenSSL داریم. برای آشنایی با جزئیات عملکرد پروتکل SSL/TLS می‌تونید به پست آشنایی با پروتکل SSL/TLS مراجعه کنید.

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

بخش اول: شروع به کار

دونستن اینکه با چه ورژنی از OpenSSL دارید کار می‌کنید اهمیت زیادی داره، این ورژن تعیین می‌کنه که از چه الگوریتم‌های رمزنگاری می‌تونید استفاده کنید و همچنین چه پروتکل‌هایی پشتیبانی میشن. به عنوان مثال OpenSSL 1.0.1 اولین ورژنی بود که از TLS 1.1 و TLS 1.2 پشتیبانی می‌کرد. دونستن ورژن این کتابخانه همچنین می‌تونه در دیباگ کردن نواقص احتمالی بسیار کمک کننده باشه. با دستور زیر می‌تونید ورژن مربوط به این کتابخانه رو ببینید:

openssl version

و با دستور زیر می‌تونید اطلاعات بیشتری رو مشاهده کنید، از جمله مشخصات سیستم عامل و محل ذخیره سازی گواهی‌های SSL که در سیستم خودتون ایجاد کردید:

openssl version -a

فایل plain.txt رو نظر بگیرید که فقط حاوی عبارت Hello World! هست و می‌خوایم این متن رو رمزگذاری کنیم. فرض کنید رمزگذاری ما قراره با روش CBC و با استفاده از الگوریتم AES و یه کلید 256 بیتی انجام بشه. در این صورت دستورات زیر رو خواهیم داشت:

touch plain.txt
echo "Hello World!" > plain.txt
openssl enc -aes-256-cbc -in plain.txt -out encrypted.bin
//enter aes-256-cbc encryption password: example
//Verifying - enter aes-256-cbc encryption password: example

بعد از اجرای سه دستور اول، ازتون پسووردی خواهد خواست که با استفاده از اون پسوورد قراره کلید 256 بیتی تولید شه و این پسوورد برای رمزگشایی فایل‌های رمز شده حتما نیاز خواهد بود. بعد از اجرای دستورات بالا یه فایل encrypted.bin داریم که عبارت Hello World! به صورت رمزگذاری شده داخل اون ذخیره شده و به با این دستور میشه اون رو رمزگشایی کرد:

openssl enc -aes-256-cbc -d -in encrypted.bin -pass pass:example
// Hello World!

با اجرای این دستور متن داخل فایل رمزگشایی شده و عبارت Hello World! براتون نمایش داده میشه.

بخش دوم: کلیدهای عمومی و خصوصی

در مثال بالا برای رمزگذاری متن از الگوریتم AES استفاده کردیم. یکی از پر استفاده‌ترین و امن‌ترین الگوریتم‌های رمزنگاری RSA هست که در این پست هم از این الگوریتم استفاده خواهد شد. البته الگوریتم‌های رمزنگاری دیگه‌ای هم وجود داره که بنا به کاربردشون میشه ازشون استفاده کرد. به عنوان مثال الگوریتم ECDSA که در صنعت رمزارزها از اون استفاده میشه.

 با دستور زیر یک کلید با طول 1024 بیت با استفاده از الگوریتم RSA ساخته میشه:

openssl genrsa -out key.pem 1024
cat key.pem

با دستور دوم محتویات فایل key.pem براتون نمایش داده میشه که یک رشته نسبتا بلند از کاراکترها خواهد بود. حالا سوال اینه که فرمت pem نشانگر چیه؟

فرمت pem که از عبارت Privacy Enhanced Mail گرفته شده، رایج‌ترین فرمت ذخیره‌سازی گواهی‌های امنیتی و کلیدهای رمزنگاری هست. یک فایل pem در حقیقت یک فایل text هست که می‌تونه حاوی یک کلید خصوصی یا حاوی مجموعه‌ای از گواهی‌های امنیتی باشه که در کنار هم امنیت یک ارتباط رو تضمین می‌کنند. متن این فایل با Base64 ASCII (به این صورت که دیتای باینری به صورت رشته کد ASCII) نمایش داده میشه.

با اجرای دستور:

openssl rsa -in key.pem -des3 -out enc-key.pem

می‌تونیم فایل key.pem رو رمزگذاری کنیم و اون رو در فایل enc-key.pem ذخیره کنیم. دقت داشته باشید که با اجرای دستور، ازتون پسوورد خواهد خواست که این پسوورد برای رمزگشایی فایل در آینده نیاز خواهد بود (در اینجا من پسوورد رو کلمه example وارد کردم).

حالا که کلید خصوصی رو به صورت رمزگذاری شده در اختیار داریم، حالا می‌تونیم کلید عمومی خودمون رو از اون استخراج کنیم:

openssl rsa -in key.pem -pubout -out pub-key.pem

حالا با در اختیار داشتن کلیدهای عمومی و خصوصی، می‌تونیم فایل‌ها رو رمزگذاری کنیم.

اگر خاطرتون باشه یک فایل plain.txt داشتیم که فقط حاوی عبارت Hello World! بود. برای رمزگذاری این فایل با استفاده از کلیدهایی که تولید کردیم، دستور زیر رو اجرا می‌کنیم:

openssl rsautl -encrypt -pubin -inkey public.key -in plaintext.txt -out encrypted.txt

این دستور با استفاده از کلید عمومی که در فایل pub-key.pem قرار دادیم، محتویات فایل plain.txt رو رمزگذاری کرده و در فایل cipher.txt قرار میده. با باز کردن فایل cipher.txt خواهید دید که محتوای اون کاملا نامفهوم و غیرقابل شناسایی هست.

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

openssl pkeyutl -decrypt -in cipher.txt -inkey key.pem -out decrypted.txt

با اجرای این دستور فایل decrypted.txt ایجاد میشه و محتویات فایل cipher.txt که رمزگشایی شده داخلش ذخیره میشه. اگر فایل رو باز کنید عبارت Hello World! رو می‌بینید، دقیقا همون عبارتی که در فایل plain.txt قرار دادیم و اون رو رمزگذاری کردیم. در این دستور برای رمزگشایی از کلید خامی که با الگوریتم RSA تولید کردیم، استفاده شده. بالاتر این کلید خام رو به صورت رمز شده و در فایل enc-key.pem قرار دادیم. دستور زیر رو در نظر بگیرید:

openssl pkeyutl -decrypt -in cipher.txt -inkey enc-key.pem -out decrypted.txt

تنها تفاوتش با دستور قبلی اینه که این بار با استفاده از کلید خصوصی رمز شده enc-key.pem میخوایم فایل رو رمزگشایی کنیم و بعد از اجرای این دستور از ما پسوورد خواهد خواست. این همون پسووردی هست که موقع ایجاد فایل enc.key.pem وارد کردیم (که من example وارد کردم) و با استفاده از این دستور، فایل خروجی decrypted.txt حاوی همون متن Hello World! خواهد بود.

بخش سوم: ایجاد امضای دیجیتال

امضای دیجیتال (Digital Signature) نشان دهنده سالم بودن اطلاعات هست. نحوه عملکرد امضای دیجیتال به این صورته که اطلاعات رو قبل از ارسال Hash می‌کنه و بعد اطلاعات هش شده رو رمزگذاری می‌کنه. هش کردن یعنی تبدیل هر نوع دیتایی به یک رشته از کاراکترها که این رشته‌ها همیشه منحصربفرد هستند. اگر دو بار یک متن رو با الگوریتم مشابه هش کنید، مقادیر هش متفاوت خواهند بود ولی طول اون‌ها یکسان خواهد بود.

با دستور زیر می‌تونیم به وسیله کتابخانه OpenSSL عملیات هش رو انجام بدیم:

openssl dgst -sha1 -out hashed plain.txt

در این دستور آپشن sha1 اشاره به الگوریتم هش داره. الگوریتم‌های هش مختلفی وجود دارن (SHA، SHA1، SHA224، SHA256، MD2، MD5 و …) که هرکدوم کاربرد و مزیت‌های خودشون رو دارن. این دستور یک فایل به اسم hashed ایجاد میکنه و مقدار هش شده فایل plain.txt رو در اون ذخیره می‌کنه.

حالا نیاز داریم امضای دیجیتال این هش رو به دست بیاریم. دستور زیر رو اجرا می‌کنیم:

openssl pkeyutl -sign -in hashed -out signature.txt -inkey key.pem

در اینجا امضای دیجیتال فایل هش شده (hashed) رو با استفاده از کلید خصوصی (key.pem) محاسبه کرده و در فایل signature.txt ذخیره می‌کنیم. در واقع در این دستور ما داریم هش به دست اومده رو رمزگذاری می‌کنیم.

حالا بعد از جابجایی اطلاعات با دستور زیر می‌تونیم تشخیص بدیم که آیا این اطلاعات در مسیر جابجای دچار تغییر (یا همون هک) شدن یا نه:

openssl pkeyutl -verify -sigfile signature.txt -in hashed -inkey pub-key.pem -pubin

در صورتی که اطلاعات سالم باشن پیام Signature Verified Successfully رو دریافت خواهید کرد. در اینجا فایل signature.txt فایلی است که در کنار اطلاعات اصلی برای کلاینت ارسال شده، کلاینت وقتی اطلاعات رو دریافت می‌کنه با استفاده از کلید عمومی pub-key.pem امضای دیجیتال رو رمزگشایی می‌کنه و مقدار هش به دست اومده رو با اطلاعات دریافتی مقایسه می‌کنه، در صورتی که مغایرتی وجود داشته باشه، نشان دهنده دستکاری شدن اطلاعات در مسیر خواهد بود.

بخش چهارم: درخواست امضای گواهی

اولین قدم برای دستیابی به یک گواهی SSL، درخواست امضا برای آن گواهی است. طی درخواست امضای گواهی (CSR: Certificate Signing Request)، کلید عمومی و یه سری اطلاعات کلی درباره شرکت و دامنه‌ای که براش درخواست گواهی دارید، به یک مرجع صدور گواهی معتبر (CA: Certificate Authority) ارسال میشه. اگر این مرجع، اطلاعات دریافتی شما رو تأیید کنه، شما مجاز خواهید بود با جفت کلید عمومی و خصوصی که در اختیار دارین، اطلاعات مبادله کنید. هر CSR یک کلید خصوصی مختص خودش داره که کلید عمومی ازش به دست میاد. با دستور زیر می‌تونید یک CSR ایجاد کنید:

openssl req -new -key key.pem -out yourdomain.csr

بعد از اجرای این دستور، از شما اطلاعات زیر خواسته خواهد شد:

  • کشور
  • استان (ایالت)
  • شهر
  • عنوان رسمی شرکت
  • دپارتمان مربوطه (اختیاری)
  • دامنه‌ای که براش درخواست گواهی SSL دارید (www.yourdomain.com)
  • آدرس ایمیل (اختیاری)
  • پسوورد (اختیاری، معمولا بدون پسوورد)

بعد از اینکه فایل CSR ایجاد شد، با دستور زیر می‌تونید از سالم بودن فایل درخواست مطمئن بشید:

openssl req -text -in yourdomain.csr -noout -verify

در صورتی که فایل بدون مشکل ایجاد شده باشه، پیغام verify OK رو دریافت خواهید کرد.

بخش پنجم: ایجاد گواهی SSL

شما می‌تونید بدون واسطه قرار دادن یک CA (مرجع صدور گواهی معتبر)، اقدام به استفاده از یک گواهی SSL بکنید که به وسیله خودتون امضا شده. این نوع گواهی‌های SSL با استفاده از کلید خصوصی‌ای که خودتون ایجاد کردید امضا میشن و در صورتی که اصول امنیتی در ایجاد اون‌ها رعایت شده باشه، می‌تونن درست به اندازه گواهی‌های SSL یک CA امنیت اطلاعات شما رو تضمین کنن. تنها تفاوت این نوع گواهی SSL اینه که کماکان کلاینت در مرورگر خودش پیغام Connection Not Secure رو دریفات خواهد کرد، چرا که مرورگرها فقط گواهی‌های CA هارو معتبر میدونن. برای همینه که این نوع گواهی SSL معمولا برای سرورهای غیر عمومی استفاده میشه. با دستور زیر می‌تونید همزمان یک کلید خصوصی ایجاد کرده و از همون برای ایجاد CSR استفاده کنید:

openssl req
-newkey rsa:2048 -nodes -keyout domain.key
-x509 -days 365 -out yourdomain.crt

خط دوم یک کلید خصوصی با طول 2048 بیت و با الگوریتم RSA می‌سازه و نهایتا با تعیین تاریخ انقضای یک ساله، CSR رو ایجاد می‌کنه. آپشن x509 به OpenSSL میگه که خودتون قراره گواهی SSL رو امضا کنید و برای CA ارسال نمیشه. اگر از قبل یک کلید خصوصی در اختیار دارید هم می‌تونید از دستور زیر برای ایجاد گواهی SSL استفاده کنید:

openssl req -new -key key.pem -out yourdomain.crt

در حین ایجاد فایل‌های crt هم دقیقا همون مشخصاتی ازتون سوال خواهد شد که در حین ایجاد فایل‌های csr بهشون اشاره کردم.

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

بخش ششم: بررسی امن بودن یک ارتباط بر پایه پروتکل SSL/TLS

یکی دیگه از کاربردهای کتابخانه OpenSSL بررسی کلید عمومی، الگوریتم هش (hash function) و به صورت کلی تأیید امن بود ارتباط با یه سرور هست.

برای دسترسی به کلید عمومی یک وبسایت، می‌تونیم از دستور زیر استفاده کنیم:

openssl s_client -connect www.host.com:443 | openssl x509 -pubkey -noout

با قرار دادن آدرس سایت مورد نظر به جای عبارت host.com خروجی‌ای رو مشاهده می‌کنید که بخشی از اون به شکل زیر خواهد بود و نشانگر کلید عمومی گواهی SSL مورد استفاده در اون سایت خواهد بود.

همچنین برای مشخص شدن الگوریتم هش مورد استفاده در این گواهی، از دستور زیر استفاده می‌کنیم:

openssl s_client -connect host.com:443 < /dev/null 2>/dev/null | openssl x509 -text -in /dev/stdin | grep Signature

با اجرای این دستور یک نمونه از گواهی SSL ثبت شده برای این دامنه دریافت شده و الگوریتم هش استفاده شده در این گواهی نمایشه داده میشه که خروجی مشابه عکس زیر خواهد بود:

طبق این خروجی، الگوریتم هش مورد استفاده در این ارتباط از نوع SHA256 با الگوریتم رمزنگاری RSA هست.

منابع:

A 6 Part Introductory OpenSSL Tutorial (https://bit.ly/3bFEhJh)
OpenSSL Quick Reference Guide (https://bit.ly/2T25Ypo)
PEM, DER, CRT, and CER: X.509 Encodings and Conversions (https://bit.ly/33Y84ZA)
What Is a Digital Signature? (https://bit.ly/3yiqP85)

2 پست نوشته شده
لیسانس برق کنترل دارم. ترم آخر یه درس سه واحدی اختیاری با عنوان "اصول رمزنگاری" برداشتم و از اون روز به بعد هر روز در مورد رمزنگاری میخونم. بعضی روزها 5 دقیقه و بعضی روزها 12 ساعت. Frontend Developer هستم و وقت‌های غیرکاری رو سعی میکنم بیشتر در مورد رمزنگاری و امنیت سایبری یاد بگیرم.
دسته‌ها: امنیت وب، رمزنگاری
  • به اشتراک بگذارید: