JavaRush /مدونة جافا /Random-AR /من HTTP إلى HTTPS
Viacheslav
مستوى

من HTTP إلى HTTPS

نشرت في المجموعة
من HTTP إلى HTTPS - 1
محتوى:

مقدمة

في العالم الحديث، لا يمكنك العيش بدون تطبيقات الويب. وسنبدأ بتجربة صغيرة. عندما كنت طفلاً، أتذكر كيف كانت جميع الأكشاك تبيع صحيفة مثل "الحجج والحقائق". كنت أتذكرها لأنه، وفقًا لتصوري الشخصي منذ الطفولة، كانت هذه الصحف تبدو دائمًا غريبة. وقررت ما إذا كان ينبغي لنا الذهاب إلى موقعهم على الإنترنت:
من HTTP إلى HTTPS - 2
إذا انتقلنا إلى مساعدة Google Chrome، فسنقرأ أن هذا الموقع لا يستخدم اتصالاً آمنًا وأن المعلومات التي تتبادلها مع الموقع قد تكون متاحة لأطراف ثالثة. دعونا نتحقق من بعض الأخبار الأخرى، على سبيل المثال أخبار سانت بطرسبورغ من فونتانكا، وهي وسيلة إعلام إلكترونية:
من HTTP إلى HTTPS - 3
كما ترون، لا يواجه موقع Fontanka أي مشاكل أمنية بناءً على هذه البيانات. اتضح أن موارد الويب قد تكون أو لا تكون آمنة. ونرى أيضًا أن الوصول إلى الموارد غير المحمية يتم عبر بروتوكول HTTP. وإذا كان المورد محميًا، فسيتم تبادل البيانات باستخدام بروتوكول HTTPS، حيث يعني حرف S في النهاية "آمن". تم وصف بروتوكول HTTPS في مواصفات rfc2818: " HTTP Over TLS ". دعونا نحاول إنشاء تطبيق الويب الخاص بنا ونرى بأنفسنا كيف يعمل. وعلى طول الطريق سوف نفهم الشروط.
من HTTP إلى HTTPS - 4

تطبيق ويب بلغة جافا

لذلك، نحن بحاجة إلى إنشاء تطبيق ويب بسيط جدًا في Java. أولاً، نحتاج إلى تطبيق Java نفسه. للقيام بذلك، سوف نستخدم نظام البناء التلقائي لمشروع Gradle. سيسمح لنا هذا بعدم إنشاء بنية الدليل الضرورية يدويًا + سيقوم Gradle بإدارة جميع المكتبات اللازمة للمشروع لنا والتأكد من توفرها عند تنفيذ التعليمات البرمجية. يمكنك قراءة المزيد عن Gradle في مراجعة قصيرة: " مقدمة موجزة عن Gradle ". دعونا نستخدم Gradle Init Plugin ونقوم بتشغيل الأمر:
gradle init --type java-application
بعد ذلك، دعونا نفتح برنامج البناء النصي build.gradle، الذي يصف المكتبات التي يتكون منها مشروعنا، والتي سيوفرها لنا Gradle. دعنا نضيف هناك تبعية على خادم الويب الذي سنجربه:
dependencies {
    // Web server
    implementation 'io.undertow:undertow-core:2.0.20.Final'
     // Use JUnit test framework
     testImplementation 'junit:junit:4.12'
}
لكي يعمل تطبيق الويب، نحتاج بالتأكيد إلى خادم ويب حيث سيتم استضافة تطبيقنا. هناك مجموعة كبيرة ومتنوعة من خوادم الويب، ولكن أهمها: Tomcat، وJetty، وUndertow. هذه المرة سوف نختار Undertow. لفهم كيف يمكننا العمل مع خادم الويب الخاص بنا، دعنا نذهب إلى موقع Undertow الرسمي ونذهب إلى قسم الوثائق . لقد قمت أنا وأنت بتوصيل تبعية لـ Undertow Core، لذلك نحن مهتمون بالقسم الذي يتحدث عن هذا Core بالذات، أي جوهر أساس خادم الويب. أسهل طريقة هي استخدام Builder API لـ Undertow:
public static void main(String[] args) {
	Undertow server = Undertow.builder()
            .addHttpListener(8080, "localhost")
            .setHandler(new HttpHandler() {
                @Override
                public void handleRequest(final HttpServerExchange exchange) throws Exception {
                    exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
                    exchange.getResponseSender().send("Hello World");
                }
            }).build();
    server.start();
}
إذا قمنا بتنفيذ التعليمات البرمجية، فيمكننا الانتقال إلى مورد الويب التالي:
من HTTP إلى HTTPS - 5
إنه يعمل ببساطة. بفضل واجهة برمجة تطبيقات Undertow Builder، أضفنا مستمع HTTP إلى المضيف المحلي والمنفذ 8080. يتلقى هذا المستمع الطلبات من متصفح الويب ويعيد السلسلة "Hello World" ردًا على ذلك. تطبيق ويب رائع. ولكن كما نرى، فإننا نستخدم بروتوكول HTTP، أي. هذا النوع من تبادل البيانات غير آمن. دعونا نتعرف على كيفية تنفيذ عمليات التبادل باستخدام بروتوكول HTTPS.
من HTTP إلى HTTPS - 6

متطلبات HTTPS

لفهم كيفية تمكين HTTPS، دعنا نعود إلى مواصفات HTTPS: " RFC-2818: HTTP Over TLS ". وفقًا للمواصفات، يتم نقل البيانات الموجودة في بروتوكول HTTPS عبر بروتوكولات التشفير SSL أو TLS. غالبًا ما يتم تضليل الناس بمفهوم SSL وTLS. في الواقع، لقد تطورت SSL وغيرت إصداراتها. وفي وقت لاحق، أصبح TLS الخطوة التالية في تطوير بروتوكول SSL. أي أن TLS هو ببساطة إصدار جديد من SSL. تقول المواصفات ذلك: "SSL، وTLS الذي يخلفه". لذلك، علمنا أن هناك بروتوكولات تشفير SSL/TLS. SSL هو اختصار لطبقة المقابس الآمنة ويُترجم على أنه "طبقة المقابس الآمنة". المقبس المترجم من الإنجليزية هو موصل. يستخدم المشاركون في نقل البيانات عبر الشبكة مآخذ التوصيل كواجهة برمجة (أي واجهة برمجة التطبيقات) للتواصل مع بعضهم البعض عبر الشبكة. يعمل المتصفح كعميل ويستخدم مقبس العميل، والخادم الذي يتلقى الطلب ويصدر استجابة يستخدم مقبس الخادم. ومن بين هذه المآخذ يتم تبادل البيانات. ولهذا السبب كان البروتوكول يسمى في الأصل SSL. لكن مر الوقت وتطور البروتوكول. وفي مرحلة ما، أصبح بروتوكول SSL هو بروتوكول TLS. TLS هو اختصار لـ Transport Layer Security. يعتمد بروتوكول TLS بدوره على إصدار مواصفات بروتوكول SSL 3.0. يعد بروتوكول TLS موضوعًا لمقالات ومراجعات منفصلة، ​​لذلك سأشير ببساطة إلى المواد التي أجدها مثيرة للاهتمام: باختصار، أساس HTTPS هو مصافحة TLS والتحقق من "هوية الخادم" (أي تعريف الخادم) باستخدام شهادته الرقمية. انه مهم. دعونا نتذكر هذا، لأنه... وسوف نعود إلى هذه الحقيقة لاحقا. لذلك، استخدمنا سابقًا HttpListener لإخبار الخادم بكيفية العمل عبر بروتوكول HTTP. إذا أضفنا في المثال أعلاه HttpListener للعمل عبر HTTP، فللعمل عبر HTTPS نحتاج إلى إضافة HttpsListener:
من HTTP إلى HTTPS - 7
ولكن لإضافته نحتاج إلى SSLContext. ومن المثير للاهتمام أن SSLContext ليس فئة من Undertow، ولكن javax.net.ssl.SSLContext. تعد فئة SSLContext جزءًا مما يسمى " Java Secureock Extension " (JSSE) - وهو امتداد Java لضمان أمان الاتصال بالإنترنت. تم وصف هذا الامتداد في " الدليل المرجعي لـ Java Secure Connector Extension (JSSE) ". كما ترون من الجزء التمهيدي من الوثائق، توفر JSSE إطار عمل وتنفيذ Java لبروتوكولي SSL وTLS. كيف نحصل على نص SSLContext؟ افتح JavaDoc SSLContext وابحث عن طريقة getInstance . كما ترون، للحصول على نص SSLContext، نحتاج إلى تحديد الاسم "Secure Switch Protocol". يشير وصف المعلمات إلى أنه يمكن العثور على هذه الأسماء في " وثائق اسم الخوارزمية القياسية لهندسة تشفير Java ". لذلك، دعونا نتبع التعليمات وننتقل إلى الوثائق. ونرى أنه يمكننا الاختيار بين SSL وTLS:
من HTTP إلى HTTPS - 8
الآن نفهم أننا بحاجة إلى إنشاء SSLContext على النحو التالي:
public SSLContext getSSLContext() {
	// 1. Получаем контекст, в рамках которого будем работать по TLS протоколу
	SSLContext context = null;
	try {
		context = SSLContext.getInstance("TLS");
	} catch (NoSuchAlgorithmException e) {
		throw new IllegalStateException(e);
	}
	return context;
}
بعد إنشاء سياق جديد، نتذكر أن SSLContext تم وصفه في " الدليل المرجعي لـ Java Secure Plug Extension (JSSE) ". نقرأ ونرى أنه "يجب تهيئة نص SSLContext الذي تم إنشاؤه حديثًا عن طريق استدعاء طريقة init". أي أن خلق السياق ليس كافيًا. يجب أن تتم تهيئته. وهذا أمر منطقي، لأنه فيما يتعلق بالأمان، قلنا لك فقط أننا نريد استخدام بروتوكول TLS. لتهيئة SSLContext نحتاج إلى توفير ثلاثة أشياء: KeyManager وTrustManager وSecureRandom.
من HTTP إلى HTTPS - 9

KeyManager

KeyManager هو مدير رئيسي. وهو مسؤول عن "بيانات اعتماد المصادقة" التي يجب تقديمها لأي شخص يتصل بنا. يمكن ترجمة بيانات الاعتماد على أنها هوية. الهوية مطلوبة حتى يتأكد العميل من أن الخادم هو الذي يدعي أنه يمكن الوثوق به. ما الذي سيتم استخدامه كتعريف؟ كما نتذكر، يتم التحقق من هوية الخادم من خلال الشهادة الرقمية للخادم. ويمكن تمثيل هذه العملية على النحو التالي:
من HTTP إلى HTTPS - 10
بالإضافة إلى ذلك، يقول " الدليل المرجعي لـ JSSE: كيف يعمل SSL " أن SSL يستخدم "التشفير غير المتماثل"، مما يعني أننا بحاجة إلى زوج مفاتيح: مفتاح عام ومفتاح خاص. بما أننا نتحدث عن التشفير، فإن "هندسة تشفير جافا" (JCA) تدخل حيز التنفيذ. توفر Oracle مستندًا ممتازًا حول هذه البنية: " الدليل المرجعي لهندسة تشفير Java (JCA) ". بالإضافة إلى ذلك، يمكنك قراءة نظرة عامة مختصرة عن JCA على JavaRush: " هندسة تشفير Java: التعارف الأول ." لذا، لتهيئة KeyManager، نحتاج إلى KeyStore، الذي سيقوم بتخزين شهادة الخادم الخاص بنا. الطريقة الأكثر شيوعًا لإنشاء مخزن المفاتيح والشهادات هي الأداة المساعدة keytool، المضمنة مع JDK. يمكن رؤية مثال في وثائق JSSE: " إنشاء ملف تخزين مفاتيح لاستخدامه مع JSSE ". لذلك، نحتاج إلى استخدام الأداة المساعدة KeyTool لإنشاء مخزن مفاتيح وكتابة الشهادة هناك. ومن المثير للاهتمام، أنه تم تحديد إنشاء المفاتيح مسبقًا باستخدام -genkey، ولكن يوصى الآن باستخدام -genkeypair. سنحتاج إلى تحديد الأمور التالية:
  • الاسم المستعار : الاسم المستعار أو ببساطة الاسم الذي سيتم حفظ الإدخال به في Keystore
  • keyalg : خوارزمية تشفير المفاتيح. دعونا نختار خوارزمية RSA، والتي تعد في الأساس حلاً قياسيًا لغرضنا.
  • حجم المفتاح : حجم المفتاح (بالبت). الحد الأدنى للحجم الموصى به هو 2048، لأن... لقد تم بالفعل تصدع حجم أصغر. يمكنك قراءة المزيد هنا: " شهادة SSL في 2048 بت ".
  • dname : الاسم المميز، الاسم المميز.
من المهم أن نفهم أنه سيتم مقارنة المورد المطلوب (على سبيل المثال، https://localhost) به. وهذا ما يسمى "مطابقة الموضوع cn".
  • الصلاحية : المدة بالأيام التي تكون فيها الشهادة التي تم إنشاؤها صالحة، أي. صالح.
  • ext : ملحق الشهادة المحدد في " الامتدادات المسماة ".
بالنسبة للشهادات الموقعة ذاتيًا (أي الشهادات التي تم إنشاؤها بشكل مستقل)، يجب عليك تحديد الامتدادات التالية:
  • -ext san:critical=dns:localhost,ip:127.0.0.1 > لإجراء مطابقة الموضوع بواسطة SubjectAlternativeName
  • -ext bc=ca:false > للإشارة إلى عدم استخدام هذه الشهادة لتوقيع شهادات أخرى
لنقم بتشغيل الأمر (على سبيل المثال لنظام التشغيل Windows):
keytool -genkeypair -alias ssl -keyalg RSA -keysize 2048 -dname "CN=localhost,OU=IT,O=Javarush,L=SaintPetersburg,C=RU,email=contact@email.com" -validity 90 -keystore C:/keystore.jks -storepass passw0rd -keypass passw0rd -ext san:critical=dns:localhost,ip:127.0.0.1 -ext bc=ca:false
لأن سيتم إنشاء الملف، تأكد من أن لديك كافة الحقوق لإنشاء الملف. بالإضافة إلى ذلك، من المحتمل أن ترى نصيحة مثل هذه:
من HTTP إلى HTTPS - 11
قيل لنا هنا أن JKS هو تنسيق خاص. الملكية تعني أنها ملكية خاصة للمؤلفين وهي مخصصة للاستخدام في Java فقط. عند العمل مع أدوات مساعدة تابعة لجهات خارجية، قد ينشأ تعارض، ولهذا السبب يتم تحذيرنا. بالإضافة إلى ذلك، قد نتلقى الخطأ: The destination pkcs12 keystore has different storepass and keypass. يحدث هذا الخطأ بسبب اختلاف كلمات المرور الخاصة بالإدخال في Keystore ومخزن المفاتيح نفسه. كما تقول وثائق أداة المفاتيح ، "على سبيل المثال، تتطلب معظم أدوات الجهات الخارجية أن يكون كلمة المرور وكلمة المرور في مخزن المفاتيح PKCS #12 متطابقتين." يمكننا تحديد المفتاح بأنفسنا (على سبيل المثال، -destkeypassentrypassw). لكن من الأفضل عدم انتهاك المتطلبات وتعيين كلمة المرور نفسها. لذلك قد يبدو الاستيراد كما يلي:
keytool -importkeystore -srckeystore C:/keystore.jks -destkeystore C:/keystore.jks -deststoretype pkcs12
مثال النجاح:
من HTTP إلى HTTPS - 12
لتصدير الشهادة إلى ملف، يمكنك تشغيل:
keytool -export -alias ssl -storepass passw0rd -file C:/server.cer -keystore C:/keystore.jks
بالإضافة إلى ذلك، يمكننا الحصول على محتويات Keystore مثل هذا:
keytool -list -v -keystore C:/keystore.jks -storepass passw0rd
عظيم، لدينا الآن مخزن مفاتيح يحتوي على الشهادة. الآن يمكنك الحصول عليه من الكود:
public KeyStore getKeyStore() {
	// Согласно https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyStore
	try(FileInputStream fis = new FileInputStream("C:/keystore.jks")){
		KeyStore keyStore = KeyStore.getInstance("pkcs12");
		keyStore.load(fis, "passw0rd".toCharArray());
		return keyStore;
	} catch (IOException ioe) {
		throw new IllegalStateException(ioe);
	} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException e) {
		throw new IllegalStateException(e);
	}
}
إذا كان هناك KeyStore، فيمكننا تهيئة KeyManager:
public KeyManager[] getKeyManagers(KeyStore keyStore) {
	String keyManagerAlgo = KeyManagerFactory.getDefaultAlgorithm();
	KeyManagerFactory keyManagerFactory = null;
	try {
		keyManagerFactory = KeyManagerFactory.getInstance(keyManagerAlgo);
		keyManagerFactory.init(keyStore, "passw0rd".toCharArray());
		return keyManagerFactory.getKeyManagers();
	} catch (NoSuchAlgorithmException e) {
		throw new IllegalStateException(e);
	} catch (UnrecoverableKeyException | KeyStoreException e) {
		throw new IllegalStateException(e);
	}
}
لقد تم تحقيق هدفنا الأول. يبقى أن نفهم ما هو TrustManager. تم وصف TrustManager في وثائق JSSE في القسم " واجهة TrustManager ". إنه مشابه جدًا لـ KeyManager، لكن الغرض منه هو التحقق مما إذا كان يمكن الوثوق بالشخص الذي يطلب الاتصال. بصراحة، هذا هو KeyManager في الاتجاه المعاكس =) لا نحتاج إلى TrustManager، لذلك سنمرر قيمة null. سيتم بعد ذلك إنشاء TrustManager الافتراضي الذي لا يتحقق من قيام المستخدم النهائي بتقديم الطلبات إلى خادمنا. تقول الوثائق ذلك: "سيتم استخدام التنفيذ الافتراضي". نفس الشيء مع SecureRandom. إذا حددنا قيمة فارغة، فسيتم استخدام التنفيذ الافتراضي. دعونا نتذكر فقط أن SecureRandom هي فئة JCA وقد تم وصفها في وثائق JCA في القسم " فئة SecureRandom ". بشكل عام، قد يبدو التحضير مع مراعاة جميع الطرق الموضحة أعلاه كما يلي:
public static void main(String[] args) {
	// 1. Подготавливаем приложение к работе по HTTPS
	App app = new App();
	SSLContext sslContext = app.getSSLContext();
	KeyStore keyStore = app.getKeyStore();
	KeyManager[] keyManagers = app.getKeyManagers(keyStore);
	try {
		sslContext.init(keyManagers, null, null);
	} catch (KeyManagementException e) {
		throw new IllegalStateException(e);
	}
كل ما تبقى هو تشغيل الخادم:
// 2. Поднимаем server
 	int httpsPort = 443;
	Undertow server = Undertow.builder()
            .addHttpsListener(httpsPort, "localhost", sslContext)
            .setHandler(new HttpHandler() {
                @Override
                public void handleRequest(final HttpServerExchange exchange) throws Exception {
                    exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
                    exchange.getResponseSender().send("Hello World");
                }
            }).build();
	server.start();
}
هذه المرة سيكون خادمنا متاحًا على العنوان التالي، https://localhost:443 ومع ذلك، سنستمر في تلقي خطأ يفيد بأنه لا يمكن الوثوق بهذا المورد:
من HTTP إلى HTTPS - 13
دعونا نتعرف على الخطأ في الشهادة وماذا نفعل حيال ذلك.
من HTTP إلى HTTPS - 14

إدارة الشهادات

لذلك، خادمنا جاهز بالفعل للعمل عبر HTTPS، لكن العميل لا يثق به. لماذا؟ دعونا نلقي نظرة:
من HTTP إلى HTTPS - 15
والسبب هو أن هذه الشهادة هي شهادة موقعة ذاتيًا. تشير شهادة SSL الموقعة ذاتيًا إلى شهادة المفتاح العام الصادرة والموقعة من قبل نفس الشخص الذي تحدده. أي أنه لم يتم إصدارها من قبل أي مرجع مصدق محترم (CA، المعروف أيضًا باسم المرجع المصدق). تعمل هيئة التصديق كوصي وتشبه كاتب العدل في الحياة اليومية. ويؤكد أن الشهادات التي يصدرها موثوقة. يتم دفع خدمة إصدار الشهادات من قبل هذه المراجع، لذلك لا يحتاج أحد إلى فقدان الثقة والمخاطر المتعلقة بالسمعة. بشكل افتراضي، هناك العديد من المراجع المصدقة الموثوق بها. هذه القائمة قابلة للتحرير. ولكل نظام تشغيل إدارته الخاصة لقائمة المراجع المصدقة. على سبيل المثال، يمكن قراءة إدارة هذه القائمة في Windows هنا: " إدارة شهادات الجذر الموثوقة في Windows ". لنضيف الشهادة إلى الشهادات الموثوقة كما هو موضح في رسالة الخطأ. للقيام بذلك، قم أولاً بتنزيل الشهادة:
من HTTP إلى HTTPS - 16
في نظام التشغيل Windows، اضغط على Win+R وقم بالتنفيذ mmcلاستدعاء وحدة التحكم. بعد ذلك، اضغط على Ctrl+M لإضافة قسم "الشهادات" إلى وحدة التحكم الحالية. بعد ذلك، في القسم الفرعي "المراجع الموثوقة لشهادات الجذر"، سنقوم بتنفيذ Действия / Все задачи / Импорт. لنقم باستيراد الملف الذي تم تنزيله مسبقًا إلى الملف. ربما تذكر المتصفح حالة الثقة السابقة للشهادة. لذلك، قبل فتح الصفحة، تحتاج إلى إعادة تشغيل المتصفح. على سبيل المثال، في Google Chrome في شريط العناوين، تحتاج إلى تشغيل chrome://restart. في نظام التشغيل Windows، يمكنك أيضًا استخدام الأداة المساعدة لعرض الشهادات certmgr.msc:
من HTTP إلى HTTPS - 17
إذا فعلنا كل شيء بشكل صحيح، فسنرى اتصالًا ناجحًا بخادمنا عبر HTTPS:
من HTTP إلى HTTPS - 18
كما ترون، تعتبر الشهادة الآن صالحة، والمورد متاح، ولا توجد أخطاء.
من HTTP إلى HTTPS - 19

الحد الأدنى

لذلك اكتشفنا كيف يبدو مخطط تمكين بروتوكول HTTPS على خادم الويب وما هو مطلوب لهذا الغرض. آمل في هذه المرحلة أن يكون من الواضح أن الدعم يتم توفيره من خلال تفاعل بنية تشفير Java (JCA)، المسؤولة عن التشفير، وملحق Java Secure المقبس (JSSE)، الذي يوفر تنفيذ TLS على جانب Java. لقد رأينا كيف يتم استخدام الأداة المساعدة keytool المضمنة في JDK للعمل مع مفتاح KeyStore ومخزن الشهادات. بالإضافة إلى ذلك، أدركنا أن HTTPS يستخدم بروتوكولات SSL/TLS للأمان. ولتعزيز ذلك أنصحك بقراءة مقالات ممتازة حول هذا الموضوع: نأمل، بعد هذه المراجعة البسيطة، أن يصبح HTTPS أكثر شفافية. وإذا كنت بحاجة إلى تمكين HTTPS، فيمكنك بسهولة فهم المصطلحات من وثائق خوادم التطبيقات وأطر العمل الخاصة بك. # فياتشيسلاف
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION