記一篇http巫财,ws通過nginx加殼打造https和wss

記一篇http盗似,ws通過nginx加殼打造https和wss

產(chǎn)生背景

我們通常開發(fā)的應(yīng)用都是基于http的,但是在使用h5的notification功能的時候平项,要求必須是https才行赫舒,所以在這種類似的情況下不得不使用https,但是我們又不想改動原來的應(yīng)用闽瓢。這個時候我們就需要通過nginx做反向代理接癌,在nginx這層加個ssl的殼。相當(dāng)于是用戶訪問nginx時是https扣讼,nginx轉(zhuǎn)發(fā)到目的服務(wù)器的時候就已經(jīng)變成http了缺猛。我們的ssl的殼只是加在nginx這層

ws加殼變成wss的原因是因為我們的應(yīng)用在web端使用了websocket(連接mqtt)椭符,但是因為原應(yīng)用變成https之后荔燎,ws會被瀏覽器broken,意思就是我們使用https销钝,那么就必須使用wss有咨。當(dāng)然wss也是使用nginx反向代理,加個殼蒸健。

好了背景了解了座享,我們現(xiàn)在來開始處理這個轉(zhuǎn)變過程中會出現(xiàn)的一些問題和解決辦法。

第一步http轉(zhuǎn)https

這一步纵装,我們使用openssl可以生成自簽名的證書征讲,證書是.pem或者cer都可以,這個不影響橡娄。

生成的時候會讓我們填一些信息诗箍,注意一下common_name,填這個信息的時候需要填成域名挽唉!后續(xù)會有其他方式生成滤祖,那個時候就不用填域名了筷狼,但是這里我們需要填成域名。

命令:

生成秘鑰: openssl genrsa -out privkey.pem 1024/2038
生成key: openssl req -new -x509 -key privkey.pem -out server.pem -days 365

生成之后在nginx端配置上相應(yīng)的證書匠童,我為了方便埂材,將證書放在和nginx.conf同樣的位置了,后續(xù)也一樣汤求,我就不提了俏险。

http {
...
 server {
        listen       443 ssl;
        server_name www.bb.com;
        
        ssl_certificate server.pem;
        ssl_certificate_key privkey.key;
        error_log   logs/error.log;
        client_max_body_size 60M;
        client_body_buffer_size 512k;
        location ~/.* {
            proxy_pass   http://127.0.0.1:7080;
        }
    }
...
}

配置完成之后,在host配置www.bb.com的本地DNS扬绪。

配置完之后竖独,我們使用這個域名打開應(yīng)用頁面。這個時候會出現(xiàn)如下的界面挤牛,不安全的鏈接莹痢。當(dāng)然,在這種情況下我們可以直接點高級墓赴,繼續(xù)前往也能正確訪問竞膳。

not_auth_ssl.png

我們從圖中可以看到是ERR_AUTHORITY_INVALID錯誤,這種是認證錯誤诫硕,說明證書不被信任坦辟。這種情況我們可以通過chrome導(dǎo)入受信任證書,或者通過windows的運行痘括,輸入certmgr.msc指令长窄,導(dǎo)入我們生成的server.pem證書滔吠。

導(dǎo)入過后纲菌,我們再次重啟瀏覽器,會發(fā)現(xiàn)依然是這個界面疮绷,只是錯誤變成了ERR_CERT_COMMON_NAME_INVALID翰舌,這個是錯誤的common_name,這個是啥東西冬骚,這個就是我們的域名不匹配證書導(dǎo)致的椅贱。

common_name_err.png

不管是上面的哪種錯誤,如果只是https只冻,那么整個就算是完了庇麦,沒有任何其他的問題,這種錯誤可以不用管它喜德,但是如果有wss在的話這種情況就就必須要處理了山橄。

wss

我們先來試試不處理上訴問題時wss會怎樣。

首先我們必須明確的是舍悯,不管是ws還是wss航棱,我們都得走nginx轉(zhuǎn)睡雇。那么我們先來配一下wss的nginx轉(zhuǎn)發(fā)的配置(和上面使用的是同一個nginx,只是加了個配置)饮醇。這里我們mqtt加了新的域名它抱,im.mqtt.chat,并且我們使用8083為ssl端口朴艰。

http{
...
server {
        listen 8083 ssl;
        server_name im.mqtt.chat;
    
        ssl_certificate server.pem;
        ssl_certificate_key privkey.key;
        ssl_protocols SSLv3 SSLv2 TLSv1 TLSv1.1 TLSv1.2;
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        # ssl_prefer_server_ciphers on;
    

        location /mqtt{
            #反向代理到mqtt的ws端口8083观蓄,同時協(xié)議轉(zhuǎn)換為http,這樣服務(wù)器端代碼就不需要做修改
            proxy_pass http://192.168.55.111:8083;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            #由于服務(wù)器端源碼(建議大家做好大小寫匹配)只匹配了"Upgrade"字符串,所以如果這里填"upgrade"服務(wù)器端會將這條http請求當(dāng)成普通的請求,導(dǎo)致websocket握手失敗
            proxy_set_header Connection "Upgrade";
            proxy_set_header Remote_addr $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_read_timeout 600s;
        }
    }
...
}

從上面的配置中祠墅,我們可以看到蜘腌,我們使用和https一樣的證書,我們在轉(zhuǎn)發(fā)的過程中把/mqtt的wss請求轉(zhuǎn)發(fā)到mqtt的地址饵隙,也就是proxy_pass的值撮珠,可以看到協(xié)議也是轉(zhuǎn)成http了,8083是192.168.55.111這臺機器上mqtt的ws監(jiān)聽端口金矛。貼個圖吧芯急。

common_name_err.png

這里簡單介紹一下為什么是ws會轉(zhuǎn)給http吧。

HTTP/1.1 Upgrade

詳細的請查詢:HTTP升級機制

http/1.1提供了一個升級的機制驶俊,協(xié)議的升級請求總是由端發(fā)起的娶耍;暫時沒有服務(wù)端請求協(xié)議更改的機制。當(dāng)客戶端試圖升級到一個新的協(xié)議時饼酿,可以先發(fā)送一個普通的請求(GET榕酒,POST等),不過這個請求需要進行特殊配置以包含升級請求故俐。

特別這個請求需要添加兩項額外的header:

# 設(shè)置Connection頭的值為“Upgrade”來指示這是一個升級請求
Connection: Upgrade
# Upgrade頭指定一項或多想?yún)f(xié)議名想鹰,按照有銜接排序,以逗號分隔
Upgrade: protocols

如果服務(wù)器決定升級這次連接药版,就會返回一個 101 Switching Protocols響應(yīng)狀態(tài)碼辑舷,和一個要切換到的協(xié)議的頭部字段Upgrade。 如果服務(wù)器沒有(或者不能)升級這次連接槽片,它會忽略客戶端發(fā)送的 "Upgrade 頭部字段何缓,返回一個常規(guī)的響應(yīng):例如一個200 OK).

服務(wù)在發(fā)送 101 狀態(tài)碼之后,就可以使用新的協(xié)議还栓,并可以根據(jù)需要執(zhí)行任何其他協(xié)議指定的握手碌廓。實際上,一旦這次升級完成了剩盒,連接就變成了雙向管道谷婆。并且可以通過新協(xié)議完成啟動升級的請求。

所以,再來看我們的nginx配置當(dāng)中多出來的其中兩項:

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";

測試

配置好之后波材,我們來看看頁面鏈接mqtt的情況股淡。

mqtt_auth_err.png

我們打開控制臺,可以咋netwrk下的ws標(biāo)簽下看到ws的請求廷区,在console頁可以看大ws證書出現(xiàn)的問題是ERR_CERT_AUTHORITY_INVALID唯灵,當(dāng)然也有可能是和之前https一樣的COMMON_NAME_ERR.這個就不演示了。反正這種錯誤就說明證書是不受信任的隙轻。

但是可能我們會想埠帕,我們不是已經(jīng)把證書導(dǎo)入了嗎,而且導(dǎo)入的還是受信任的根證書玖绿,為什么還會使不受信任呢敛瓷。其實我們https連接的時候就可以看出來,路徑上https是被叉掉了的斑匪,這就說證書是不信任的呐籽,那是什么情況呢。

chrome解決自簽名證書無效

chrome驗證證書很嚴格蚀瘸,必須帶有Subject Alternative Name.

簽發(fā)csr(Certificate Signing Request 證書簽名請求文件)時狡蝶,也就是我們生成證書的時候,我們需要修改openssl的配置贮勃。

linux下找一下openssl.cnf文件贪惹。cp一份到當(dāng)前open文件夾下面。

cp /etc/pki/tls/openssl.cnf ~/open/

第一步寂嘉,在[ req ]節(jié)添加:

req_extetions = v3_req

第二步奏瞬,添加v3_req節(jié)的配置

[ v3_req ] # Extensions to add to a certificate request 
basicConstraints = CA:FALSE 
keyUsage = nonRepudiation, digitalSignature, keyEncipherment 
subjectAltName = @alt_names

第三步,在alt_names添加受信任域名,這個受信任的域名用處就是泉孩,我們生成的證書只能是以下域名使用才行硼端,否則會報COMMON_NAME_INVALID錯誤。

[ alt_names ]
134 DNS.1 = localhost
135 DNS.2 = im.mqtt.chat
136 DNS.3 = www.bb.com

改完之后是這樣:

openssl_cnf.png

貼下代碼:

[ req ]
...
req_extetions = v3_req
...
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = localhost
DNS.2 = im.mqtt.chat
DNS.3 = www.bb.com

為了我們生成一份兒證書棵譬,兩個域名都可以使用显蝌,我這里就直接把兩個域名都配置上了预伺,方便而已订咸,如果不嫌麻煩的可以分開。

配置好之后我們使用我們的修改好的配置文件來生成我們的證書酬诀,以下命令會一次性生成crt證書和key脏嚷,生成的時候會讓填一些雜七雜八的信息,都可以亂填瞒御,因為我們配置這次我們修改了配置文件父叙,證書信任的域名已經(jīng)配置了,所以在這步當(dāng)中讓我們填的common_name也可以不用像之前那樣填域名,隨便填個值都行趾唱。

openssl req -sha256 -newkey rsa:2048 -nodes -keyout  mssl.key -x509 -days 3650 -out  mssl.crt -config ./openssl.cnf -extensions v3_req

生成之后涌乳,我們也是需要將證書導(dǎo)入到受信任的證書伙单。我這里就直接使用certmgr.msc來安裝了冷离,當(dāng)然我們這次生成的是crt證書夯到,這個可以直接雙擊安裝忙上。我這里貼一個cermgr.msc的圖吧,在“操作->所有任務(wù)->導(dǎo)入”可以導(dǎo)入我們的證書砾层。

certmgr.png

導(dǎo)入證書之后雳旅,修改一下nginx的https和wss的證書配置治拿。

http {
  server {
        listen       443 ssl;
        server_name www.bb.com;
        
        ssl_certificate mssl.crt;
        ssl_certificate_key mssl.key;
        error_log   logs/error.log;
        client_max_body_size 60M;
        client_body_buffer_size 512k;
        location ~/.* {
            proxy_pass   http://127.0.0.1:7080;
        }
    }
    
    server {
        listen 8083 ssl;
        server_name im.mqtt.chat;
    
        ssl_certificate mssl.crt;
        ssl_certificate_key mssl.key;
        ssl_protocols SSLv3 SSLv2 TLSv1 TLSv1.1 TLSv1.2;
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        # ssl_prefer_server_ciphers on;
    

        location /mqtt{
             #反向代理到mqtt的ws端口8083逃糟,同時協(xié)議轉(zhuǎn)換為http析既,這樣服務(wù)器端代碼就不需要做修改
            proxy_pass http://192.168.55.111:8083;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            #由于服務(wù)器端源碼(建議大家做好大小寫匹配)只匹配了"Upgrade"字符串,所以如果這里填"upgrade"服務(wù)器端會將這條http請求當(dāng)成普通的請求,

導(dǎo)致websocket握手失敗
            proxy_set_header Connection "Upgrade";
            proxy_set_header Remote_addr $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_read_timeout 600s;
        }
    }   
}

可以看到我們兩個地方都是改成了mssl.crt和mssl.key躬贡。reload一下nginx(nginx -s reload).

可以慶祝了

重啟瀏覽器,我們可以看到眼坏,我們的鏈接變成安全的鏈接了拂玻。

mqtt也正常鏈接,沒有報錯了宰译,查看mqtt的鏈接纺讲,也可以正常看到返回的是101囤屹,協(xié)議升級熬甚,header中Upgrade字段也返回了本次升級的協(xié)議是websocket。

測試通過肋坚,h5的Notification功能也正常使用乡括。到此為止,ws和http加殼就算完成了智厌。

result.png

over~~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末诲泌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子铣鹏,更是在濱河造成了極大的恐慌敷扫,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诚卸,死亡現(xiàn)場離奇詭異葵第,居然都是意外死亡,警方通過查閱死者的電腦和手機合溺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進店門卒密,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人棠赛,你說我怎么就攤上這事哮奇√鸥” “怎么了?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵鼎俘,是天一觀的道長哲身。 經(jīng)常有香客問我,道長贸伐,這世上最難降的妖魔是什么律罢? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮棍丐,結(jié)果婚禮上误辑,老公的妹妹穿的比我還像新娘。我一直安慰自己歌逢,他們只是感情好巾钉,可當(dāng)我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著秘案,像睡著了一般砰苍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上阱高,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天赚导,我揣著相機與錄音,去河邊找鬼赤惊。 笑死吼旧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的未舟。 我是一名探鬼主播圈暗,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼裕膀!你這毒婦竟也來了员串?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤昼扛,失蹤者是張志新(化名)和其女友劉穎寸齐,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抄谐,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡渺鹦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了斯稳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片海铆。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖挣惰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤憎茂,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布珍语,位于F島的核電站,受9級特大地震影響竖幔,放射性物質(zhì)發(fā)生泄漏板乙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一拳氢、第九天 我趴在偏房一處隱蔽的房頂上張望募逞。 院中可真熱鬧,春花似錦馋评、人聲如沸放接。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纠脾。三九已至,卻和暖如春蜕青,著一層夾襖步出監(jiān)牢的瞬間苟蹈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工右核, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留慧脱,地道東北人。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓贺喝,卻偏偏與公主長得像磷瘤,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子搜变,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內(nèi)容