记一篇http,ws通过nginx加壳打造https和wss

编程

记一篇http,ws通过nginx加壳打造https和wss

产生背景

我们通常开发的应用都是基于http的,但是在使用h5的notification功能的时候,要求必须是https才行,所以在这种类似的情况下不得不使用https,但是我们又不想改动原来的应用。这个时候我们就需要通过nginx做反向代理,在nginx这层加个ssl的壳。相当于是用户访问nginx时是https,nginx转发到目的服务器的时候就已经变成http了。我们的ssl的壳只是加在nginx这层。

ws加壳变成wss的原因是因为我们的应用在web端使用了websocket(连接mqtt),但是因为原应用变成https之后,ws会被浏览器broken,意思就是我们使用https,那么就必须使用wss。当然wss也是使用nginx反向代理,加个壳。

好了背景了解了,我们现在来开始处理这个转变过程中会出现的一些问题和解决办法。

第一步http转https

这一步,我们使用openssl可以生成自签名的证书,证书是.pem或者cer都可以,这个不影响。

生成的时候会让我们填一些信息,注意一下common_name,填这个信息的时候需要填成域名!后续会有其他方式生成,那个时候就不用填域名了,但是这里我们需要填成域名。

命令:

生成秘钥: openssl genrsa -out privkey.pem 1024/2038

生成key: openssl req -new -x509 -key privkey.pem -out server.pem -days 365

生成之后在nginx端配置上相应的证书,我为了方便,将证书放在和nginx.conf同样的位置了,后续也一样,我就不提了。

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。

配置完之后,我们使用这个域名打开应用页面。这个时候会出现如下的界面,不安全的链接。当然,在这种情况下我们可以直接点高级,继续前往也能正确访问。

我们从图中可以看到是ERR_AUTHORITY_INVALID错误,这种是认证错误,说明证书不被信任。这种情况我们可以通过chrome导入受信任证书,或者通过windows的运行,输入certmgr.msc指令,导入我们生成的server.pem证书。

导入过后,我们再次重启浏览器,会发现依然是这个界面,只是错误变成了ERR_CERT_COMMON_NAME_INVALID,这个是错误的common_name,这个是啥东西,这个就是我们的域名不匹配证书导致的。

不管是上面的哪种错误,如果只是https,那么整个就算是完了,没有任何其他的问题,这种错误可以不用管它,但是如果有wss在的话这种情况就就必须要处理了。

wss

我们先来试试不处理上诉问题时wss会怎样。

首先我们必须明确的是,不管是ws还是wss,我们都得走nginx转。那么我们先来配一下wss的nginx转发的配置(和上面使用的是同一个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,同时协议转换为http,这样服务器端代码就不需要做修改

proxy_pass http://192.168.55.111:8083;

proxy_http_version 1.1;

proxy_set_header Upgrade $http_upgrade;

#由于服务器端源码(建议大家做好大小写匹配)只匹配了"Upgrade"字符串,所以如果这里填"upgrade"服务器端会将这条http请求当成普通的请求,导致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一样的证书,我们在转发的过程中把/mqtt的wss请求转发到mqtt的地址,也就是proxy_pass的值,可以看到协议也是转成http了,8083是192.168.55.111这台机器上mqtt的ws监听端口。贴个图吧。

配置好之后,我们来看看页面链接mqtt的情况。

我们打开控制台,可以咋netwrk下的ws标签下看到ws的请求,在console页可以看大ws证书出现的问题是ERR_CERT_AUTHORITY_INVALID,当然也有可能是和之前https一样的COMMON_NAME_ERR.这个就不演示了。反正这种错误就说明证书是不受信任的。

但是可能我们会想,我们不是已经把证书导入了吗,而且导入的还是受信任的根证书,为什么还会使不受信任呢。其实我们https连接的时候就可以看出来,路径上https是被叉掉了的,这就说证书是不信任的,那是什么情况呢。

chrome解决自签名证书无效

chrome验证证书很严格,必须带有Subject Alternative Name.

签发csr(Certificate Signing Request 证书签名请求文件)时,也就是我们生成证书的时候,我们需要修改openssl的配置。

linux下找一下openssl.cnf文件。cp一份到当前open文件夹下面。

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

第一步,在[ req ]节添加:

req_extetions = v3_req

第二步,添加v3_req节的配置

[ 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

改完之后是这样:

贴下代码:

[ 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,生成的时候会让填一些杂七杂八的信息,都可以乱填,因为我们配置这次我们修改了配置文件,证书信任的域名已经配置了,所以在这步当中让我们填的common_name也可以不用像之前那样填域名,随便填个值都行。

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

生成之后,我们也是需要将证书导入到受信任的证书。我这里就直接使用certmgr.msc来安装了,当然我们这次生成的是crt证书,这个可以直接双击安装。我这里贴一个cermgr.msc的图吧,在“操作->所有任务->导入”可以导入我们的证书。

certmgr

导入证书之后,修改一下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,同时协议转换为http,这样服务器端代码就不需要做修改

proxy_pass http://192.168.55.111:8083;

proxy_http_version 1.1;

proxy_set_header Upgrade $http_upgrade;

#由于服务器端源码(建议大家做好大小写匹配)只匹配了"Upgrade"字符串,所以如果这里填"upgrade"服务器端会将这条http请求当成普通的请求,

导致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也正常链接,没有报错了,测试通过,h5的Notification功能也正常使用。到此为止,ws和http加壳就算完成了。

over~~~

以上是 记一篇http,ws通过nginx加壳打造https和wss 的全部内容, 来源链接: utcz.com/z/512044.html

回到顶部