傳送基於TLS1.2的HTTPS請求
阿新 • • 發佈:2019-02-05
本文主要介紹瞭如何傳送基於TLS1.2安全協議的HTTPS請求
由於目前對網路安全越來越重視,我們會在HTTP的基礎上加上一些安全協議
目前最為廣泛所使用的安全協議是TLS1.2
很多服務端容器都已經支援通過配置來設定HTTPS的埠從而支援HTTPS協議
在傳送HTTPS的請求之前我們需要獲取服務端提供的簽名證書
之後將簽名證書通過keytool命令匯入到本地的keystore中,方便java應用對其進行訪問
想要傳送HTTPS(TLS1.2)請求需要2個類的支援:
第一個類:
package com.HTTPtransfer.test; import java.io.FileInputStream; import java.security.KeyStore; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Date; import javax.crypto.Cipher; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManagerFactory; /** * Certificate Model * * @author * @version 1.0 * @since 1.0 */ public class CertificateManager extends Coder { /** * Java key store (Java Key Store,JKS)KEY_STORE */ public static final String KEY_STORE = "JKS"; public static final String X509 = "X.509"; public static final String SunX509 = "SunX509"; public static final String SSL = "SSL"; /** * accord KeyStore get private key * * @param keyStorePath * @param alias * @param password * @return * @throws Exception */ private static PrivateKey getPrivateKey(String keyStorePath, String alias, String password) throws Exception { KeyStore ks = getKeyStore(keyStorePath, password); PrivateKey key = (PrivateKey) ks.getKey(alias, password.toCharArray()); return key; } /** * accord Certificate get public key * * @param certificatePath * @return * @throws Exception */ private static PublicKey getPublicKey(String certificatePath) throws Exception { Certificate certificate = getCertificate(certificatePath); PublicKey key = certificate.getPublicKey(); return key; } /** * get Certificate * * @param certificatePath * @return * @throws Exception */ private static Certificate getCertificate(String certificatePath) throws Exception { CertificateFactory certificateFactory = CertificateFactory.getInstance(X509); FileInputStream in = new FileInputStream(certificatePath); Certificate certificate = certificateFactory.generateCertificate(in); in.close(); return certificate; } /** * get Certificate * * @param keyStorePath * @param alias * @param password * @return * @throws Exception */ private static Certificate getCertificate(String keyStorePath, String alias, String password) throws Exception { KeyStore ks = getKeyStore(keyStorePath, password); Certificate certificate = ks.getCertificate(alias); return certificate; } /** * get KeyStore * * @param keyStorePath * @param password * @return * @throws Exception */ private static KeyStore getKeyStore(String keyStorePath, String password) throws Exception { FileInputStream is = new FileInputStream(keyStorePath); KeyStore ks = KeyStore.getInstance(KEY_STORE); ks.load(is, password.toCharArray()); is.close(); return ks; } /** * private key encrypt * * @param data * @param keyStorePath * @param alias * @param password * @return * @throws Exception */ public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath, String alias, String password) throws Exception { PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password); Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateKey); return cipher.doFinal(data); } /** * private key decrypt * * @param data * @param keyStorePath * @param alias * @param password * @return * @throws Exception */ public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath, String alias, String password) throws Exception { PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password); Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateKey); return cipher.doFinal(data); } /** * public key encrypt * * @param data * @param certificatePath * @return * @throws Exception */ public static byte[] encryptByPublicKey(byte[] data, String certificatePath) throws Exception { PublicKey publicKey = getPublicKey(certificatePath); Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return cipher.doFinal(data); } /** * public key decrypt * * @param data * @param certificatePath * @return * @throws Exception */ public static byte[] decryptByPublicKey(byte[] data, String certificatePath) throws Exception { PublicKey publicKey = getPublicKey(certificatePath); Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, publicKey); return cipher.doFinal(data); } /** * verify Certificate * * @param certificatePath * @return */ public static boolean verifyCertificate(String certificatePath) { return verifyCertificate(new Date(), certificatePath); } /** * verify Certificate is expired or invaild * * @param date * @param certificatePath * @return */ public static boolean verifyCertificate(Date date, String certificatePath) { boolean status = true; try { Certificate certificate = getCertificate(certificatePath); status = verifyCertificate(date, certificate); } catch (Exception e) { status = false; } return status; } /** * verify Certificate is expired or invaild * * @param date * @param certificate * @return */ private static boolean verifyCertificate(Date date, Certificate certificate) { boolean status = true; try { X509Certificate x509Certificate = (X509Certificate) certificate; x509Certificate.checkValidity(date); } catch (Exception e) { status = false; } return status; } /** * sign * * @param keyStorePath * @param alias * @param password * * @return * @throws Exception */ public static String sign(byte[] sign, String keyStorePath, String alias, String password) throws Exception { X509Certificate x509Certificate = (X509Certificate) getCertificate(keyStorePath, alias, password); KeyStore ks = getKeyStore(keyStorePath, password); PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password.toCharArray()); Signature signature = Signature.getInstance(x509Certificate.getSigAlgName()); signature.initSign(privateKey); signature.update(sign); return encryptBASE64(signature.sign()); } /** * vilidate sign * * @param data * @param sign * @param certificatePath * @return * @throws Exception */ public static boolean verify(byte[] data, String sign, String certificatePath) throws Exception { X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath); PublicKey publicKey = x509Certificate.getPublicKey(); Signature signature = Signature.getInstance(x509Certificate.getSigAlgName()); signature.initVerify(publicKey); signature.update(data); return signature.verify(decryptBASE64(sign)); } /** * validate Certificate * * @param keyStorePath * @param alias * @param password * @return */ public static boolean verifyCertificate(Date date, String keyStorePath, String alias, String password) { boolean status = true; try { Certificate certificate = getCertificate(keyStorePath, alias, password); status = verifyCertificate(date, certificate); } catch (Exception e) { status = false; } return status; } /** * vilidate Certificate * * @param keyStorePath * @param alias * @param password * @return */ public static boolean verifyCertificate(String keyStorePath, String alias, String password) { return verifyCertificate(new Date(), keyStorePath, alias, password); } /** * get SSLSocektFactory * * @param password * @param keyStorePath * @param trustKeyStorePath * @return * @throws Exception */ private static SSLSocketFactory getSSLSocketFactory(String password, String keyStorePath, String trustKeyStorePath) throws Exception { KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(SunX509); KeyStore keyStore = getKeyStore(keyStorePath, password); keyManagerFactory.init(keyStore, password.toCharArray()); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(SunX509); KeyStore trustkeyStore = getKeyStore(trustKeyStorePath, password); trustManagerFactory.init(trustkeyStore); SSLContext ctx = SSLContext.getInstance(SSL); ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); SSLSocketFactory sf = ctx.getSocketFactory(); return sf; } /** * config SSLSocketFactory for HttpsURLConnectioncon * * @param conn * HttpsURLConnection * @param password * @param keyStorePath * * @param trustKeyStorePath * @throws Exception */ public static void configSSLSocketFactory(HttpsURLConnection conn, String password, String keyStorePath, String trustKeyStorePath) throws Exception { conn.setSSLSocketFactory(getSSLSocketFactory(password, keyStorePath, trustKeyStorePath)); } }
第二個類:
package com.HTTPtransfer.test; import java.security.MessageDigest; import javax.crypto.KeyGenerator; import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; /** * Base Encrypt Model * * @author * @version 1.0 * @since 1.0 */ public abstract class Coder { public static final String KEY_SHA = "SHA"; public static final String KEY_MD5 = "MD5"; /** * Optional in many of the following algorithm MAC algorithm * * <pre> * HmacMD5 * HmacSHA1 * HmacSHA256 * HmacSHA384 * HmacSHA512 * </pre> */ public static final String KEY_MAC = "HmacMD5"; /** * BASE64 Decrypt * * @param key * @return * @throws Exception */ public static byte[] decryptBASE64(String key) throws Exception { return (new BASE64Decoder()).decodeBuffer(key); } /** * BASE64 Encrypt * * @param key * @return * @throws Exception */ public static String encryptBASE64(byte[] key) throws Exception { return (new BASE64Encoder()).encodeBuffer(key); } /** * MD5 Encrypt * * @param data * @return * @throws Exception */ public static byte[] encryptMD5(byte[] data) throws Exception { MessageDigest md5 = MessageDigest.getInstance(KEY_MD5); md5.update(data); return md5.digest(); } /** * SHA Encrypt * * @param data * @return * @throws Exception */ public static byte[] encryptSHA(byte[] data) throws Exception { MessageDigest sha = MessageDigest.getInstance(KEY_SHA); sha.update(data); return sha.digest(); } /** * InIt HMAC secret key * * @return * @throws Exception */ public static String initMacKey() throws Exception { KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC); SecretKey secretKey = keyGenerator.generateKey(); return encryptBASE64(secretKey.getEncoded()); } /** * HMAC Encrypt * * @param data * @param key * @return * @throws Exception */ public static byte[] encryptHMAC(byte[] data, String key) throws Exception { SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), KEY_MAC); Mac mac = Mac.getInstance(secretKey.getAlgorithm()); mac.init(secretKey); return mac.doFinal(data); } }
接下來才是傳送HTTPS請求的方法:
package com.HTTPtransfer.test;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import com.HTTPtransfer.test.Client_HTTP.ResponseBean;
public class TLS_Https {
public static void httpsRequest(String urlpath, String body) {
ResponseBean resBean = new ResponseBean();
int responseCode = -1;
String responseMessage = "Exception.";
HttpsURLConnection conn = null;
try {
java.lang.System.setProperty("https.protocols", "TLS1.2") ;
URL u = new URL(urlpath);
conn = (HttpsURLConnection) u.openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setConnectTimeout(20000);
conn.setReadTimeout(15000);
conn.setRequestMethod("POST");
conn.setUseCaches(false);
conn.setRequestProperty("Content-Type", "text/html;charset=UTF-8");
CertificateManager.configSSLSocketFactory(conn, Configuration.CLIENTPASSWORD,
Configuration.CLIENTKEYSTOREPATH, Configuration.CLIENTTRUSTOREPATH);
conn.connect();
OutputStream out = conn.getOutputStream();
out.write(body.getBytes());
out.flush();
out.close();
// Sleep 50 mill seconds wait for response.
Thread.sleep(50);
responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream in = conn.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in, ConfigurationFiles.CLIENT_CHARSET));
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line);
}
in.close();
conn.disconnect();
String responseMsg = sb.toString();
resBean.httpstatus = responseCode;
if (null == resBean.result_code) {
resBean.result_code = "999";
}
if (responseMessage == null) {
responseMessage = conn.getResponseMessage();
}
} else {
resBean.httpstatus = responseCode;
resBean.result_code = "999";
}
} catch (Exception e) {
e.printStackTrace();
}
resBean.httpstatus = responseCode;
resBean.result_code = "999";
}
}
在上面類中有3個物件是需要我們指定的,主要是keystore的絕對目錄
Configuration.CLIENTPASSWORD
Configuration.CLIENTKEYSTOREPATH
Configuration.CLIENTTRUSTOREPATH
java.lang.System.setProperty("https.protocols", "TLS1.2")
能夠將HTTPS的安全協議指定為TLS1.2