問題描述
因為公司要求所有生產環境為了安全性需求,全部都走https, 並且在Nginx里面加入了Content-Security-Policy "upgrade-insecure-requests;connect-src *響應頭, 作用是讓瀏覽器自動升級請求,防止訪問者訪問不安全的內容。
該指令用於讓瀏覽器自動升級請求從http到https,用於大量包含http資源的http網頁直接升級到https.雖然這樣讓http升級為https,但是導致出現的問題是,之前加載http資源的
圖片顯示不了
,樣式,js加載不了
, 寫在本地還行,但如果是公共的js文件,往往就是存在cdn或者其他服務器上, 這時候如果訪問不了,可能導致業務完全操作不了, 比如: jquery加載失效,所有操作,請求都將無效了
https和http共存場景
https是當下的網站的主流趨勢,甚至像蘋果這樣的大公司,則完全要求用戶必須使用https地址。
然而對於以前http鏈接來說,我們往往就存在一個兼容性問題,因為你不可能一下就全部切換過去,應該在很長一段時間內,https與http將共存。
https與http共存場景如:
/*
1. app已經發布出去,其調用接口的地址為http的,那么這是必須兼容的。
2. app中嵌入了h5頁面,而這頁面在以前的設計中是使用http訪問的,如果換成https地址,極有可能將導致h5頁面無法打開。
3. 對於流量推廣一類的業務,可能原有的http推廣地址已經發送給第三方,而且即使你通知到第三方要求改為https,也不排除有http地址的訪問,或者第三方不願意改.
*/
問題分析
http協議與https協議區別
解決這個問題之前首先要知道https和http是什么, 區別在哪里.
https
它是一個安全通信通道,它基於HTTP開發,用於在客戶計算機和服務器之間交換信息,它使用安全套接字層(SSL)進行信息交換,簡單來說它是HTTP的安全版。它是由Netscape開發並內置於其瀏覽器中,用於對數據進行壓縮和解壓操作,並返回網絡上傳送回的結果。HTTPS實際上應用了Netscape的安全全套接字層(SSL)作為HTTP應用層的子層。(HTTPS使用端口443,而不是象HTTP那樣使用端口80來和TCP/IP進行通信。)SSL使用40 位關鍵字作為RC4流加密算法,這對於商業信息的加密是合適的。HTTPS和SSL支持使用X.509數字認證,如果需要的話用戶可以確認發送者是誰。總的來說,HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議要比http協議安全。
在URL前加
https://
前綴表明是用SSL加密的,你的電腦與服務器之間收發的信息傳輸將更加安全。 Web服務器啟用SSL需要獲得一個服務器證書並將該證書與要使用SSL的服務器綁定。
https與http區別
/*
1. https協議需要到ca申請證書,一般免費證書很少,需要交費。
2. http是超文本傳輸協議,信息是明文傳輸,https 則是具有安全性的ssl加密傳輸協議。
3. http和https使用的是完全不同的連接方式用的端口也不一樣,前者是80,后者是443。
4. http的連接很簡單,是無狀態的。
5. HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議 要比http協議安全。
*/
混合內容
當用戶訪問使用https頁面時, 他們與web服務器之間的連接是使用SSL加密的, 從而保護連接不受嗅探和中間人攻擊.
如果https頁面包括由普通明文http連接加密的內容, 那么連接只是被部分加密; 非加密的內容可以被嗅探者入侵, 並且可以被中間人攻擊者修改,因此連接不再受保護. 當一個頁面出現這種情況時, 他被稱為混合內容頁面.
在瀏覽器中訪問https頁面時,如果該htpps頁面中有一些http資源,我們可以把這些http資源,叫做混合內容(Mixed Content)。htpps頁面在顯示“混合內容”時候,會出現以下問題:
1、加載了混合內容,但會出現警告;
2、不加載混合內容,直接會顯示空白內容;
3、 在加載混合內容之前,會出現類似是否“顯示”,或存在不安全風險而被“阻止”的提示!
瀏覽器出現以上混合內容顯示的問題,是因為https協議請求的站點,讀取的資源文件js、css、圖片、音視頻,甚至包括請求post和get,還有iframe的頁面,都必須是https協議的。這是由於https協議傳輸的頁面比http更加安全可靠,為了保持https頁面安全的一致性而作出的反應。
但https頁面加載混合內容導致的問題帶來的用戶體驗確實不太好,給用戶造成了一定的麻煩,為了解決https頁面加載http資源出現的問題,我們可以通過以下幾種方式加以改進!
解決辦法
改https初看起來,其實就是一個域名指向的問題,也許我們只要將http的請求,直接跳轉到https地址去,那么也就完成了https的切換。實際並不是這么簡單的。
因為https地址中,如果加載了http資源,瀏覽器將認為這是不安全的資源,將會默認阻止,這就會給你帶來資源不全的問題了,比如:圖片顯示不了,樣式加載不了,JS加載不了.
我們雖然可以將http請求直接跳轉至https請求,是一種解決辦法, 而且很多公司都是這么干的,比如百度什么的,但是前提是,你所有的服務都已切換https完成。
如果說我們要兼容https,http兩種協議,應該怎樣做尼?
最笨辦法
直接復制原有代碼, 寫成兩套代碼,一套為https使用,一套為http使用,http和https各自指向各自服務
全站http換成https
將所有頁面中的圖片、視頻、音樂、js,css,ajax等帶有http的資源換成https方式,但要注意,有些外部http資源,如果沒有https方式,直接換成https就會出現問題,最好還是下載到本地來實現!
這種方式比較適用於那些http資源不是太多,或容易更換成https的網站.
可用辦法
用同一套代碼, 在后台請求標識好協議,將變量傳到html頁面, 進行協議替換, 如: 后台變量, ,$protocol = 'https://'; 前台接收變量 src='{$protocol}res.aa.com/jquery.js'.
h5辦法
. h5方法,使用js自己加載協議情況,如在body onload='aa()', 在aa() 方法中,將資源按照需求加載進來即可。
使用iframe
使用 iframe 的方式引入 http 資源,比如在 https 里面播放優酷的視頻,我們可以先在一個 http 的頁面里播放優酷視頻,然后將這個頁面嵌入到 https 頁面里就可以了。
另外一個典型的例子是在 https 頁面里通過 Ajax 的方式請求 http 資源,Chrome 是不允許直接 Ajax 請求 http 的。如果兩個頁面的內容都可以控制的話,當前窗口可以 iframe 窗口進行通信。
其他用法
這個小技巧同樣適用於 CSS
.omg { background: url(//test/kittyonadolphin.gif); }
推薦辦法
相對協議, 如果你的網站同時准備了https資源和http資源, 那么使用相對協議可以實現根據當前網站的協議,瀏覽器自行通過https還是http發送請求,使用資源協議自適配,比如,當前為https頁面,那么就是https資源,如果是http頁面,那么就是http資源。具體方法超簡單:將URL的協議(http,https去掉)
`