HTTPは平文通信を行うため、データが第三者に盗聴されるリスクがあります。HTTPSはSSL/TLSプロトコルを採用し、通信を暗号化することで、データの機密性と整合性を確保します。また、CA(証明機関)発行のデジタル証明書によるサーバー認証機能も備えており、フィッシング攻撃の防止に役立ちます。
さらに、検索エンジンのランキング向上や、最新のHTTP/2やTLS 1.3の導入による性能改善も、HTTPS採用の推進要因となっています。
自署名証明書の生成
コマンドラインツールを使用して、自署名証明書を生成します。
keytool -genkeypair -alias secure -keyalg RSA -keysize 4096 -validity 730 -storetype PKCS12 -keystore secure.p12 -storepass mysecret
各パラメータの説明:
-alias secure:キーのエイリアス名-keysize 4096:鍵の長さを4096ビットに設定-validity 730:有効期限を730日(2年)に設定-storepass mysecret:キーストアのパスワード
生成時に組織情報の入力を求められますが、自動入力する場合は-dnameオプションを使用できます。
keytool -genkeypair -alias secure -keyalg RSA -keysize 4096 -validity 730 -storetype PKCS12 -keystore secure.p12 -storepass mysecret -dname "CN=localhost, OU=IT, O=Example, L=Tokyo, ST=Tokyo, C=JP"
JavaによるHTTPSサーバー実装
以下は、生成した証明書を使用したHTTPSサーバーのコード例です。
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsServer;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.FileInputStream;
import java.net.InetSocketAddress;
import java.security.KeyStore;
public class SecureHttpServer {
public static void main(String[] args) throws Exception {
KeyStore ks = KeyStore.getInstance("PKCS12");
try (FileInputStream fis = new FileInputStream("secure.p12")) {
ks.load(fis, "mysecret".toCharArray());
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "mysecret".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ks);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
HttpsServer server = HttpsServer.create(new InetSocketAddress(8443), 0);
server.setHttpsConfigurator(new HttpsConfigurator(sslContext));
server.createContext("/secure", new HttpHandler() {
@Override
public void handle(HttpExchange exchange) {
if ("POST".equals(exchange.getRequestMethod())) {
try {
var json = new String(exchange.getRequestBody().readAllBytes());
System.out.println("受信データ: " + json);
String response = "{\"status\":\"success\"}";
exchange.sendResponseHeaders(200, response.getBytes().length);
try (var os = exchange.getResponseBody()) {
os.write(response.getBytes());
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
exchange.sendResponseHeaders(405, -1);
}
}
});
server.start();
System.out.println("HTTPSサーバー起動中: https://localhost:8443/secure");
}
}
HTTPSクライアントテスト
サーバーを起動した後、以下のようなクライアントコードでテストできます。
import javax.net.ssl.*;
import java.io.OutputStream;
import java.net.URL;
import java.security.cert.X509Certificate;
public class SecureClient {
public static void main(String[] args) throws Exception {
String urlStr = "https://localhost:8443/secure";
String jsonData = "{\"data\":\"test\"}";
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}}, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
URL url = new URL(urlStr);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
os.write(jsonData.getBytes());
}
try (var is = conn.getInputStream()) {
var response = new String(is.readAllBytes());
System.out.println("レスポンス: " + response);
}
}
}
コマンドラインでのテストには、curlコマンドを使用できます。
curl -X POST https://localhost:8443/secure -H "Content-Type: application/json" -d '{"data":"test"}' -k
HTTP 405エラーが発生した場合は、リクエストメソッドがPOSTであることを確認してください。サーバー側ではPOSTメソッドのみを許可しています。