اعتبارسنجی با Client Certificate و Mutual Authentication

اصل ایده این مقاله از هک دیشب توییتر ایجاد شد که من اصلاً کاری ندارم سناریوی مطرح شده واقعی هست یا نه ، چیزی که مهم است اینه که در این شرایط کرونایی و اجبار و گسترده شدن دورکاری اعتبارسنجی مطمئن از سرویس هایی است که انتظار می رود یک مدیر سیستم برای سازمان خودش ارائه کند.خلاصه داستان در این سناریو اینه که ما می خواهیم هم وب سرور برای کاربر ، هم کاربر برای وب سرور ، در همان لایه ارتباط اولیه براساس certificate اعتبارسنجی شوند. (قبل از اینکه صفحه ای باز شود)یعنی اگر مثلاً پسورد بخش مدیریت را هم روی اینترنت پخش کنیم تا زمانیکه روی مرورگر گواهینامه مورد تایید مربوط به همان کاربر، نصب نشده باشد، امکان دسترسی نباشد.به عبارت دیگر یک certificate می سازیم ، به اپراتورها و کاربران مجاز فایلش را می دهیم که روی سیستم (مرورگر) خود نصب کنند و در سرویس خودمان (در این مقاله وب سرور apache) تعریف می کنیم برای فلان URI فقط کاربرانی را مجاز بدان که این گواهینامه روی مرورگر آن ها نصب شده است. ...بعد بقیه مراحل سرو وب را انجام بده و پسورد و نام کاربری و ... بپرس.بدیهی است که روی IIS و nginx و انواع سرویس های دیگر هم می توان چنین سناریویی پیاده کرد.کلاینت سرتیفیکیت که مشخص است چیست. گواهینامه ای که کاربر را معرفی و تایید می کند. سرور سرتیفیکیت هم (حداقل در این مقاله) همان https متداول است با گواهینامه و CA خودمان.در اعتبارسنجی ، اگر 2=< طرفین یکدیگر را اعتبارسنجی کنند ، به این وضعیت ؛ Mutual Authentication می گویند. در پروتکل هایی مثل ssh الزامی است و در پروتکل هایی مثل TLS آپشنال.اعتبارسنجی براساس چیزی که :می دانید ؛ مثل پسورددارید ؛ مثل کلید یا کارتهستید ؛ مثل انواع روش های بیومتریک (اثر انگشت و قرنیه و صدا و ...)انجام می شود.هر کدام از اینها یک فاکتور هستند و وقتی از مثلاً 2 یا چندتاشون همزمان استفاده می کنید اعتبارسنجی چندفاکتوری انجام داده اید.مثلاً در اینجا اگر سناریو را صفحه مدیریت یک سامانه وبی در نطر بگیریم، کاربر هم باید گواهینامه معتبر و صحیح را داشته باشد هم نام کاربری/پسورد را بداند.یعنی علاوه براینکه صفحه مدیریت ما username/password دارد ، برای دسترسی به آن به نصب certificate معتبر روی مرورگر هم نیاز باشد.مرحله، در اعتبارسنجی، یک چیز دیگر است ، یعنی وقتی تعریف می کنیم اول این اعتبارسنجی انجام شود و اگر موفقیت آمیز بود دومی انجام شود. ممکن است در مواقعی خود [اعتبارسنجی مرحله بعد] شامل اطلاعاتی باشد که می خواهیم حتی الامکان از دید عموم مخفی بمانند، مثلاً شاید نخواهیم نفوذگر مراحل بعدی اعتبارسنجی را بداند تا برای آن ها چاره ای کند. منظور از (Certificate Authority (CA اونی هست که گواهینامه ها را صادر،امضا،مدیریت،تایید و ... می کند. Large organizations or government bodies may have their own PKIs (public key infrastructure), each containing their own CAs. Any site using self-signed certificates acts as its own CA.ما اینجا از OpenSSL استفاده می کنیم و با CA خودمون کار این صدور و امضا و تایید گواهینامه ها را انجام می دهیم. مدیریت و نکات CA البته خیلی بیشتر از مواردی هست که در این مقاله ذکر می شود. ما فقط اینجا برای همین سناریو استفاده می کنیم.من از centos7 استفاده می کنم و با دستور ذیل ابتدا apache و mod_ssl و OpenSSL را نصب کرده ام.yum install httpd mod_ssl opensslساخت CA و صدور و امضا گواهینامه با OpenSSLبا دستور openssl version -a مسیر فایل های های آن را می بینیم.فایل openssl.cnf تنظیمات پیش فرض است که openssl استفاده می کند. بخش هایی از آن را اختصاصی می کنیم.سپس ساختار پوشه هایی را که می خواهیم برای کلاینت و سرور می سازیم :#cd /etc/pki/tls/ #mkdir myOrg #cd myOrg #mkdir CA server server/certificates server/requests server/keys user user/certificates user/requests user/keysبا این پوشه بندی خیلی تر و تمیز مشخص هست certificate های هر کدام کجان ، کجا keyها هست و کجا requestها.همچنین به یک فایل بنام serial نیاز دارید که last unique serial number assigned to a generated certificate را نگه داری می کند. یک فایل txt دیتابیس هم در تنظیمات معرفی شده که می سازیم.[root@localhost myOrg]# echo &quot01&quot > serial [root@localhost myOrg]# touch index.txtاول کلید CA بسازیم :#openssl genrsa -out ./CA/myOrg.key 1024حالا CA certificate request را بسازیم(فایل csr که مشخصات درخواست کننده گواهینامه در آن است و بر مبنای آن گواهینامه صادر می شود).دقت کنید در قبلی کلید CA را ساختیم و الان می گوییم درخواست صدور گواهینامه را براساس این کلید بساز. چند سئوال می کنه که همون اول در openssl.cnf تنظیم کردیم اما می تونید اینجا پیش فرض را تغییر دهید.بخش هایی که مربوط به common name و email و کلاً درباره یک entity مشخص و معرفه هست را پر کنید که بعداً اگر لازم شد بتوانید براساس اینها گواهینامه را authorization هم بکنید.برای ساخت csr و گواهینامه یک پسورد هم از شما خواسته می شود. می توانید خالی رها کنید، اما برای امنیت بیشتر، اگر این پسورد را وارد کنید برای استفاده از گواهینامه باید پسورد هم وارد شود. به این ترتیب اگر فقط فایل های مربوط به گواهینامه ها را کسی داشته باشد باز نمی تواند استفاده کند یا مثلاً در مورد csr بر مبنای آن گواهینامه صادر کند.در دستور ذیل براساس کلیدی که ساختیم یک درخواست گواهینامه (CSR) می سازیم.A CSR or Certificate Signing request is a block of encoded text that is given to a Certificate Authority when applying for an SSL Certificate. It is usually generated on the server where the certificate will be installed and contains information that will be included in the certificate such as the organization name, common name (domain name), locality, and country. It also contains the public key that will be included in the certificate. A private key is usually created at the same time that you create the CSR, making a key pair.A certificate authority will use a CSR to create a certificate.#openssl req -new -key ./CA/myOrg.key -out ./CA/myOrg.csrحالا یک گواهینامه self-sign برای CA خودمون براساس این درخواست CSR صادر می کنیم.#openssl x509 -req -days 3650 -in ./CA/myOrg.csr -out ./CA/myOrg.crt -signkey ./CA/myOrg.keyما الان گواهینامه و کلید خود CA را ساختیم و داریم. حالا باید برای سرور و یوزر بسازیم.این گواهینامه ای را که برای CA ساختیم بعداً به مرورگر import می کنیم تا CA شخصی ما را بعنوان یک CA معتبر بشناسد.برای دیدن و چک کردن گواهینامه ای که ساخته اید از دستور ذیل استفاده کنید :#openssl x509 -in ./CA/myOrg.crt -textساخت گواهینامه سرور و تنظیم apache و سرور https معتبر برای مرورگر کاربرالان باید برای وب سرورمون گواهینامه ایجاد کنیم. در مرحله قبل که گواهینامه خود CA را ساختیم مجبور بودیم self-sign کنیم چون کس دیگری نبود که این گواهینامه را امضا کند. (خودش root هست)اما الان که CA داریم با کلید CA برای بقیه گواهینامه صادر می کنیم.اول کلید خصوصی وب سرور را می سازیم و یک پسورد هم انتخاب می کنیم که دست هر کس افتاد برای استفاده و صدور گواهینامه به پسورد هم احتیاج داشته باشد. در اینجا ما باید یک fully qualified DNS name هم برای آدرس اون سرور تعریف کنیم. من می زنم myorg.ir#openssl genrsa -des3 -out ./server/keys/myorg.ir.key 1024حالا certificate request یا csrش را می سازیم که گواهینامه با این کلید خصوصی ساختیم و براساس این اطلاعات صادر می شود.کلاینت ما چک می کند که گواهینامه با این اطلاعات تطابق دارد یا خیر. اون آدرس fqdn برای همین جا لازم است که مثلاً ببیند https://myorg.ir با گواهینامه این که ارائه می کند یکی هست یا نه.حالا باید این csr سرور را که با کلیدخصوصی خودش ساختیم با کلید CA امضا کنیم.دقت بفرمایید از فایل هایی که در قبل ساختیم در این مرحله چطور استفاده می کنیم.#openssl ca -days 3650 -in server/requests/myorg.ir.csr -cert ./CA/myOrg.crt -keyfile ./CA/myOrg.key -out ./server/certificates/myorg.ir.crt -config ../openssl.cnf2تا y می زنیم و مثل قبل برای چک کردن گواهینامه صادر شده برای سرور از دستور ذیل استفاده می کنیم.#openssl x509 -in ./server/certificates/myorg.ir.crt -textحالا 3 تا فایلی را که باید به وب سرور معرفی کنیم که موقع سرویس دادن استفاده کند و سرویس https بگیریم tar می کنیم و در جایی که در تنظیمات وب سرور آدرس می دهیم کپی می کنیم.#tar cvf ./myorg_certs.tar ./server/certificates/myorg.ir.crt ./server/keys/myorg.ir.key ./CA/myOrg.crt#cp myorg_certs.tar /etc/httpd/conf/certs/*وقتی tar می کنیم خودش ساختار دایرکتوری ها را حفظ می کند.من مثلاً به /etc/httpd/conf/certs/ کپی کردم ، cd می کنم اونجا و extract می کنم :#tar xvf myorg_certs.tarبرای تنظیم apache من مستقیم روی httpd.conf تنظیمات را اعمال می کنم ، ممکن است شما فایل conf دیگری بسازید یا ...این تنظیمات را در config خود باید اضافه کنید تا گواهینامه ها برای ارائه سرویس https تعریف شوند.SSLEngine on SSLCertificateFile conf/certs/server/certificates/myorg.ir.crt SSLCertificateKeyFile conf/certs/server/keys/myorg.ir.key SSLCACertificateFile conf/certs/CA/myOrg.crtواقعیتش باید با تنظیم apache (یا سرور و سرویسی که تنظیم می کنید) راحت باشید، یکسری موارد بدیهی هم هست مثلاً در فایل etc/hosts/ باید myorg.ir را اضافه کنید و ...وقتی بخواهید httpd را استارت کنید همان پسوردی را که تنظیم کرده بودید می خواهد زیرا می خواهد از این گواهینامه استفاده کند. (یا پسورد نگذارید یا برای اینکه در هنگام start و restart پسورد نپرسد یک جستجو کوچک بکنید)نمونه تنظیم virtualhost ، خیلی خطی و مستقیم و ساده :<VirtualHost myorg.ir:443> ServerName myorg.ir SSLEngine on SSLCertificateFile conf/certs/server/certificates/myorg.ir.crt SSLCertificateKeyFile conf/certs/server/keys/myorg.ir.key SSLCACertificateFile conf/certs/CA/myOrg.crt DocumentRoot &quot/var/www/html&quot <Directory &quot/var/www/html&quot> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> </VirtualHost>باید در نهایت از وب سرورتون همچین چیزی بگیرید.از اونجاییکه گواهینامه این وب سایت که وب سرور ارائه می کند توسط CA خودمون امضا شده و در لیست CAهای مورد تایید مرورگرها نیست خطای certificate error طبیعی هست. حالا باید CA خودمون را هم به مرورگر کاربر معرفی می کنیم که علامت قفلش کامل و سبز و بدون خطا شود.برای اینکار راحت ترین راه این است که فایل گواهینامه CA را که اینجا myOrg.crt است ، بگذاریم روی وب سایت و با مرورگر باز کنیم.اما ممکنه به خطا بخورید. بنابراین فایلش را save کنید و از این مسیر در فایرفاکس و مشابهش در سایر مرورگرها preferences->certificate management->import آن را در زبانه server ایمپورت کنید. نتیجه :ساخت گواهینامه برای کاربر و الزام وب سرور به اعتبارسنجی آنحالا می خواهیم برای فلان کاربر گواهینامه بسازیم.در مرحله قبل حتی شاید راحت تر باشید پسورد ست نکنید اما اینجا حتماً برای استفاده از گواهینامه پسورد تنظیم کنید تا اگر فایل گواهینامه بدست کسی افتاد نتواند نصب کند و خود را جای فلان کاربر جا بزند.برگردیم داخل پوشه /etc/pki/tls/myOrg/ و حالا برای user کلید و CSR و CRT(گواهینامه) بسازیم.مثل قبل، اول کلیدش را بسازیم :#openssl genrsa -des3 -out ./user/keys/follanuser@myorg.ir.key 1024بعد csrش را بسازیم :#openssl req -new -key ./user/keys/follanuser@myorg.ir.key -out ./user/requests/follanuser@myorg.ir.csrدقت کنید که اینها را وارد نمایید :Common Name (eg, your name or your server's hostname) []:follan user Email Address [info@myorg.ir]:follanuser@myorg.irبعد برایش گواهینامه بسازیم و با کلید CA امضا کنیم :#openssl ca -in ./user/requests/follanuser@myorg.ir.csr -cert ./CA/myOrg.crt -keyfile ./CA/myOrg.key -out ./user/certificates/follanuser@myorg.ir.crtبعد دوباره چک کنیم گواهینامه اش سالم و صحیح است.#openssl x509 -in ./user/certificates/follanuser@myorg.ir.crt -textو حالا این گواهینامه را در مرورگر وی نصب کنیم که وقتی می خواهد به آدرس تنظیم شده دسترسی پیدا کند باید ارائه دهد.یکسری مرورگرها مثل فایرفاکس فرمت PKCS#12 را پشتیبانی می کنند بنابراین از دستور ذیل برای تبدیل گواهینامه کاربر که ساخته ایم به p12 استفاده می کنیم.#openssl pkcs12 -export -clcerts -in ./user/certificates/follanuser@myorg.ir.crt -inkey ./user/keys/follanuser@myorg.ir.key -out ./user/certificates/follanuser@myorg.ir.p12یک فایل p12 بدست می آوریم و بعد این فایل را می رسانیم به دست طرف.برای نصبش هم همان مسیر preferences->certificate management->import در فایرفاکس یا مسیر مشابهی در سایر مرورگرها که گواهینامه ها از آنجا مدیریت می شوند را استفاده می کنیم.در ادامه نصب گواهینامه کاربری توضیح داده شده است.تنظیم apache برای الزام کاربر به ارائه certificateاین 2 خط را به تنظیمات همان virtualhost بالا اضافه می کنیم. چون CA ما خودش root است depth را 2 تنظیم کرده ایم. برای اطلاعات بیشتر درباره verify depth اینجا را در مستندات apache ببینید.SSLVerifyClient require SSLVerifyDepth 2در اینجا من همون داخل تنظیمات virtualhost دو خط بالا را اضافه کردم و شرطی چیزی نگذاشتم ،کلاً برای دیدن myorg.ir باید certificate داشت.اما طبیعتاً ممکن است در سناریوی شما چک کردن اطلاعات گواهینامه برای دسترسی به یک مسیر خاص و پیچیدگی بیشتر نیز نیاز باشد.بدون نصب گواهینامه کاربر چنین خطایی خواهید گرفت : حالا گواهینامه کاربر را در بخش your certificates وارد می کنیم :و میشه :و دفعه بعد که می خواهیم سایت را باز کنیم ، وب سرور به مرورگر می گوید گواهینامه ات را ارائه بده و مرورگر از ما می پرسد کدام گواهینامه :و بعد که انتخاب و ok کردیم :داخل بخش <Directory> تنظیمات apache می توانید بصورت انتخابی برای دایرکتوری ها و مسیرهای مشخص از دستورات ذیل استفاده نمایید و ذکر کنید چه کسی؟ کدام گواهینامه؟ کجا؟ :<IfDefine SSL> SSLRequireSSL SSLRequire %{SSL_CLIENT_S_DN_CN} eq &quotfollan user&quot </IfDefine>البته ظاهرا SSLRequire دیگر deprecate شده که اینجا را برای اطلاعات بیشتر و مستندات mod_ssl ببینید.جزئیات بیشتر را لطفاً سرچ کنید در مستندات apache کامل نکات هست. من خیلی مستقیم و خلاصه برای یک ادمین سیستم فرآیند کار را شرح دادم. البته که نکات و جزئیات و ترفند و ... زیاد هست. اما کلیت داستان برای سرویس های مختلف همین است.