JavaRush /Java Blog /Random-ID /Dari HTTP ke HTTPS
Viacheslav
Level 3

Dari HTTP ke HTTPS

Dipublikasikan di grup Random-ID
Dari HTTP ke HTTPS - 1
Isi:

Perkenalan

Di dunia modern, Anda tidak bisa hidup tanpa aplikasi web. Dan kita akan mulai dengan eksperimen kecil. Sebagai seorang anak, saya ingat bagaimana semua kios menjual koran seperti “Argumen dan Fakta”. Saya mengingatnya karena menurut persepsi pribadi saya sejak kecil, surat kabar ini selalu terlihat aneh. Dan saya memutuskan apakah kami harus mengunjungi situs web mereka:
Dari HTTP ke HTTPS - 2
Jika kami membuka bantuan Google Chrome, kami akan membaca bahwa situs ini tidak menggunakan koneksi aman dan informasi yang Anda tukarkan dengan situs tersebut mungkin dapat diakses oleh pihak ketiga. Yuk simak berita lainnya, misalnya berita St. Petersburg dari Fontanka, sebuah media elektronik:
Dari HTTP ke HTTPS - 3
Seperti yang Anda lihat, situs web Fontanka tidak memiliki masalah keamanan berdasarkan data ini. Ternyata sumber daya web mungkin aman atau tidak. Kami juga melihat bahwa akses ke sumber daya yang tidak dilindungi terjadi melalui protokol HTTP. Dan jika resource dilindungi, maka pertukaran data dilakukan menggunakan protokol HTTPS, dimana S di akhir berarti “Aman”. Protokol HTTPS dijelaskan dalam spesifikasi rfc2818: " HTTP Over TLS ". Mari kita coba membuat aplikasi web kita sendiri dan lihat sendiri cara kerjanya. Dan dalam perjalanannya kita akan memahami istilah-istilah tersebut.
Dari HTTP ke HTTPS - 4

Aplikasi web di Java

Jadi, kita perlu membuat aplikasi web yang sangat sederhana di Java. Pertama, kita membutuhkan aplikasi Java itu sendiri. Untuk melakukan ini, kita akan menggunakan sistem pembangunan otomatis proyek Gradle. Ini akan memungkinkan kita untuk tidak membuat struktur direktori yang diperlukan secara manual + Gradle akan mengelola semua perpustakaan yang kita perlukan untuk proyek tersebut dan memastikan bahwa perpustakaan tersebut tersedia saat menjalankan kode. Anda dapat membaca lebih lanjut tentang Gradle dalam ulasan singkat: " Pengantar Singkat tentang Gradle ". Mari gunakan Plugin Gradle Init dan jalankan perintah:
gradle init --type java-application
Setelah ini, mari kita buka skrip build build.gradle, yang menjelaskan pustaka apa saja yang terdapat dalam proyek kita, yang akan disediakan Gradle kepada kita. Mari tambahkan ketergantungan pada server web tempat kita akan bereksperimen:
dependencies {
    // Web server
    implementation 'io.undertow:undertow-core:2.0.20.Final'
     // Use JUnit test framework
     testImplementation 'junit:junit:4.12'
}
Agar aplikasi web dapat berfungsi, kita pasti memerlukan server web tempat aplikasi kita akan dihosting. Ada berbagai macam server web, tetapi yang utama adalah: Tomcat, Jetty, Undertow. Kali ini kita akan memilih Undertow. Untuk memahami bagaimana kami dapat bekerja dengan server web kami ini, mari kunjungi situs resmi Undertow dan buka bagian dokumentasi . Anda dan saya telah menghubungkan ketergantungan pada Undertow Core, jadi kami tertarik pada bagian tentang Inti ini , yaitu inti, dasar dari server web. Cara termudah adalah dengan menggunakan Builder API 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 kita mengeksekusi kodenya, kita dapat menavigasi ke sumber daya web berikut:
Dari HTTP ke HTTPS - 5
Ini bekerja dengan sederhana. Berkat Undertow Builder API, kami menambahkan pendengar HTTP ke localhost dan port 8080. Pendengar ini menerima permintaan dari browser web dan mengembalikan string "Hello World" sebagai tanggapan. Aplikasi web yang bagus. Tapi seperti yang bisa kita lihat, kami menggunakan protokol HTTP, mis. Jenis pertukaran data ini tidak aman. Mari kita cari tahu bagaimana pertukaran dilakukan menggunakan protokol HTTPS.
Dari HTTP ke HTTPS - 6

Persyaratan untuk HTTPS

Untuk memahami cara mengaktifkan HTTPS, mari kembali ke spesifikasi HTTPS: " RFC-2818: HTTP Over TLS ". Menurut spesifikasinya, data dalam protokol HTTPS ditransmisikan melalui protokol kriptografi SSL atau TLS. Orang sering disesatkan dengan konsep SSL dan TLS. Faktanya, SSL telah berevolusi dan mengubah versinya. Nantinya, TLS menjadi langkah selanjutnya dalam pengembangan protokol SSL. Artinya, TLS hanyalah versi baru dari SSL. Spesifikasinya berbunyi demikian: “SSL, dan penerusnya TLS”. Jadi, kami mengetahui bahwa ada protokol kriptografi SSL/TLS. SSL adalah singkatan dari Secure Sockets Layer dan diterjemahkan sebagai “lapisan soket aman”. Soket yang diterjemahkan dari bahasa Inggris adalah konektor. Peserta dalam transmisi data melalui jaringan menggunakan soket sebagai antarmuka pemrograman (yaitu API) untuk berkomunikasi satu sama lain melalui jaringan. Browser bertindak sebagai klien dan menggunakan soket klien, dan server yang menerima permintaan dan mengeluarkan respons menggunakan soket server. Dan di antara soket inilah pertukaran data terjadi. Itu sebabnya protokol ini awalnya disebut SSL. Namun waktu berlalu dan protokolnya berkembang. Dan pada suatu saat, protokol SSL menjadi protokol TLS. TLS adalah kependekan dari Keamanan Lapisan Transportasi. Protokol TLS, pada gilirannya, didasarkan pada spesifikasi protokol SSL versi 3.0. Protokol TLS adalah topik artikel dan ulasan terpisah, jadi saya hanya akan menunjukkan materi yang menurut saya menarik: Singkatnya, dasar HTTPS adalah jabat tangan TLS dan pemeriksaan “Identitas Server” (yaitu identifikasi server) menggunakan sertifikat digitalnya. Itu penting. Mari kita ingat ini, karena... Kami akan kembali ke fakta ini nanti. Jadi, sebelumnya kita menggunakan HttpListener untuk memberi tahu server cara beroperasi melalui protokol HTTP. Jika pada contoh di atas kita menambahkan HttpListener untuk bekerja melalui HTTP, maka untuk bekerja melalui HTTPS kita perlu menambahkan HttpsListener:
Dari HTTP ke HTTPS - 7
Namun untuk menambahkannya kita membutuhkan SSLContext. Menariknya, SSLContext bukanlah kelas dari Undertow, melainkan javax.net.ssl.SSLContext. Kelas SSLContext adalah bagian dari apa yang disebut " Java Secure Socket Extension " (JSSE) - ekstensi Java untuk memastikan keamanan koneksi Internet. Ekstensi ini dijelaskan dalam " Panduan Referensi Java Secure Socket Extension (JSSE) ". Seperti yang dapat Anda lihat dari bagian pengantar dokumentasi, JSSE menyediakan kerangka kerja dan implementasi Java dari protokol SSL dan TLS. Bagaimana cara kita mendapatkan SSLContext? Buka JavaDoc SSLContext dan temukan metode getInstance . Seperti yang Anda lihat, untuk mendapatkan SSLContext kita perlu menentukan nama "Secure Socket Protocol". Deskripsi parameter menunjukkan bahwa nama-nama ini dapat ditemukan di " Dokumentasi Nama Algoritma Standar Arsitektur Kriptografi Java ". Oleh karena itu, mari ikuti petunjuknya dan buka dokumentasinya. Dan kita melihat bahwa kita dapat memilih antara SSL dan TLS:
Dari HTTP ke HTTPS - 8
Sekarang kita memahami bahwa kita perlu membuat SSLContext sebagai berikut:
public SSLContext getSSLContext() {
	// 1. Получаем контекст, в рамках которого будем работать по TLS протоколу
	SSLContext context = null;
	try {
		context = SSLContext.getInstance("TLS");
	} catch (NoSuchAlgorithmException e) {
		throw new IllegalStateException(e);
	}
	return context;
}
Setelah membuat konteks baru, kami ingat bahwa SSLContext dijelaskan dalam " Panduan Referensi Java Secure Socket Extension (JSSE) ". Kita membaca dan melihat bahwa “SSLContext yang baru dibuat harus diinisialisasi dengan memanggil metode init”. Artinya, menciptakan konteks saja tidak cukup. Itu perlu diinisialisasi. Dan ini logis, karena tentang keamanan, kami hanya memberi tahu Anda bahwa kami ingin menggunakan protokol TLS. Untuk menginisialisasi SSLContext kita perlu menyediakan tiga hal: KeyManager, TrustManager, SecureRandom.
Dari HTTP ke HTTPS - 9

Manajer kunci

KeyManager adalah manajer kunci. Dia bertanggung jawab atas “kredensial autentikasi” apa yang harus diberikan kepada seseorang yang menghubungi kami. Kredensial dapat diterjemahkan sebagai identitas. Identitas tersebut diperlukan agar client yakin bahwa server tersebut sesuai dengan klaimnya dan dapat dipercaya. Apa yang akan digunakan sebagai identifikasi? Seperti yang kita ingat, Identitas Server diverifikasi oleh sertifikat digital server. Proses ini dapat direpresentasikan sebagai berikut:
Dari HTTP ke HTTPS - 10
Selain itu, " Panduan Referensi JSSE: Cara Kerja SSL " menyatakan bahwa SSL menggunakan "kriptografi asimetris", yang berarti kita memerlukan pasangan kunci: kunci publik dan kunci pribadi. Karena kita berbicara tentang kriptografi, “Arsitektur Kriptografi Java” (JCA) ikut berperan. Oracle menyediakan dokumen luar biasa tentang arsitektur ini: " Panduan Referensi Arsitektur Kriptografi Java (JCA) ". Selain itu, Anda dapat membaca gambaran singkat JCA di JavaRush: " Arsitektur Kriptografi Java: Kenalan pertama ." Jadi, untuk menginisialisasi KeyManager, kita memerlukan KeyStore, yang akan menyimpan sertifikat server kita. Cara paling umum untuk membuat penyimpanan kunci dan sertifikat adalah utilitas keytool, yang disertakan dengan JDK. Contohnya dapat dilihat pada dokumentasi JSSE: " Membuat Keystore untuk Digunakan dengan JSSE ". Jadi, kita perlu menggunakan utilitas KeyTool untuk membuat penyimpanan kunci dan menulis sertifikat di sana. Menariknya, pembuatan kunci sebelumnya ditentukan menggunakan -genkey, namun sekarang direkomendasikan untuk menggunakan -genkeypair. Kita perlu mendefinisikan hal-hal berikut:
  • alias : Alias ​​​​atau sekadar nama di mana entri tersebut akan disimpan di Keystore
  • keyalg : Algoritma enkripsi kunci. Mari kita pilih algoritma RSA, yang pada dasarnya merupakan solusi standar untuk tujuan kita.
  • ukuran kunci : Ukuran kunci (dalam bit). Ukuran minimum yang disarankan adalah 2048, karena... ukuran yang lebih kecil telah retak. Anda dapat membaca lebih lanjut di sini: " sertifikat ssl dalam 2048 bit ".
  • dname : Nama Yang Terhormat, nama yang terhormat.
Penting untuk dipahami bahwa sumber daya yang diminta (misalnya, https://localhost) akan dibandingkan dengan sumber daya tersebut. Ini disebut "pencocokan subjek".
  • validitas : Durasi dalam hari di mana sertifikat yang dihasilkan valid, mis. sah.
  • ext : Ekstensi Sertifikat ditentukan dalam " Ekstensi Bernama ".
Untuk Sertifikat yang Ditandatangani Sendiri (yaitu, untuk sertifikat yang dibuat secara mandiri), Anda harus menentukan ekstensi berikut:
  • -ext san:critical=dns:localhost,ip:127.0.0.1 > untuk melakukan pencocokan subjek dengan SubjectAlternativeName
  • -ext bc=ca:false > untuk menunjukkan bahwa sertifikat ini tidak digunakan untuk menandatangani sertifikat lainnya
Mari kita jalankan perintah (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
Karena file akan dibuat, pastikan Anda memiliki semua hak untuk membuat file tersebut. Anda mungkin juga akan melihat saran seperti ini:
Dari HTTP ke HTTPS - 11
Di sini kita diberitahu bahwa JKS adalah format berpemilik. Kepemilikan artinya adalah milik pribadi penulis dan dimaksudkan untuk digunakan hanya di Jawa. Saat bekerja dengan utilitas pihak ketiga, konflik mungkin muncul, itulah sebabnya kami diperingatkan. Selain itu, kami mungkin menerima kesalahan: The destination pkcs12 keystore has different storepass and keypass. Kesalahan ini terjadi karena kata sandi untuk entri di Keystore dan untuk keystore itu sendiri berbeda. Seperti yang tertulis dalam dokumentasi keytool , "Misalnya, sebagian besar alat pihak ketiga memerlukan storepass dan keypass di keystore PKCS #12 agar sama." Kita dapat menentukan sendiri kuncinya (misalnya, -destkeypass entrypassw). Namun lebih baik tidak melanggar persyaratan dan menetapkan kata sandi yang sama. Jadi impornya mungkin terlihat seperti ini:
keytool -importkeystore -srckeystore C:/keystore.jks -destkeystore C:/keystore.jks -deststoretype pkcs12
Contoh sukses:
Dari HTTP ke HTTPS - 12
Untuk mengekspor sertifikat ke file, Anda dapat menjalankan:
keytool -export -alias ssl -storepass passw0rd -file C:/server.cer -keystore C:/keystore.jks
Selain itu, kita bisa mendapatkan konten Keystore seperti ini:
keytool -list -v -keystore C:/keystore.jks -storepass passw0rd
Bagus, sekarang kita punya keystore yang berisi sertifikat. Sekarang Anda bisa mendapatkannya dari kode:
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 ada KeyStore, maka kita dapat menginisialisasi 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);
	}
}
Tujuan pertama kami telah tercapai. Masih mencari tahu apa itu TrustManager. TrustManager dijelaskan dalam dokumentasi JSSE di bagian " Antarmuka TrustManager ". Ini sangat mirip dengan KeyManager, namun tujuannya adalah untuk memeriksa apakah orang yang meminta koneksi dapat dipercaya. Terus terang, ini adalah KeyManager sebaliknya =) Kita tidak memerlukan TrustManager, jadi kita akan memberikan null. TrustManager default kemudian akan dibuat yang tidak memverifikasi pengguna akhir yang membuat permintaan ke server kami. Dokumentasinya menyatakan demikian: "implementasi default akan digunakan". Sama dengan SecureRandom. Jika kita menentukan null, implementasi default akan digunakan. Ingatlah bahwa SecureRandom adalah kelas JCA dan dijelaskan dalam dokumentasi JCA di bagian " Kelas SecureRandom ". Secara total, persiapan dengan mempertimbangkan semua metode yang dijelaskan di atas mungkin terlihat 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 tersisa hanyalah memulai server:
// 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 server kami akan tersedia di alamat berikut, https://localhost:443 namun kami masih menerima pesan kesalahan bahwa sumber daya ini tidak dapat dipercaya:
Dari HTTP ke HTTPS - 13
Mari kita cari tahu apa yang salah dengan sertifikat tersebut dan apa yang harus dilakukan.
Dari HTTP ke HTTPS - 14

Manajemen sertifikat

Jadi, server kami sudah siap bekerja melalui HTTPS, tetapi klien tidak mempercayainya. Mengapa? Mari kita lihat:
Dari HTTP ke HTTPS - 15
Pasalnya, sertifikat ini merupakan Sertifikat yang Ditandatangani Sendiri. Sertifikat SSL yang ditandatangani sendiri mengacu pada sertifikat kunci publik yang diterbitkan dan ditandatangani oleh orang yang sama yang diidentifikasi. Artinya, sertifikat tersebut tidak dikeluarkan oleh otoritas sertifikasi mana pun yang dihormati (CA, juga dikenal sebagai Otoritas Sertifikat). Otoritas Sertifikat bertindak sebagai wali dan mirip dengan notaris dalam kehidupan sehari-hari. Ia menjamin sertifikat yang dikeluarkannya dapat dipercaya. Layanan penerbitan sertifikat oleh CA tersebut dibayar, jadi tidak ada yang perlu kehilangan kepercayaan dan risiko reputasi. Secara default, ada beberapa otoritas sertifikat yang dipercaya. Daftar ini dapat diedit. Dan setiap sistem operasi memiliki pengelolaan daftar otoritas sertifikasinya sendiri. Misalnya pengelolaan daftar ini di Windows dapat dibaca di sini: " Kelola Sertifikat Root Tepercaya di Windows ". Mari tambahkan sertifikat ke sertifikat tepercaya seperti yang ditunjukkan dalam pesan kesalahan. Untuk melakukannya, unduh sertifikatnya terlebih dahulu:
Dari HTTP ke HTTPS - 16
Di OS Windows, tekan Win+R dan jalankan mmcuntuk memanggil konsol kontrol. Selanjutnya, tekan Ctrl+M untuk menambahkan bagian “Sertifikat” ke konsol saat ini. Selanjutnya, di subbagian "Otoritas Sertifikasi Root Tepercaya" kita akan menjalankan Действия / Все задачи / Импорт. Mari kita import file yang sudah didownload tadi ke dalam file tersebut. Browser mungkin mengingat status kepercayaan sertifikat di masa lalu. Oleh karena itu, sebelum membuka halaman tersebut, Anda perlu me-restart browser. Misalnya, di Google Chrome di bilah alamat Anda perlu menjalankan chrome://restart. Di OS Windows, Anda juga dapat menggunakan utilitas untuk melihat sertifikat certmgr.msc:
Dari HTTP ke HTTPS - 17
Jika kami melakukan semuanya dengan benar, kami akan melihat panggilan berhasil ke server kami melalui HTTPS:
Dari HTTP ke HTTPS - 18
Seperti yang Anda lihat, sertifikat sekarang dianggap valid, sumber daya tersedia, dan tidak ada kesalahan.
Dari HTTP ke HTTPS - 19

Intinya

Jadi kita sudah mengetahui seperti apa skema untuk mengaktifkan protokol HTTPS di server web dan apa yang diperlukan untuk ini. Saya berharap pada titik ini jelas bahwa dukungan diberikan melalui interaksi Java Cryptography Architecture (JCA), yang bertanggung jawab atas kriptografi, dan Java Secure Socket Extension (JSSE), yang menyediakan implementasi TLS di sisi Java. Kami melihat bagaimana utilitas keytool yang disertakan dalam JDK digunakan untuk bekerja dengan kunci KeyStore dan penyimpanan sertifikat. Selain itu, kami menyadari bahwa HTTPS menggunakan protokol SSL/TLS untuk keamanan. Untuk memperkuat hal ini, saya menyarankan Anda untuk membaca artikel bagus tentang topik ini: Mudah-mudahan setelah ulasan kecil ini, HTTPS menjadi sedikit lebih transparan. Dan jika Anda perlu mengaktifkan HTTPS, Anda dapat dengan mudah memahami persyaratan dari dokumentasi server dan kerangka aplikasi Anda. #Viacheslav
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION