發(fā)布于:2021-02-02 14:15:20
0
283
0
根據(jù)FirefoxTelemetry,76%的網(wǎng)頁(yè)加載了HTTPS,而且這個(gè)數(shù)字還在增長(zhǎng)。
軟件工程師遲早要處理HTTPS,而且越早越好。繼續(xù)閱讀,了解為什么以及如何在開(kāi)發(fā)環(huán)境中使用HTTPS為JavaScript應(yīng)用程序提供服務(wù)。
為什么在開(kāi)發(fā)環(huán)境中使用HTTPS?
首先,你應(yīng)該通過(guò)HTTPS服務(wù)于一個(gè)生產(chǎn)中的網(wǎng)站嗎?除非您真的知道自己在做什么,否則默認(rèn)答案是“是”。它在很多方面改善了你的網(wǎng)站:安全性,性能,搜索引擎優(yōu)化,等等。
如何設(shè)置HTTPS通常在第一個(gè)版本中討論,并帶來(lái)許多其他問(wèn)題。通信應(yīng)該從端到端加密,還是加密到反向代理就足夠了?如何生成證書(shū)?它應(yīng)該存放在哪里?那HSTS呢?
開(kāi)發(fā)團(tuán)隊(duì)?wèi)?yīng)該能夠盡早回答這些問(wèn)題。如果沒(méi)有做到這一點(diǎn),您可能會(huì)像堆棧溢出一樣浪費(fèi)大量時(shí)間。
此外,擁有一個(gè)與生產(chǎn)環(huán)境盡可能接近的開(kāi)發(fā)環(huán)境,可以減少bug到達(dá)生產(chǎn)環(huán)境的風(fēng)險(xiǎn),而且還可以減少調(diào)試這些bug的時(shí)間。端到端測(cè)試也是如此。
此外,還有一些功能只能在HTTPS服務(wù)的頁(yè)面上工作,例如服務(wù)工作者。
但是HTTPS很慢!許多人認(rèn)為加密很復(fù)雜,在某種程度上必須很慢才能有效。但隨著現(xiàn)代硬件和協(xié)議的發(fā)展,這不再是事實(shí)。
如何為開(kāi)發(fā)環(huán)境生成有效的證書(shū)?
對(duì)于生產(chǎn)系統(tǒng),很容易獲得TLS證書(shū):從生成一個(gè),讓我們加密或從付費(fèi)提供商購(gòu)買(mǎi)一個(gè)。
對(duì)于開(kāi)發(fā)環(huán)境,這似乎比較棘手,但并不難。
Mkcert: 簡(jiǎn)單的 CLI
菲利波·瓦爾索達(dá)(Filippo Valsorda)最近發(fā)布mkcert了一個(gè)簡(jiǎn)單的CLI,可以生成本地信任的開(kāi)發(fā)證書(shū)。您只需要運(yùn)行一個(gè)單行命令:
mkcert -install
mkcert example.com
完全受支持的證書(shū)將在您運(yùn)行命令的位置提供,即位于./example.com-key.pem。
使用OpenSSL手動(dòng)安裝
mkcert除非您必須與您的同事或通過(guò)本地環(huán)境以外的其他系統(tǒng)共享同一證書(shū),否則您應(yīng)該滿(mǎn)足您的所有需求。在這種情況下,您可以借助生成自己的證書(shū)openssl。
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt
證書(shū)(server.crt)及其密鑰(server.key)將是有效的但具有自簽名。任何證書(shū)頒發(fā)機(jī)構(gòu)都不知道該證書(shū)。但是所有瀏覽器都要求知名的證書(shū)頒發(fā)機(jī)構(gòu)來(lái)驗(yàn)證證書(shū),以接受加密的連接。對(duì)于自簽名證書(shū),他們無(wú)法對(duì)其進(jìn)行驗(yàn)證,因此顯示煩人的警告:
您可以接受這種不便之處,并在每次警告出現(xiàn)時(shí)手動(dòng)忽略它。但這非常麻煩,并且可能會(huì)阻止CI環(huán)境中的e2e測(cè)試。更好的解決方案是創(chuàng)建您自己的本地證書(shū)頒發(fā)機(jī)構(gòu),將此自定義證書(shū)頒發(fā)機(jī)構(gòu)添加到瀏覽器并從中生成證書(shū)。
這就是mkcert您的內(nèi)幕,但是如果您想自己做,我寫(xiě)了一個(gè)要幫助您的要點(diǎn):Kmaschta / 205a67e42421e779edd3530a0efe5945。
來(lái)自反向代理或第三方應(yīng)用程序的HTTPS
通常,最終用戶(hù)不會(huì)直接訪問(wèn)應(yīng)用程序服務(wù)器。而是由負(fù)載平衡器或反向代理處理用戶(hù)請(qǐng)求,該負(fù)載均衡器或反向代理將請(qǐng)求分布在后端,存儲(chǔ)緩存,防止有害請(qǐng)求,等等??吹竭@些代理同時(shí)充當(dāng)解密請(qǐng)求和加密響應(yīng)的角色并不少見(jiàn)。
在開(kāi)發(fā)環(huán)境中,我們也可以使用反向代理!
通過(guò)Traefik和Docker Compose進(jìn)行加密
Traefik是反向代理,對(duì)開(kāi)發(fā)人員來(lái)說(shuō)具有很多優(yōu)勢(shì)。其中,配置簡(jiǎn)單,并且?guī)в蠫UI。另外,在docker hub上有一個(gè)官方的docker鏡像。
因此,讓我們?cè)赿ocker-compose.yml僅提供靜態(tài)文件的假設(shè)應(yīng)用程序內(nèi)部使用它:
version: '3.4'
services:
reverse-proxy:
image: traefik # The official Traefik docker image
command: --docker --api # Enables the web UI and tells Traefik to listen to docker
ports:
- '3000:443' # Proxy entrypoint
- '8000:8080' # Dashboard
volumes:
- /var/run/docker.sock:/var/run/docker.sock # So that Traefik can listen to the Docker events
- ./certs/server.crt:/sslcerts/server.crt
- ./certs/server.key:/sslcerts/server.key
- ./traefik.toml:/traefik.toml # Traefik configuration file (see below)
labels:
- 'traefik.enable=false'
depends_on:
- static-files
static-files:
image: halverneus/static-file-server
volumes:
- ./static:/web
labels:
- 'traefik.enable=true'
- 'traefik.frontend.rule=Host:localhost'
- 'traefik.port=8080'
- 'traefik.protocol=http'
ports:
- 8080:8080
在此示例中,我們的靜態(tài)文件服務(wù)器偵聽(tīng)端口8080并以HTTP提供文件。此配置告訴Traefik處理HTTPS請(qǐng)求https://localhost并代理每個(gè)請(qǐng)求,http://localhost:8080以提供靜態(tài)文件。
我們還必須添加一個(gè)traefik.toml以配置Traefik入口點(diǎn):
debug = false
logLevel = "ERROR"
defaultEntryPoints = ["https","http"]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[[entryPoints.https.tls.certificates]]
certFile = "/sslcerts/server.crt"
keyFile = "/sslcerts/server.key"
在這里,我們有兩個(gè)入口點(diǎn):http和https,分別偵聽(tīng)端口80和443。第一個(gè)重定向到HTTPS,第二個(gè)通過(guò)指定的TLS證書(shū)配置為加密請(qǐng)求。
通過(guò)Nginx從Docker Compose加密
顯然,我們可以使用流行的Nginx反向代理來(lái)做完全相同的事情。由于Nginx本身也可以直接提供靜態(tài)文件,因此設(shè)置更加簡(jiǎn)單。同樣,第一步是docker-compose.yml:
version: '3'
services:
web:
image: nginx:alpine
volumes:
- ./static:/var/www
- ./default.conf:/etc/nginx/conf.d/default.conf
- ../../certs/server.crt:/etc/nginx/conf.d/server.crt
- ../../certs/server.key:/etc/nginx/conf.d/server.key
ports:
- "3000:443"
Nginx配置位于default.conf:
server {
listen 80 default_server;
listen [::]:80 default_server;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name ~.;
ssl_certificate /etc/nginx/conf.d/server.crt;
ssl_certificate_key /etc/nginx/conf.d/server.key;
location / {
root /var/www;
}
## If the static server was another docker service,
## It is possible to forward requests to its port:
# location / {
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_pass http://web:3000/;
# }
}
直接從應(yīng)用程序提供HTTPS服務(wù)
有時(shí),安全性要求需要端到端加密,或者在開(kāi)發(fā)環(huán)境中使用反向代理似乎顯得過(guò)大。大多數(shù)時(shí)候,有可能直接從您的日常開(kāi)發(fā)環(huán)境中提供HTTPS服務(wù)。
讓我們以一個(gè)常見(jiàn)的堆棧為例:一個(gè)帶有Express API的帶有REST API的React應(yīng)用程序。
使用Create React App或Webpack Dev Server
您的平均React應(yīng)用程序由引導(dǎo)create-react-app。這個(gè)很棒的工具帶有許多內(nèi)置功能,可以開(kāi)箱即用地處理HTTPS。為此,您只需要HTTPS=true在啟動(dòng)應(yīng)用程序時(shí)指定一個(gè)環(huán)境變量:
HTTPS=true npm run start
# or
HTTPS=true yarn start
此命令將通過(guò)https://localhost:3000而不是http://localhost:3000自動(dòng)生成的證書(shū)為您的應(yīng)用提供服務(wù)。但這是一個(gè)自簽名證書(shū),因此開(kāi)發(fā)人員體驗(yàn)很差。
如果您想使用自己的HTTPS證書(shū)(使用瀏覽器信任的權(quán)限簽名),create-react-app則在不彈出應(yīng)用程序(npm run eject)的情況下不允許您對(duì)其進(jìn)行配置。
編輯:面向讀者的Zwerge發(fā)現(xiàn)了一個(gè)聰明的解決方法,可以即時(shí)替換默認(rèn)的HTTPS證書(shū):
"scripts": {
"prestart": "(cat ../../certs/server.crt ../../certs/server.key > ./node_modules/webpack-dev-server/ssl/server.pem) || :",
"start": "react-scripts start",
},
幸運(yùn)的是,如果您確實(shí)彈出CRA,或者您的項(xiàng)目與webpack捆綁在一起,webpack-dev-server則就像create-react-app提供HTTPS一樣簡(jiǎn)單!可以在Webpack配置中使用兩行來(lái)配置自定義HTTPS證書(shū):
const fs = require('fs');
const path = require('path');
module.exports = {
mode: 'production',
// ...
devServer: {
https: {
key: fs.readFileSync(path.resolve(__dirname, '../../certs/server.key')),
cert: fs.readFileSync(path.resolve(__dirname, '../../certs/server.crt')),
},
port: 3000,
},
};
下次運(yùn)行時(shí)webpack-dev-server,它將處理對(duì)的HTTPS請(qǐng)求https://localhost:3000。
使用Express和SPDY加密的HTTP / 2
現(xiàn)在我們有了通過(guò)HTTPS服務(wù)的應(yīng)用程序的前端部分,我們必須對(duì)后端進(jìn)行相同的操作。
為此,讓我們使用express和spdy。難怪這兩個(gè)庫(kù)的名稱(chēng)為何與SPEED有關(guān),這是因?yàn)樗鼈冊(cè)O(shè)置起來(lái)很快!
const fs = require('fs');
const path = require('path');
const express = require('express');
const spdy = require('spdy');
const CERTS_ROOT = '../../certs/';
const app = express();
app.use(express.static('static'));
const config = {
cert: fs.readFileSync(path.resolve(CERTS_ROOT, 'server.crt')),
key: fs.readFileSync(path.resolve(CERTS_ROOT, 'server.key')),
};
spdy.createServer(config, app).listen(3000, (err) => {
if (err) {
console.error('An error occured', error);
return;
}
console.log('Server listening on https://localhost:3000.')
});
使用HTTPS不需要HTTP / 2,可以使用名稱(chēng)為HTTP的加密內(nèi)容來(lái)服務(wù),但是當(dāng)我們使用HTTPS時(shí),可以升級(jí)HTTP協(xié)議。如果您想進(jìn)一步了解HTTP / 2的優(yōu)勢(shì),可以閱讀此快速FAQ。
結(jié)論
現(xiàn)代化的工具允許構(gòu)建對(duì)于最終用戶(hù)而言更安全,更快速,并且現(xiàn)在易于引導(dǎo)的應(yīng)用程序。我希望我說(shuō)服您從項(xiàng)目開(kāi)始時(shí)就開(kāi)始使用這些庫(kù)和技術(shù),因?yàn)樗鼈兊陌惭b成本仍然很低。
作者介紹
熱門(mén)博客推薦