本文主要介绍了如何发送基于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