-
概念
http協(xié)議傳輸?shù)臄?shù)據(jù)都是未加密的,也就是明文的,因此使用http協(xié)議傳輸隱私信息非常不安全,為了保證這些隱私數(shù)據(jù)能加密傳輸,于是網(wǎng)景公司設(shè)計(jì)了ssl(Secure Sockets Layer)協(xié)議用于對http協(xié)議傳輸?shù)臄?shù)據(jù)進(jìn)行加密,從而就誕生了https。簡單來說,https協(xié)議是由http協(xié)議構(gòu)建的可進(jìn)行加密傳輸、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議,要比http協(xié)議安全。詳解:https://www.cnblogs.com/wqhwe/p/5407468.html
https是采用非對稱加密算法+對稱加密算法來保證數(shù)據(jù)的安全(c 客戶端 | s 服務(wù)端)。首先由c發(fā)起https請求s,s收到請求后返回證書(公鑰),然后c收到公鑰后隨機(jī)生成一個稱加密的密鑰,并使用s返回的公鑰加密生成的密鑰,發(fā)送至s,s使用自己的私鑰解密得到c的密鑰,后續(xù)都是用c生成的密鑰進(jìn)行通信
-
非對稱加密兩種用法:
- 第一種用法:
公鑰加密,私鑰解密。用于加解密(https中c向s發(fā)送隨即密鑰時使用此方式) - 第二種用法:
私鑰簽名,公鑰驗(yàn)簽。用于簽名
詳解:https://www.kuacg.com/22672.html
- 第一種用法:
-
-
HTTPS中間人攻擊
https的加密傳輸彌補(bǔ)了http明文傳輸?shù)陌踩[患,保證了在傳輸過程中信息的安全,但是https本身依舊存在一個隱患,即中間人攻擊。過程大致是,當(dāng)我們向https服務(wù)器發(fā)送請求時,請求被劫持(DNS劫持,或者信任不安全證書),然后偽裝成https服務(wù)器,接收c的請求,并返回c公鑰,然后建立與c端的請求,得到c的所有請求信息,并構(gòu)造一個c1偽裝為c與真實(shí)的s建立通信,得到所有的返回信息,這個過程信息就會被泄露或篡改。因?yàn)閏無法知道自己訪問到的是真正的s,還是偽裝成的s,所以https中間人攻擊依然使得https存在一定的安全風(fēng)險。而解決這一風(fēng)險的方式就是SSL證書+CA機(jī)構(gòu)
-
CA證書與keytool自制證書
CA證書為CA機(jī)構(gòu)頒發(fā)的SSL證書,keytool自制證書為使用java證書管理工具生成的證書。瀏覽器接受服務(wù)返回的證書后查找操作系統(tǒng)中已內(nèi)置的受信任的證書發(fā)布機(jī)構(gòu)CA,與服務(wù)器的證書中的CA匹配,查看是否為合法機(jī)構(gòu)頒發(fā),如果使用keytool自制證書則有可能被攔截,如果在keytool中將機(jī)構(gòu)寫成受信任的機(jī)構(gòu),瀏覽器從操作系統(tǒng)中獲取CA機(jī)構(gòu)的公鑰,解密證書中的簽名,同時使用相同的hash算法計(jì)算出服務(wù)器的證書的hash值與簽名做對比,對比結(jié)果即代表證書是否受信任
-
HostnameVerifier
在使用httpclient進(jìn)行https請求時,為防止https中間人攻擊http默認(rèn)會使用HostnameVerifer對請求證書中的主機(jī)名與配置的主機(jī)名或請求的主機(jī)名進(jìn)行匹配檢驗(yàn)以判斷證書是否為偽裝
-
SSL、TLS、SSH協(xié)議
SSH 應(yīng)用層的通信加密協(xié)議,往往用于遠(yuǎn)程登錄的會話;TLS(傳輸層安全協(xié)議)時SSL(安全套接層)標(biāo)準(zhǔn)化的結(jié)果
-
配置
-
Spring Boot 配置
首先生成證書:keytool -genkeypair -alias eairlv -keyalg RSA -keystore C:\eairlv.key然后配置:
server: port: 8083 ssl: key-store: eairlv.key key-store-type: JKS key-alias: eairlv key-store-password: eairlv.com http: port: 8084 -
注入Bean:
/** * server.port作為https端口 * 如果不配置http端口的bean則默認(rèn)只開啟https服務(wù) */ @Value("${server.port}") private Integer httpsPort; @Value("${http.port}") private Integer httpPort; @Bean public UndertowEmbeddedServletContainerFactory embeddedServletContainerFactory() { UndertowEmbeddedServletContainerFactory undertow = new UndertowEmbeddedServletContainerFactory(); undertow.addBuilderCustomizers((Undertow.Builder builder) -> builder.addHttpListener(httpPort, "0.0.0.0") ); log.info("undertow http port: {}, https port: {} ", httpPort, httpsPort); return undertow; } //spring boot 2.0 UndertowEmbeddedServletContainerFactory 被剔除 //spring boot 2.0 正確配置: /** * server.port作為https端口 */ @Value("${server.port}") private Integer httpsPort; @Value("${http.port}") private Integer httpPort; @Bean public UndertowServletWebServerFactory embeddedServletContainerFactory() { UndertowServletWebServerFactory undertow = new UndertowServletWebServerFactory(); undertow.addBuilderCustomizers((UndertowBuilderCustomizer) builder -> builder.addHttpListener(httpPort, "0.0.0.0") ); return undertow; } //增強(qiáng)版: @Bean public UndertowServletWebServerFactory embeddedServletContainerFactory() { UndertowServletWebServerFactory undertow = new UndertowServletWebServerFactory(); undertow.addBuilderCustomizers((UndertowBuilderCustomizer) builder -> { // IP配置'0.0.0.0'任意方式訪問 builder.addHttpListener(httpPort, "0.0.0.0"); // 開啟HTTP2 builder.setServerOption(UndertowOptions.ENABLE_HTTP2, true); }); undertow.addDeploymentInfoCustomizers(deploymentInfo -> { // 開啟HTTP自動跳轉(zhuǎn)至HTTPS deploymentInfo.addSecurityConstraint(new SecurityConstraint() .addWebResourceCollection(new WebResourceCollection().addUrlPattern("/*")) .setTransportGuaranteeType(TransportGuaranteeType.CONFIDENTIAL) .setEmptyRoleSemantic(SecurityInfo.EmptyRoleSemantic.PERMIT)) .setConfidentialPortManager(exchange -> httpsPort); }); return undertow; } //undertow配置http跳轉(zhuǎn)https后post接口400。 //https://stackoverflow.com/questions/37464220/springboot-undertow-redirect-post-from-http-to-https -
RestTemplate配置
@Bean public RestTemplate restTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException { TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true; SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom() .loadTrustMaterial(null, acceptingTrustStrategy) .build(); SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); CloseableHttpClient httpClient = HttpClients.custom() .setSSLContext(sslContext) .setSSLSocketFactory(csf) .build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient); return new RestTemplate(requestFactory); } //不可行方案: SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext); CloseableHttpClient httpClient = HttpClients.custom() .setSSLSocketFactory(csf) .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) .build(); //可行方案1: SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); CloseableHttpClient httpClient = HttpClients.custom() .setSSLSocketFactory(csf) .build(); //可行方案2: CloseableHttpClient httpClient = HttpClients.custom() .setSSLContext(sslContext) .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) .build(); // HttpClientBuilder // 933 public CloseableHttpClient build() {...} // 914 if (sslSocketFactoryCopy == null) {...} // 如果設(shè)置了SSLConnectionSocketFactory,CloseableHttpClient的HostnameVerifier就會使用SSLConnectionSocketFactory中的SSLHostnameVerifier,即出現(xiàn)不可行情況 -
血案
- httpclient訪問https血案:Certificate for <localhost> doesn't match any of the subject alternative names: []
- httpclient默認(rèn)會通過HostnameVerifier驗(yàn)證訪問主機(jī),而我們想要訪問https服務(wù)就需要對HostnameVerifier配置
- HostnameVerifier 擁有一個DefaultHostnameVerifier,它對訪問的主機(jī)名與證書中的主機(jī)名匹配校驗(yàn),如:https://api.eairlv.com:8443/v2/api可訪問(IE直接訪問證書合法),而訪問https://115.28.100.23:8443/v2/api則訪問不通過(IE直接訪問證書不合法)
-
信任證書
信任服務(wù)器證書,如果不配置證書信任,則httpclient默認(rèn)會對證書進(jìn)行校驗(yàn),keytool自制的證書則無法通過校驗(yàn)
-
https://api.eairlv.com:8443/v2/api,IE信任而httpclient默認(rèn)不信任,猜測為證書類型為DV,即信任等級較低。DV < OV < EV。DV證書僅對傳輸信息進(jìn)行加密,并不能真正證明網(wǎng)站的真實(shí)身份,只是提高了偽造身份的復(fù)雜度,依然存在https中間人攻擊的可能性(中間人擁有可信任機(jī)構(gòu)頒發(fā)的證書,且域名一致)
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true; SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom() .loadTrustMaterial(null, acceptingTrustStrategy) .build(); 或: SSLContext context = SSLContext.getInstance("TLS"); context.init(null, new TrustManager[] { new SkipX509TrustManager() }, new SecureRandom()); private static class SkipX509TrustManager implements X509TrustManager { @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } @Override public void checkClientTrusted(X509Certificate[] chain, String authType) { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) { } }
-
信任主機(jī)名(配置的主機(jī)名或請求的主機(jī)名與證書中主機(jī)名的匹配)
重寫HostnameVerifier類中的verify方法,可自行配置主機(jī)名的匹配規(guī)則,也可使用DefaultHostnameVerifier匹配請求的主機(jī)名與證書中的主機(jī)名,如果信任所有主機(jī)則只需使verify方法始終返回true
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); // 據(jù)說這種方式在google play上會報不合法,需要簡單的在verify中添加邏輯 SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, (s, sslSession) -> true);
-
-
總結(jié)
要想防止中間人攻擊證書的信任與主機(jī)名的信任需要同時開啟,我之前一直也覺得只需要信任證書就行了,為什么還需要信任主機(jī)名?而如果中間人偽裝的服務(wù)器也擁有CA信任證書,主機(jī)名則能夠幫助客戶端區(qū)分證書是否為真正受信任的CA證書。同一個域名可能對應(yīng)多個可信任證書,即依然存在安全隱患,而如果希望安全性更高的話,則可采取客戶端預(yù)埋證書的方式鎖死證書,當(dāng)客戶端證書與服務(wù)端證書完全一致才能進(jìn)行通信,對于證書過期問題則需要要求用戶在官網(wǎng)(軟件更新本身也會有可能被中間調(diào)包)下載證書來解決。在一般的Android程序中,連接https請求時為保證安全性可自定義規(guī)則,也可使用默認(rèn)(默認(rèn)更嚴(yán)格,自定義規(guī)則用于子域名的情況,CA通配符證書較貴),首先檢驗(yàn)證書是否被信任與主機(jī)名是否被信任,而在瀏覽器中則使用默認(rèn)的匹配規(guī)則以達(dá)到防止https中間人的攻擊
https總結(jié)及在java中的應(yīng)用
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。