JavaRush /Blog Java /Random-VI /Từ HTTP đến HTTPS
Viacheslav
Mức độ

Từ HTTP đến HTTPS

Xuất bản trong nhóm
Từ HTTP đến HTTPS - 1
Nội dung:

Giới thiệu

Trong thế giới hiện đại, bạn không thể sống thiếu các ứng dụng web. Và chúng ta sẽ bắt đầu với một thí nghiệm nhỏ. Khi còn nhỏ, tôi nhớ tất cả các quầy hàng đều bán một tờ báo như “Lý lẽ và sự thật”. Tôi nhớ đến chúng bởi vì, theo nhận thức cá nhân của tôi từ khi còn nhỏ, những tờ báo này luôn có vẻ ngoài kỳ lạ. Và tôi quyết định liệu chúng tôi có nên truy cập trang web của họ hay không:
Từ HTTP đến HTTPS - 2
Nếu chúng tôi truy cập phần trợ giúp của Google Chrome, chúng tôi sẽ biết rằng trang web này không sử dụng kết nối an toàn và thông tin bạn trao đổi với trang web có thể bị truy cập bởi các bên thứ ba. Hãy xem một số tin tức khác, ví dụ như tin tức St. Petersburg từ Fontanka, một phương tiện truyền thông điện tử:
Từ HTTP đến HTTPS - 3
Như bạn có thể thấy, trang web Fontanka không gặp vấn đề gì về bảo mật theo những dữ liệu này. Hóa ra tài nguyên web có thể an toàn hoặc không. Chúng tôi cũng thấy rằng việc truy cập vào các tài nguyên không được bảo vệ xảy ra thông qua giao thức HTTP. Và nếu tài nguyên được bảo vệ thì việc trao đổi dữ liệu sẽ được thực hiện bằng giao thức HTTPS, trong đó chữ S ở cuối có nghĩa là “Bảo mật”. Giao thức HTTPS được mô tả trong đặc tả rfc2818: " HTTP Over TLS ". Chúng ta hãy thử tạo ứng dụng web của riêng mình và tự mình xem nó hoạt động như thế nào. Và trên đường đi, chúng ta sẽ hiểu các điều khoản.
Từ HTTP đến HTTPS - 4

Ứng dụng web bằng Java

Vì vậy, chúng ta cần tạo một ứng dụng web rất đơn giản bằng Java. Đầu tiên, chúng ta cần chính ứng dụng Java. Để làm điều này, chúng ta sẽ sử dụng hệ thống xây dựng tự động của dự án Gradle. Điều này sẽ cho phép chúng ta không phải tạo cấu trúc thư mục cần thiết theo cách thủ công + Gradle sẽ quản lý tất cả các thư viện cần thiết cho dự án cho chúng ta và đảm bảo rằng chúng có sẵn khi thực thi mã. Bạn có thể đọc thêm về Gradle trong bài đánh giá ngắn: " Giới thiệu tóm tắt về Gradle ". Hãy sử dụng Gradle Init Plugin và chạy lệnh:
gradle init --type java-application
Sau đó, hãy mở tập lệnh xây dựng build.gradle, mô tả dự án của chúng ta bao gồm những thư viện nào mà Gradle sẽ cung cấp cho chúng ta. Hãy thêm vào đó một phần phụ thuộc trên máy chủ web mà chúng ta sẽ thử nghiệm:
dependencies {
    // Web server
    implementation 'io.undertow:undertow-core:2.0.20.Final'
     // Use JUnit test framework
     testImplementation 'junit:junit:4.12'
}
Để một ứng dụng web hoạt động, chúng tôi chắc chắn cần một máy chủ web nơi ứng dụng của chúng tôi sẽ được lưu trữ. Có rất nhiều loại máy chủ web, nhưng những máy chủ chính là: Tomcat, Jetty, Undertow. Lần này chúng ta sẽ chọn Undertow. Để hiểu cách chúng tôi có thể làm việc với máy chủ web này của chúng tôi, hãy truy cập trang web chính thức của Undertow và đi tới phần tài liệu . Bạn và tôi đã kết nối một phần phụ thuộc trên Undertow Core nên chúng ta quan tâm đến phần nói về chính Core này , tức là cốt lõi, nền tảng của máy chủ web. Cách dễ nhất là sử dụng API Builder cho 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();
}
Nếu chúng tôi thực thi mã, chúng tôi có thể điều hướng đến tài nguyên web sau:
Từ HTTP đến HTTPS - 5
Nó hoạt động đơn giản. Nhờ API Undertow Builder, chúng tôi thêm trình nghe HTTP vào localhost và cổng 8080. Trình nghe này nhận được yêu cầu từ trình duyệt web và trả về chuỗi "Xin chào thế giới". Ứng dụng web tuyệt vời. Nhưng như chúng ta thấy, chúng ta sử dụng giao thức HTTP, tức là. Kiểu trao đổi dữ liệu này không an toàn. Hãy tìm hiểu cách trao đổi được thực hiện bằng giao thức HTTPS.
Từ HTTP đến HTTPS - 6

Yêu cầu đối với HTTPS

Để hiểu cách kích hoạt HTTPS, chúng ta hãy quay lại thông số kỹ thuật của HTTPS: " RFC-2818: HTTP Over TLS ". Theo thông số kỹ thuật, dữ liệu trong giao thức HTTPS được truyền qua giao thức mã hóa SSL hoặc TLS. Mọi người thường bị nhầm lẫn bởi khái niệm SSL và TLS. Trên thực tế, SSL đã phát triển và thay đổi các phiên bản của nó. Sau đó, TLS trở thành bước tiếp theo trong quá trình phát triển giao thức SSL. Tức là TLS đơn giản là một phiên bản mới của SSL. Thông số kỹ thuật nói như vậy: “SSL và TLS kế nhiệm của nó”. Vì vậy, chúng tôi đã biết rằng có các giao thức mã hóa SSL/TLS. SSL là tên viết tắt của Secure Sockets Layer và được dịch là “lớp cổng bảo mật”. Ổ cắm dịch từ tiếng Anh là một đầu nối. Những người tham gia truyền dữ liệu qua mạng sử dụng ổ cắm làm giao diện lập trình (nghĩa là API) để liên lạc với nhau qua mạng. Trình duyệt hoạt động như một máy khách và sử dụng ổ cắm máy khách, còn máy chủ nhận được yêu cầu và đưa ra phản hồi sẽ sử dụng ổ cắm máy chủ. Và chính giữa các ổ cắm này mà việc trao đổi dữ liệu diễn ra. Đó là lý do tại sao giao thức ban đầu được gọi là SSL. Nhưng thời gian trôi qua và giao thức đã phát triển. Và tại một thời điểm, giao thức SSL đã trở thành giao thức TLS. TLS là viết tắt của Bảo mật lớp vận chuyển. Ngược lại, giao thức TLS dựa trên đặc tả giao thức SSL phiên bản 3.0. Giao thức TLS là chủ đề của các bài viết và đánh giá riêng biệt, vì vậy tôi sẽ chỉ chỉ ra những tài liệu mà tôi thấy thú vị: Nói tóm lại, cơ sở của HTTPS là bắt tay TLS và kiểm tra “Nhận dạng máy chủ” (tức là nhận dạng máy chủ) bằng chứng chỉ kỹ thuật số của nó. Nó quan trọng. Chúng ta hãy ghi nhớ điều này, bởi vì... Chúng ta sẽ quay lại thực tế này sau. Vì vậy, trước đó chúng tôi đã sử dụng HttpListener để thông báo cho máy chủ cách hoạt động qua giao thức HTTP. Nếu trong ví dụ trên, chúng ta đã thêm một HttpListener để hoạt động qua HTTP, thì để hoạt động trên HTTPS, chúng ta cần thêm một HttpsListener:
Từ HTTP đến HTTPS - 7
Nhưng để thêm nó chúng ta cần SSLContext. Điều thú vị là SSLContext không phải là một lớp từ Undertow mà là javax.net.ssl.SSLContext. Lớp SSLContext là một phần của cái gọi là " Java Secure Socket Extension " (JSSE) - một tiện ích mở rộng Java để đảm bảo bảo mật kết nối Internet. Tiện ích mở rộng này được mô tả trong " Hướng dẫn tham khảo tiện ích mở rộng ổ cắm bảo mật Java (JSSE) ". Như bạn có thể thấy từ phần giới thiệu của tài liệu, JSSE cung cấp một khung và triển khai Java cho các giao thức SSL và TLS. Làm cách nào để chúng tôi nhận được SSLContext? Mở JavaDoc SSLContext và tìm phương thức getInstance . Như bạn có thể thấy, để có được SSLContext, chúng ta cần chỉ định tên "Giao thức ổ cắm an toàn". Mô tả các tham số chỉ ra rằng những tên này có thể được tìm thấy trong " Tài liệu tên thuật toán tiêu chuẩn kiến ​​trúc mã hóa Java ". Vì vậy, hãy làm theo hướng dẫn và đi đến tài liệu. Và chúng tôi thấy rằng chúng tôi có thể chọn giữa SSL và TLS:
Từ HTTP đến HTTPS - 8
Bây giờ chúng ta hiểu rằng chúng ta cần tạo SSLContext như sau:
public SSLContext getSSLContext() {
	// 1. Получаем контекст, в рамках которого будем работать по TLS протоколу
	SSLContext context = null;
	try {
		context = SSLContext.getInstance("TLS");
	} catch (NoSuchAlgorithmException e) {
		throw new IllegalStateException(e);
	}
	return context;
}
Sau khi tạo một bối cảnh mới, chúng tôi nhớ rằng SSLContext đã được mô tả trong " Hướng dẫn tham khảo phần mở rộng ổ cắm bảo mật Java (JSSE) ". Chúng tôi đọc và thấy rằng “SSLContext mới được tạo nên được khởi tạo bằng cách gọi phương thức init”. Nghĩa là, tạo bối cảnh thôi là chưa đủ. Nó cần phải được khởi tạo. Và điều này là hợp lý, bởi vì về bảo mật, chúng tôi chỉ nói với bạn rằng chúng tôi muốn sử dụng giao thức TLS. Để khởi tạo SSLContext, chúng tôi cần cung cấp ba thứ: KeyManager, TrustManager, SecureRandom.
Từ HTTP đến HTTPS - 9

Trình quản lý khóa

KeyManager là một trình quản lý khóa. Anh ta chịu trách nhiệm về “thông tin xác thực” cần cung cấp cho người liên hệ với chúng tôi. Thông tin xác thực có thể được dịch là danh tính. Cần có danh tính để khách hàng chắc chắn rằng máy chủ chính là người mà họ tuyên bố và có thể tin cậy được. Điều gì sẽ được sử dụng làm nhận dạng? Như chúng tôi đã nhớ, Nhận dạng máy chủ được xác minh bằng chứng chỉ kỹ thuật số của máy chủ. Quá trình này có thể được biểu diễn như sau:
Từ HTTP đến HTTPS - 10
Ngoài ra, " Hướng dẫn tham khảo JSSE: Cách thức hoạt động của SSL " nói rằng SSL sử dụng "mật mã bất đối xứng", có nghĩa là chúng ta cần một cặp khóa: khóa chung và khóa riêng. Vì chúng ta đang nói về mật mã nên “Kiến trúc mật mã Java” (JCA) sẽ phát huy tác dụng. Oracle cung cấp một tài liệu tuyệt vời về kiến ​​trúc này: " Hướng dẫn tham khảo kiến ​​trúc mật mã Java (JCA) ". Ngoài ra, bạn có thể đọc phần tổng quan ngắn gọn về JCA trên JavaRush: " Kiến trúc mật mã Java: Lần đầu làm quen ." Vì vậy, để khởi tạo KeyManager, chúng ta cần có KeyStore, nơi sẽ lưu trữ chứng chỉ máy chủ của chúng ta. Cách phổ biến nhất để tạo kho lưu trữ khóa và chứng chỉ là tiện ích keytool, được bao gồm trong JDK. Có thể xem một ví dụ trong tài liệu JSSE: " Tạo Keystore để sử dụng với JSSE ". Vì vậy, chúng ta cần sử dụng tiện ích KeyTool để tạo kho khóa và ghi chứng chỉ vào đó. Điều thú vị là việc tạo khóa trước đây được chỉ định bằng -genkey, nhưng bây giờ nên sử dụng -genkeypair. Chúng ta sẽ cần xác định những điều sau:
  • bí danh : Bí danh hoặc đơn giản là tên mà mục nhập sẽ được lưu trong Keystore
  • keyalg : Thuật toán mã hóa khóa. Hãy chọn thuật toán RSA, về cơ bản đây là một giải pháp tiêu chuẩn cho mục đích của chúng ta.
  • keysize : Kích thước khóa (tính bằng bit). Kích thước tối thiểu được đề xuất là 2048, bởi vì... một kích thước nhỏ hơn đã bị nứt. Bạn có thể đọc thêm tại đây: " chứng chỉ ssl 2048 bit ".
  • dname : Tên phân biệt, tên phân biệt.
Điều quan trọng là phải hiểu rằng tài nguyên được yêu cầu (ví dụ: https://localhost) sẽ được so sánh với tài nguyên đó. Điều này được gọi là "khớp chủ đề cn".
  • hiệu lực : Khoảng thời gian tính bằng ngày mà chứng chỉ được tạo có hiệu lực, tức là có hiệu lực.
  • ext : Tiện ích mở rộng chứng chỉ được chỉ định trong " Tiện ích mở rộng được đặt tên ".
Đối với Chứng chỉ tự ký (tức là đối với chứng chỉ được tạo độc lập), bạn phải chỉ định các tiện ích mở rộng sau:
  • -ext san:cript=dns:localhost,ip:127.0.0.1 > để thực hiện khớp chủ đề theo Chủ đềAlternativeName
  • -ext bc=ca:false > để chỉ ra rằng chứng chỉ này không được sử dụng để ký các chứng chỉ khác
Hãy chạy lệnh (ví dụ cho hệ điều hành 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
Bởi vì tệp sẽ được tạo, hãy đảm bảo rằng bạn có mọi quyền để tạo tệp. Bạn cũng có thể sẽ thấy lời khuyên như thế này:
Từ HTTP đến HTTPS - 11
Ở đây chúng tôi được biết rằng JKS là một định dạng độc quyền. Độc quyền có nghĩa là nó là tài sản riêng của các tác giả và chỉ được sử dụng trong Java. Khi làm việc với các tiện ích của bên thứ ba, xung đột có thể phát sinh, đó là lý do tại sao chúng tôi được cảnh báo. Ngoài ra, chúng tôi có thể nhận được lỗi: The destination pkcs12 keystore has different storepass and keypass. Lỗi này xảy ra do mật khẩu của mục nhập trong Kho khóa và mật khẩu của chính kho khóa khác nhau. Như tài liệu về keytool cho biết : "Ví dụ: hầu hết các công cụ của bên thứ ba đều yêu cầu mật khẩu cửa hàng và mật khẩu khóa trong kho khóa PKCS #12 phải giống nhau." Chúng ta có thể tự chỉ định khóa (ví dụ: -destkeypass entrypassw). Nhưng tốt hơn hết là đừng vi phạm các yêu cầu và đặt cùng một mật khẩu. Vì vậy, quá trình nhập có thể trông như thế này:
keytool -importkeystore -srckeystore C:/keystore.jks -destkeystore C:/keystore.jks -deststoretype pkcs12
Ví dụ thành công:
Từ HTTP đến HTTPS - 12
Để xuất chứng chỉ sang một tệp, bạn có thể chạy:
keytool -export -alias ssl -storepass passw0rd -file C:/server.cer -keystore C:/keystore.jks
Ngoài ra, chúng ta có thể lấy nội dung Keystore như thế này:
keytool -list -v -keystore C:/keystore.jks -storepass passw0rd
Tuyệt vời, giờ chúng ta đã có kho khóa chứa chứng chỉ. Bây giờ bạn có thể lấy nó từ mã:
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);
	}
}
Nếu có KeyStore thì chúng ta có thể khởi tạo 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);
	}
}
Mục tiêu đầu tiên của chúng tôi đã đạt được. Vẫn còn phải tìm ra TrustManager là gì. TrustManager được mô tả trong tài liệu JSSE trong phần " Giao diện TrustManager ". Nó rất giống với KeyManager nhưng mục đích của nó là kiểm tra xem người yêu cầu kết nối có đáng tin cậy hay không. Nói trắng ra thì đây là KeyManager đảo ngược =) Chúng ta không cần TrustManager nên sẽ chuyển null. Sau đó, TrustManager mặc định sẽ được tạo để không xác minh người dùng cuối đưa ra yêu cầu đối với máy chủ của chúng tôi. Tài liệu nói như vậy: "việc triển khai mặc định sẽ được sử dụng". Tương tự với SecureRandom Nếu chúng tôi chỉ định null, việc triển khai mặc định sẽ được sử dụng. Chúng ta hãy nhớ rằng SecureRandom là một lớp JCA và được mô tả trong tài liệu JCA trong phần " Lớp SecureRandom ". Nhìn chung, quá trình chuẩn bị có tính đến tất cả các phương pháp được mô tả ở trên có thể trông như thế này:
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);
	}
Tất cả những gì còn lại là khởi động máy chủ:
// 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();
}
Lần này máy chủ của chúng tôi sẽ có sẵn tại địa chỉ https://localhost:443 Tuy nhiên, chúng tôi vẫn sẽ nhận được lỗi rằng tài nguyên này không thể tin cậy được:
Từ HTTP đến HTTPS - 13
Hãy cùng tìm hiểu xem chứng chỉ có vấn đề gì và phải làm gì với nó.
Từ HTTP đến HTTPS - 14

Quản lý chứng chỉ

Vì vậy, máy chủ của chúng tôi đã sẵn sàng hoạt động thông qua HTTPS, nhưng khách hàng không tin tưởng nó. Tại sao? Chúng ta hãy xem:
Từ HTTP đến HTTPS - 15
Lý do là chứng chỉ này là Chứng chỉ tự ký. Chứng chỉ SSL tự ký đề cập đến chứng chỉ khóa công khai được cấp và ký bởi cùng một người mà nó xác định. Nghĩa là, nó không được cấp bởi bất kỳ cơ quan cấp chứng chỉ uy tín nào (CA, còn được gọi là Cơ quan cấp chứng chỉ). Cơ quan cấp chứng chỉ hoạt động như một người được ủy thác và tương tự như một công chứng viên trong cuộc sống hàng ngày. Ông đảm bảo rằng các chứng chỉ ông cấp là đáng tin cậy. Dịch vụ cấp chứng chỉ của các CA như vậy được trả phí nên không ai phải mất niềm tin và rủi ro về uy tín. Theo mặc định, có một số cơ quan cấp chứng chỉ đáng tin cậy. Danh sách này có thể chỉnh sửa được. Và mỗi hệ điều hành đều có sự quản lý riêng về danh sách các cơ quan cấp chứng chỉ. Ví dụ: quản lý danh sách này trong Windows có thể đọc tại đây: " Quản lý chứng chỉ gốc đáng tin cậy trong Windows ". Hãy thêm chứng chỉ vào những chứng chỉ đáng tin cậy như được nêu trong thông báo lỗi. Để thực hiện việc này, trước tiên, hãy tải xuống chứng chỉ:
Từ HTTP đến HTTPS - 16
Trong hệ điều hành Windows, nhấn Win+R và thực hiện mmcđể gọi bảng điều khiển. Tiếp theo, nhấn Ctrl+M để thêm phần “Chứng chỉ” vào bảng điều khiển hiện tại. Tiếp theo, trong tiểu mục "Cơ quan chứng nhận gốc đáng tin cậy", chúng tôi sẽ thực thi các tệp Действия / Все задачи / Импорт. Hãy nhập tệp đã được tải xuống trước đó vào tệp. Trình duyệt có thể đã ghi nhớ trạng thái tin cậy trước đây của chứng chỉ. Do đó, trước khi mở trang bạn cần khởi động lại trình duyệt. Ví dụ: trong Google Chrome trên thanh địa chỉ, bạn cần chạy chrome://restart. Trong hệ điều hành Windows, bạn cũng có thể sử dụng tiện ích để xem chứng chỉ certmgr.msc:
Từ HTTP đến HTTPS - 17
Nếu chúng tôi đã làm mọi thứ chính xác, chúng tôi sẽ thấy cuộc gọi thành công đến máy chủ của mình thông qua HTTPS:
Từ HTTP đến HTTPS - 18
Như bạn có thể thấy, chứng chỉ hiện được coi là hợp lệ, tài nguyên có sẵn và không có lỗi.
Từ HTTP đến HTTPS - 19

Điểm mấu chốt

Vì vậy, chúng tôi đã tìm ra sơ đồ kích hoạt giao thức HTTPS trên máy chủ web trông như thế nào và những gì cần thiết cho việc này. Tôi hy vọng tại thời điểm này, rõ ràng là sự hỗ trợ được cung cấp bởi sự tương tác của Kiến trúc mật mã Java (JCA), chịu trách nhiệm về mật mã và Phần mở rộng ổ cắm bảo mật Java (JSSE), cung cấp triển khai TLS ở phía Java. Chúng ta đã thấy cách sử dụng tiện ích keytool có trong JDK để hoạt động với kho khóa và chứng chỉ KeyStore. Ngoài ra, chúng tôi nhận thấy rằng HTTPS sử dụng giao thức SSL/TLS để bảo mật. Để củng cố điều này, tôi khuyên bạn nên đọc những bài viết hay về chủ đề này: Hy vọng rằng sau lần đánh giá nhỏ này, HTTPS sẽ trở nên minh bạch hơn một chút. Và nếu bạn cần kích hoạt HTTPS, bạn có thể dễ dàng hiểu các điều khoản từ tài liệu về máy chủ và khung ứng dụng của mình. #Viacheslav
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION