在信息安全形势愈发严峻的当下,通过传统的超文本传输协议(HTTP)传输的数据在代理提供者或发动攻击的不法分子眼中如同裸奔。因此,使用合适的措施加密用户与服务器之间的通信是十分之重要的。本文介绍通过 Nginx 快速的将传统超文本传输协议升级为超文本传输安全(HTTPS)协议的方法和要点。
目录
一、概述
在本文开头,我们提到,通过 HTTP 传输的数据十分的不安全,在一般数据的传输中,这尚无大碍,但在涉及到用户的重要数据(如账号密码或隐私数据)时,这是十分危险的,所以我们需要通过对连接进行加密来保障信息在传输过程中的安全。
那么,什么是 HTTP,HTTPS 又是什么,为什么 HTTP 不安全?
1.HTTP(S) 是什么?
关于这一部分的内容,尽管我很想用我自己的话来展开讲以求能让你更好地理解它们,但菜鸟教程已有对这些问题的讲解,且大多足够详细易懂,所以如果你感兴趣,请参阅以下链接:
https://www.runoob.com/http/http-intro.html
https://www.runoob.com/w3cnote/http-vs-https.html
2.为什么 HTTP 不安全?
首先,这是一般情况下正常的 HTTP 通讯简图:

但是,如果你的域名服务器(DNS)不可信或被污染又或是其他情况例如代理提供商篡改了返回并抢先一步将篡改的返回包送达用户等实际上让访问得到的内容不是或不完全是域名所有者期望用户看到的内容的情况,我们将其称为劫持。
其中,由于域名服务器出现问题造成用户实际访问的服务器不是域名所有者所期望用户访问的服务器的情况,称作 DNS 劫持。
在信息传输过程中信息被篡改,导致用户或服务器得到的信息不是所期望的或符合设定的情况,称作 HTTP 劫持。
对于 DNS 劫持,HTTPS 并不能很好地防范,而是应该通过 DNSSEC 进行防范。
对于 HTTP 劫持,HTTPS 可以有效地解决这个问题。
这到底有多么重要呢?举个例子。你正在使用的网上银行网站使用 HTTP 而不是安全的 HTTPS,这个时候隔壁的张三恰巧知道你使用的网上银行网站不安全,便动起了歪心思,打开光纤箱把你家的光纤拉到了他的特制设备上,再由特制设备接着走正常的传输过程。这时你打开网上银行,张三马上收到了消息,当你在转账时,张三把对方的账号篡改为了自己的账号,并把转账金额篡改为余额,得手后立刻逃到了致远星。现在你只能看着余额页面大大的 0 抱头痛哭了。

张三甚至还可以做得更隐蔽些:因为 HTTP 通过明文传输数据,所以可以通过监听知道你的密码,等你睡着了张三再与银行通讯刷走你的钱然后跑路。
事实上,类似这样的劫持可以在信息传输的任意阶段发生,在信息送达之前,你的信息只有天知道安不安全。
当然,不用担心这个例子真的在现实中发生,因为网银在传输这些信息时是 100% 使用 HTTPS 的,而且银行也采用了很多其他手段保护你的交易。但是这足以说明 HTTP 的不安全。
好了,我们进入正题。接下来我们讲解反向代理。
二、反向代理的基本概念
在讲解反向代理前,我们应该讲解一下代理是什么。
1.代理是什么?
代理服务器,顾名思义,就是专门用来“代理”的服务器,那么它“代理”什么呢?自然是网络请求。
代理服务器的工作流程大致是:你的电脑告诉代理你要访问什么,代理替你访问,然后代理告诉你访问的结果。
这有什么作用呢?作用有很多,举一个重要用途的例子:你无法访问一个网站,但你可以访问代理服务器,而且代理服务器可以访问这个网站,此时你可以通过代理服务器访问这个网站。
2.反向代理是什么?
那么,反向代理又是什么呢?
通过上面的讲解,我们知道,代理是你,也就是用户访问目标用的,而反向代理,自然便是反过来,是访问目标所使用的代理。
一般的代理服务器是这样的:

而反向代理是这样的:

对于用户来说,反向代理服务器就是用户的目标,但反向代理服务器本身并不会处理用户的具体请求,只是将请求转给真正的目标。
那么,这又有什么用呢?作用同样有很多,比如本文的主题:加密传输。还有负载均衡,加响应头……等等功能。
接下来说明一下反向代理如何加密我们的连接。
3.反向代理如何加密我们的连接?
如下图:

你可能要问了:这不还是用了 HTTP 协议传输信息嘛!怎么就安全了呢?
此言差矣!前面我们提到:
劫持可以在信息传输的任意阶段发生
而通过反向代理,我们把可能可以有效劫持的区域缩小到了一个机房,甚至是一台机器内部。显然的,你要是连机房都看不好你搞个屁安全?人都进到你机房了还用劫持?所以这样便有效地保证了信息在传输过程中的安全。
现在我们知道了反向代理是什么,它如何保障我们的信息安全。接下来我们来实践一下,搭建一个反向代理来加密连接。
三、Nginx 的配置
要使用反向代理来加密连接,我们显然需要先搭建反向代理服务器。反向代理服务器有很多,本文主要说明 Nginx 的使用。
1.搭建 Nginx 环境
笔者在 Windows 环境下编写本文,如果你使用其它系统,推荐你自行搜索这部分的内容,网络上已经有很多足够简明的教程且你使用的系统并不影响接下来介绍的大多数操作。
首先,访问 Nginx 官网的 下载页面:
下载 Stable version 下的版本。

下载完成后,解压压缩包至一个合适的目录,你将得到这样的目录结构:
注:已删去版本号
nginx
├─ conf
│ ├─ fastcgi.conf
│ ├─ fastcgi_params
│ ├─ koi-utf
│ ├─ koi-win
│ ├─ mime.types
│ ├─ nginx.conf
│ ├─ scgi_params
│ ├─ uwsgi_params
│ └─ win-utf
├─ contrib
│ ├─ README
│ ├─ geo2nginx.pl
│ ├─ unicode2nginx
│ │ ├─ koi-utf
│ │ ├─ unicode-to-nginx.pl
│ │ └─ win-utf
│ └─ vim
│ ├─ ftdetect
│ ├─ ftplugin
│ ├─ indent
│ └─ syntax
├─ docs
│ ├─ CHANGES
│ ├─ CHANGES.ru
│ ├─ LICENSE
│ ├─ OpenSSL.LICENSE
│ ├─ PCRE.LICENCE
│ ├─ README
│ └─ zlib.LICENSE
├─ html
│ ├─ 50x.html
│ └─ index.html
├─ logs
├─ nginx.exe
└─ temp
略去我们不会用到的部分,简化的目录结构如下:
nginx
├─ conf
│ └─ nginx.conf
└─ nginx.exe
不在简化的目录结构中的文件,你不用理会,也最好别动。
记住你解压 Nginx 的目录,现在你就搭建好了 Nginx 环境。没错!就是这么简单,开箱即用!
2.配置 Nginx
现在,我们打开 conf\nginx.conf,你会看到以下内容:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
复制下面这个推荐配置,替换掉里面的内容:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
sendfile on;
keepalive_timeout 65;
gzip on;
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
现在,我们完成了 Nginx 的配置,是时候开始加密我们的连接了。
四、SSL 证书的获取
HTTPS 依赖 SSL 证书进行加密。所以,在配置加密之前,我们必须先获得一个有效的 SSL 证书。
1.由 CA 签发的证书
想要获得可信的 SSL 证书,通常需要你向 CA 申请。但这并不是免费的,一张 SSL 证书从几百元到上千元不等,而且还是有有效期的。
毫无疑问的,这对于一般的个人来说成本太高了,但是我们同样还有许多免费 SSL 证书可以选择,它们同样可信,不过有一些缺点:
- 通常无法获得免费的泛域名证书。
- 常见地免费证书的有效期通常只有一年。这意味着你每年都得更换证书,一旦你忘记,证书过期后你的站点就会被提示不安全,尽管此时信息的传输仍被保护,但可能无法验证服务器的身份。
泛域名是什么?e.g.,*.example.com
这意味着你必须给每个需要使用 HTTPS 的子域申请签发证书。当然,一般情况下,这并不是非常麻烦。
当然,这些缺点几乎算不上缺点,比起几百上千的付费证书,这算缺点吗?要啥自行车!
现在我们以 TrustAsia 为例,演示如何申请签发一张 CA 证书。
考虑到安全性,笔者推荐你通过腾讯云申请 TrustAsia 免费证书。当然,如果你没有且不想注册腾讯云,你也可以选择 FreeSSL.cn。但请注意,笔者并不熟悉也并不推荐使用本网站签发证书。
接下来我们假设你已经登陆好了腾讯云切到了控制台打开了 SSL 证书的管理页面(当然如果你没有可以 点此跳转),你将看到以下界面:

切换至图中框住的 我的证书 选项卡,你将看到以下界面:

单击图中框住的 申请免费证书 按钮,在弹出的 确认证书类型 窗口中选择 免费版 并点击确定。然后你将看到以下界面:

建议你除了改动绑定的域名和申请邮箱外按图中配置填写。填写完成后,点击 提交申请,进行域名验证 来进行下一步。

接着,我们需要前往 DNS 服务提供商处添加一条 CA 指定的 DNS 记录,记录内容可以从域名验证页面获取。
添加完成后,等待 CA 验证并等着腾讯云给你发邮件即可。
当腾讯云通知你审核通过时,回到 我的证书 页面,就可以看到申请的 SSL 证书了。

单击图中框出的 下载,在弹出的页面中下载 Nginx 版本的证书。
记住,保管好你下载的证书文件,千万不要让私钥(e.g. example.com.key)泄露,否则你就只能吊销这个证书了。
现在你就获得了一个由 CA 签发的 SSL 证书。
2.自签名的 SSL 证书
你还可以自己充当 CA,自己给自己签发 SSL 证书。这虽然可以加密传输的信息,但却不能完全阻止中间人攻击。
为什么呢?因为你的用户不知道你是不是你。自签名的 SSL 证书很难对服务器的身份进行验证,也就是说可能出现这样的情况:

换句话说,你能签发证书那不法分子一样能签发证书,用户怎么知道证书是不是你签发的?
但如果你使用的是 CA 签名的证书,就可能出现这样的情况:

CA 签发的证书因为存在证书链,而可信 CA 的根证书预装在了每台设备中,即意味着这个证书的签发被 CA 认可,而 CA 认可身份并签发证书需要严格的审核,这就保障了这个证书就是你本人申请的证书,而使用者默认是你本人。这也是为什么你必须保管好你的私钥,私钥一旦泄露,CA 签发的证书也就失去了验证“你是你”的作用。
所以笔者不推荐使用自签名证书,如果你想了解相关信息,可以使用搜索引擎查询。
五、使用 SSL 证书对连接进行加密
不管通过哪种方式取得了 SSL 证书,拿了证书总是要用的,接下来我们来使用它。
假设你从腾讯云申请证书,证书已经解压到 conf\ssl。
让我们回到刚刚推荐的配置文件中,不知道你是否注意到了这个部分:
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
没错,这部分就是至关重要的加密部分!
假设我的域名是 example.com,将上面的部分修改为下面的样子:
server {
listen 443 ssl;
server_name localhost;
ssl_certificate example.com_bundle.pem;
ssl_certificate_key example.com.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://127.0.0.1:80;
proxy_set_header Host $proxy_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
其中,location 里面的 80 端口可以改为你服务的端口,如果它不在 80 的话。同样的,你可以把开头 listen 中的 443 改为其他端口。
不过要注意,有些时候你可能需要在 location 中加上一行:
add_header Content-Security-Policy upgrade-insecure-requests;
它的作用是将网页中所有的 HTTP 内容自动升级为 HTTPS 内容,这么做的原因是在 HTTPS 连接中不允许再通过 HTTP 传输数据。
一定要记得对齐缩进!
现在,打开 nginx.exe,启动 Nginx。
现在你就成功的使用 Nginx 反向代理加密了你的连接。
Enjoy!








Comments | NOTHING