JavaRush /Blog Java /Random-MS /Daripada HTTP kepada HTTPS

Daripada HTTP kepada HTTPS

Diterbitkan dalam kumpulan
Daripada HTTP ke HTTPS - 1
Kandungan:

pengenalan

Dalam dunia moden, anda tidak boleh hidup tanpa aplikasi web. Dan kita akan mulakan dengan percubaan kecil. Semasa kecil, saya masih ingat bagaimana semua gerai menjual surat khabar seperti "Hujah dan Fakta". Saya ingat mereka kerana mengikut persepsi peribadi saya sejak kecil, akhbar-akhbar ini sentiasa kelihatan pelik. Dan saya memutuskan sama ada kita perlu pergi ke laman web mereka:
Daripada HTTP ke HTTPS - 2
Jika kami pergi ke bantuan Google Chrome, kami akan membaca bahawa tapak ini tidak menggunakan sambungan selamat dan maklumat yang anda tukar dengan tapak mungkin boleh diakses oleh pihak ketiga. Mari kita semak beberapa berita lain, contohnya berita St. Petersburg dari Fontanka, sebuah media elektronik:
Daripada HTTP kepada HTTPS - 3
Seperti yang anda lihat, laman web Fontanka tidak mempunyai masalah keselamatan mengikut data ini. Ternyata sumber web mungkin selamat atau tidak. Kami juga melihat bahawa akses kepada sumber yang tidak dilindungi berlaku melalui protokol HTTP. Dan jika sumber itu dilindungi, maka pertukaran data dijalankan menggunakan protokol HTTPS, di mana S pada akhirnya bermaksud "Secure". Protokol HTTPS diterangkan dalam spesifikasi rfc2818: " HTTP Over TLS ". Mari cuba buat aplikasi web kita sendiri dan lihat sendiri cara ia berfungsi. Dan sepanjang perjalanan kita akan memahami syarat-syaratnya.
Daripada HTTP kepada HTTPS - 4

Aplikasi web dalam Java

Jadi, kita perlu mencipta aplikasi web yang sangat mudah di Java. Pertama, kita memerlukan aplikasi Java itu sendiri. Untuk melakukan ini, kami akan menggunakan sistem binaan automatik projek Gradle. Ini akan membolehkan kami tidak membuat struktur direktori yang diperlukan secara manual + Gradle akan mengurus semua perpustakaan yang diperlukan untuk projek untuk kami dan memastikan ia tersedia semasa melaksanakan kod. Anda boleh membaca lebih lanjut tentang Gradle dalam ulasan ringkas: " Pengenalan Ringkas kepada Gradle ". Mari gunakan Gradle Init Plugin dan jalankan arahan:
gradle init --type java-application
Selepas ini, mari buka skrip bina build.gradle, yang menerangkan pustaka yang terdiri daripada projek kami, yang akan diberikan oleh Gradle kepada kami. Mari tambahkan kebergantungan pada pelayan web yang akan kami uji:
dependencies {
    // Web server
    implementation 'io.undertow:undertow-core:2.0.20.Final'
     // Use JUnit test framework
     testImplementation 'junit:junit:4.12'
}
Untuk aplikasi web berfungsi, kami pasti memerlukan pelayan web di mana aplikasi kami akan dihoskan. Terdapat pelbagai jenis pelayan web, tetapi yang utama ialah: Tomcat, Jetty, Undertow. Kali ini kita akan memilih Undertow. Untuk memahami cara kami boleh bekerja dengan pelayan web kami ini, mari pergi ke tapak web rasmi Undertow dan pergi ke bahagian dokumentasi . Anda dan saya telah menyambungkan pergantungan pada Undertow Core, jadi kami berminat dengan bahagian tentang Core ini , iaitu teras, asas pelayan web. Cara paling mudah ialah menggunakan API Builder untuk 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();
}
Jika kami melaksanakan kod tersebut, kami boleh menavigasi ke sumber web berikut:
Daripada HTTP kepada HTTPS - 5
Ia berfungsi dengan mudah. Terima kasih kepada Undertow Builder API, kami menambah pendengar HTTP pada localhost dan port 8080. Pendengar ini menerima permintaan daripada pelayar web dan mengembalikan rentetan "Hello World" sebagai tindak balas. Aplikasi web yang hebat. Tetapi seperti yang kita lihat, kita menggunakan protokol HTTP, i.e. Jenis pertukaran data ini tidak selamat. Mari kita fikirkan cara pertukaran dijalankan menggunakan protokol HTTPS.
Daripada HTTP kepada HTTPS - 6

Keperluan untuk HTTPS

Untuk memahami cara mendayakan HTTPS, mari kembali kepada spesifikasi HTTPS: " RFC-2818: HTTP Over TLS ". Mengikut spesifikasi, data dalam protokol HTTPS dihantar melalui protokol kriptografi SSL atau TLS. Orang ramai sering terpedaya dengan konsep SSL dan TLS. Sebenarnya, SSL telah berkembang dan menukar versinya. Kemudian, TLS menjadi langkah seterusnya dalam pembangunan protokol SSL. Maksudnya, TLS hanyalah versi baharu SSL. Spesifikasi mengatakan demikian: "SSL, dan penggantinya TLS". Jadi, kami mengetahui bahawa terdapat protokol kriptografi SSL/TLS. SSL ialah singkatan untuk Lapisan Soket Selamat dan diterjemahkan sebagai "lapisan soket selamat". Soket yang diterjemahkan daripada bahasa Inggeris ialah penyambung. Peserta dalam penghantaran data melalui rangkaian menggunakan soket sebagai antara muka pengaturcaraan (iaitu, API) untuk berkomunikasi antara satu sama lain melalui rangkaian. Penyemak imbas bertindak sebagai pelanggan dan menggunakan soket klien, dan pelayan yang menerima permintaan dan mengeluarkan respons menggunakan soket pelayan. Dan di antara soket inilah pertukaran data berlaku. Itulah sebabnya protokol itu pada asalnya dipanggil SSL. Tetapi masa berlalu dan protokol berkembang. Dan pada satu ketika, protokol SSL menjadi protokol TLS. TLS ialah singkatan untuk Transport Layer Security. Protokol TLS pula adalah berdasarkan spesifikasi protokol SSL versi 3.0. Protokol TLS ialah topik artikel dan ulasan yang berasingan, jadi saya hanya akan menunjukkan bahan yang saya rasa menarik: Ringkasnya, asas HTTPS ialah jabat tangan TLS dan semakan "Identiti Pelayan" (iaitu, pengenalan pelayan) menggunakan sijil digitalnya. Ia penting. Mari kita ingat ini, kerana... Kami akan kembali kepada fakta ini kemudian. Jadi, sebelum ini kami menggunakan HttpListener untuk memberitahu pelayan cara untuk beroperasi melalui protokol HTTP. Jika dalam contoh di atas kami menambah HttpListener untuk berfungsi melalui HTTP, kemudian untuk bekerja melalui HTTPS kami perlu menambah HttpsListener:
Daripada HTTP ke HTTPS - 7
Tetapi untuk menambahnya, kami memerlukan SSLContext. Menariknya, SSLContext bukan kelas dari Undertow, tetapi javax.net.ssl.SSLContext. Kelas SSLContext adalah sebahagian daripada apa yang dipanggil " Java Secure Socket Extension " (JSSE) - sambungan Java untuk memastikan keselamatan sambungan Internet. Sambungan ini diterangkan dalam " Panduan Rujukan Sambungan Soket Selamat Java (JSSE) ". Seperti yang anda boleh lihat daripada bahagian pengenalan dokumentasi, JSSE menyediakan rangka kerja dan pelaksanaan Java bagi protokol SSL dan TLS. Bagaimanakah kita mendapatkan SSLContext? Buka JavaDoc SSLContext dan cari kaedah getInstance . Seperti yang anda lihat, untuk mendapatkan SSLContext kita perlu menentukan nama "Protokol Soket Selamat". Perihalan parameter menunjukkan bahawa nama-nama ini boleh didapati dalam " Java Cryptography Architecture Standard Algorithm Name Documentation ". Oleh itu, mari ikut arahan dan pergi ke dokumentasi. Dan kami melihat bahawa kami boleh memilih antara SSL dan TLS:
Daripada HTTP ke HTTPS - 8
Sekarang kita faham bahawa kita perlu mencipta SSLContext seperti berikut:
public SSLContext getSSLContext() {
	// 1. Получаем контекст, в рамках которого будем работать по TLS протоколу
	SSLContext context = null;
	try {
		context = SSLContext.getInstance("TLS");
	} catch (NoSuchAlgorithmException e) {
		throw new IllegalStateException(e);
	}
	return context;
}
Setelah mencipta konteks baharu, kami ingat bahawa SSLContext telah diterangkan dalam " Panduan Rujukan Sambungan Soket Selamat Java (JSSE) ". Kami membaca dan melihat bahawa "Konteks SSL yang baru dibuat harus dimulakan dengan memanggil kaedah init". Iaitu, mencipta konteks tidak mencukupi. Ia perlu dimulakan. Dan ini adalah logik, kerana tentang keselamatan, kami hanya memberitahu anda bahawa kami ingin menggunakan protokol TLS. Untuk memulakan SSLContext kami perlu menyediakan tiga perkara: KeyManager, TrustManager, SecureRandom.
Daripada HTTP ke HTTPS - 9

KeyManager

KeyManager ialah pengurus utama. Dia bertanggungjawab ke atas "kelayakan pengesahan" yang perlu diberikan kepada seseorang yang menghubungi kami. Tauliah boleh diterjemahkan sebagai identiti. Identiti diperlukan supaya pelanggan yakin bahawa pelayan adalah yang didakwanya dan boleh dipercayai. Apakah yang akan digunakan sebagai pengenalan? Seperti yang kita ingat, Identiti Pelayan disahkan oleh sijil digital pelayan. Proses ini boleh diwakili seperti berikut:
Daripada HTTP kepada HTTPS - 10
Selain itu, " Panduan Rujukan JSSE: Cara SSL Berfungsi " mengatakan bahawa SSL menggunakan "kriptografi asimetri", yang bermaksud bahawa kita memerlukan pasangan kunci: kunci awam dan kunci peribadi. Memandangkan kita bercakap tentang kriptografi, "Java Cryptography Architecture" (JCA) mula dimainkan. Oracle menyediakan dokumen yang sangat baik tentang seni bina ini: " Panduan Rujukan Seni Bina Kriptografi Java (JCA) ". Selain itu, anda boleh membaca gambaran ringkas JCA di JavaRush: " Seni Bina Kriptografi Java: Kenalan pertama ." Jadi, untuk memulakan KeyManager, kami memerlukan KeyStore, yang akan menyimpan sijil pelayan kami. Cara paling biasa untuk mencipta kedai kunci dan sijil ialah utiliti alat kunci, yang disertakan dengan JDK. Contoh boleh dilihat dalam dokumentasi JSSE: " Mencipta Kedai Kunci untuk Digunakan dengan JSSE ". Jadi, kita perlu menggunakan utiliti KeyTool untuk mencipta stor kunci dan menulis sijil di sana. Menariknya, penjanaan kunci sebelum ini ditentukan menggunakan -genkey, tetapi kini disyorkan untuk menggunakan -genkeypair. Kita perlu menentukan perkara berikut:
  • alias : Alias ​​​​atau nama ringkas di mana entri akan disimpan dalam Keystore
  • keyalg : Algoritma penyulitan kunci. Mari kita pilih algoritma RSA, yang pada asasnya merupakan penyelesaian standard untuk tujuan kita.
  • saiz kekunci : Saiz kunci (dalam bit). Saiz minimum yang disyorkan ialah 2048, kerana... saiz yang lebih kecil telah pun retak. Anda boleh membaca lebih lanjut di sini: " sijil ssl dalam 2048 bit ".
  • dname : Nama Terbilang, nama terbilang.
Adalah penting untuk memahami bahawa sumber yang diminta (contohnya, https://localhost) akan dibandingkan dengannya. Ini dipanggil "padanan cn subjek".
  • kesahan : Tempoh dalam hari di mana sijil yang dihasilkan adalah sah, i.e. sah.
  • ext : Sambungan Sijil dinyatakan dalam " Sambungan Dinamakan ".
Untuk Sijil yang ditandatangani sendiri (iaitu untuk sijil yang dibuat secara bebas), anda mesti menentukan sambungan berikut:
  • -ext san:critical=dns:localhost,ip:127.0.0.1 > untuk melaksanakan pemadanan subjek mengikut SubjectAlternativeName
  • -ext bc=ca:false > untuk menunjukkan bahawa sijil ini tidak digunakan untuk menandatangani sijil lain
Mari jalankan arahan (contoh untuk OS 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
Kerana fail akan dibuat, pastikan anda mempunyai semua hak untuk mencipta fail. Anda juga mungkin akan melihat nasihat seperti ini:
Daripada HTTP ke HTTPS - 11
Di sini kita diberitahu bahawa JKS adalah format proprietari. Proprietari bermaksud ia adalah hak milik persendirian pengarang dan bertujuan untuk digunakan hanya di Jawa. Apabila bekerja dengan utiliti pihak ketiga, konflik mungkin timbul, itulah sebabnya kami diberi amaran. Di samping itu, kami mungkin menerima ralat: The destination pkcs12 keystore has different storepass and keypass. Ralat ini berlaku kerana kata laluan untuk entri dalam Keystore dan untuk keystore itu sendiri adalah berbeza. Seperti yang dinyatakan dalam dokumentasi alat kunci , "Sebagai contoh, kebanyakan alatan pihak ketiga memerlukan laluan simpan dan laluan kekunci dalam stor kunci PKCS #12 supaya sama." Kita boleh menentukan kunci sendiri (contohnya, -destkeypass entrypassw). Tetapi lebih baik tidak melanggar keperluan dan tetapkan kata laluan yang sama. Jadi import mungkin kelihatan seperti ini:
keytool -importkeystore -srckeystore C:/keystore.jks -destkeystore C:/keystore.jks -deststoretype pkcs12
Contoh kejayaan:
Daripada HTTP kepada HTTPS - 12
Untuk mengeksport sijil ke fail, anda boleh menjalankan:
keytool -export -alias ssl -storepass passw0rd -file C:/server.cer -keystore C:/keystore.jks
Selain itu, kami boleh mendapatkan kandungan Keystore seperti ini:
keytool -list -v -keystore C:/keystore.jks -storepass passw0rd
Bagus, kini kami mempunyai stor kunci yang mengandungi sijil. Kini anda boleh mendapatkannya daripada kod:
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);
	}
}
Jika terdapat KeyStore, maka kita boleh memulakan 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);
	}
}
Matlamat pertama kami telah tercapai. Ia masih untuk mengetahui apa itu TrustManager. TrustManager diterangkan dalam dokumentasi JSSE dalam bahagian " Antara Muka TrustManager ". Ia sangat serupa dengan KeyManager, tetapi tujuannya adalah untuk menyemak sama ada orang yang meminta sambungan itu boleh dipercayai. Secara terang-terangan, ini adalah KeyManager secara terbalik =) Kami tidak memerlukan TrustManager, jadi kami akan lulus null. TrustManager lalai kemudiannya akan dibuat yang tidak mengesahkan pengguna akhir membuat permintaan ke pelayan kami. Dokumentasi mengatakan demikian: "pelaksanaan lalai akan digunakan". Sama dengan SecureRandom. Jika kami menentukan nol, pelaksanaan lalai akan digunakan. Mari kita ingat bahawa SecureRandom ialah kelas JCA dan diterangkan dalam dokumentasi JCA dalam bahagian " The SecureRandom Class ". Secara keseluruhan, penyediaan dengan mengambil kira semua kaedah yang diterangkan di atas mungkin kelihatan seperti ini:
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);
	}
Yang tinggal hanyalah untuk memulakan pelayan:
// 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();
}
Kali ini pelayan kami akan tersedia di alamat https://localhost:443 Walau bagaimanapun, kami masih akan menerima ralat bahawa sumber ini tidak boleh dipercayai:
Daripada HTTP kepada HTTPS - 13
Mari kita fikirkan apa yang salah dengan sijil dan apa yang perlu dilakukan mengenainya.
Daripada HTTP kepada HTTPS - 14

Pengurusan sijil

Jadi, pelayan kami sudah sedia untuk berfungsi melalui HTTPS, tetapi pelanggan tidak mempercayainya. kenapa? Mari lihat:
Daripada HTTP kepada HTTPS - 15
Sebab sijil ini adalah Sijil yang ditandatangani sendiri. Sijil SSL yang ditandatangani sendiri merujuk kepada sijil kunci awam yang dikeluarkan dan ditandatangani oleh orang yang sama yang dikenal pastinya. Iaitu, ia tidak dikeluarkan oleh mana-mana pihak berkuasa pensijilan yang dihormati (CA, juga dikenali sebagai Pihak Berkuasa Sijil). Pihak Berkuasa Sijil bertindak sebagai pemegang amanah dan serupa dengan notari dalam kehidupan seharian. Dia memberi jaminan bahawa sijil yang dikeluarkannya boleh dipercayai. Perkhidmatan mengeluarkan sijil oleh CA tersebut dibayar, jadi tiada siapa yang memerlukan kehilangan kepercayaan dan risiko reputasi. Secara lalai, terdapat beberapa pihak berkuasa sijil yang dipercayai. Senarai ini boleh diedit. Dan setiap sistem pengendalian mempunyai pengurusan sendiri senarai pihak berkuasa pensijilan. Sebagai contoh, menguruskan senarai ini dalam Windows boleh dibaca di sini: " Urus Sijil Root Dipercayai dalam Windows ". Mari tambah sijil kepada yang dipercayai seperti yang ditunjukkan dalam mesej ralat. Untuk melakukan ini, mula-mula, muat turun sijil:
Daripada HTTP ke HTTPS - 16
Dalam OS Windows, tekan Win+R dan laksanakan mmcuntuk memanggil konsol kawalan. Seterusnya, tekan Ctrl+M untuk menambah bahagian "Sijil" pada konsol semasa. Seterusnya, dalam subseksyen "Pihak Berkuasa Pensijilan Root Dipercayai" kami akan melaksanakan Действия / Все задачи / Импорт. Mari import fail yang telah dimuat turun tadi ke dalam fail. Penyemak imbas mungkin telah mengingati keadaan amanah masa lalu bagi sijil. Oleh itu, sebelum membuka halaman anda perlu memulakan semula penyemak imbas. Sebagai contoh, dalam Google Chrome dalam bar alamat yang anda perlukan untuk menjalankan chrome://restart. Dalam OS Windows, anda juga boleh menggunakan utiliti untuk melihat sijil certmgr.msc:
Daripada HTTP kepada HTTPS - 17
Jika kami melakukan semuanya dengan betul, kami akan melihat panggilan yang berjaya ke pelayan kami melalui HTTPS:
Daripada HTTP kepada HTTPS - 18
Seperti yang anda lihat, sijil kini dianggap sah, sumber tersedia dan tiada ralat.
Daripada HTTP kepada HTTPS - 19

Pokoknya

Oleh itu, kami telah mengetahui rupa skema untuk membolehkan protokol HTTPS pada pelayan web dan apa yang diperlukan untuk ini. Saya harap pada ketika ini adalah jelas bahawa sokongan disediakan oleh interaksi Java Cryptography Architecture (JCA), yang bertanggungjawab untuk kriptografi, dan Java Secure Socket Extension (JSSE), yang menyediakan pelaksanaan TLS di sebelah Java. Kami melihat bagaimana utiliti alat kunci yang disertakan dalam JDK digunakan untuk berfungsi dengan kunci KeyStore dan kedai sijil. Selain itu, kami menyedari bahawa HTTPS menggunakan protokol SSL/TLS untuk keselamatan. Untuk mengukuhkan ini, saya menasihati anda untuk membaca artikel yang sangat baik mengenai topik ini: Mudah-mudahan, selepas semakan kecil ini, HTTPS akan menjadi lebih telus. Dan jika anda perlu mendayakan HTTPS, anda boleh memahami terma dengan mudah daripada dokumentasi pelayan aplikasi dan rangka kerja anda. #Viacheslav
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION