Nginx部署部分https与部分http

原创 2013年12月15日 16:13:01

    一般而言,大规模的网站都有很多台Web服务器和应用服务器组成,用户的请求可能是经由Varnish,HAProxy,Nginx之后才到应用服务器,中间有好几层。而中小规模的典型部署常见的是 Nginx+Tomcat/jboss 这种两层配置,而Tomcat或jboss 会多于一台,Nginx 作为静态文件处理和负载均衡。下面重点讲解nginx+jboss+ssl实现部分页面https部分页面http

    如果Nginx作为前端代理的话,则Tomcat/jboss不处理自己 https,全交由Nginx处理是可以的。一般情况下nginxTomcat/jboss处于同一个局域网内,安全问题暂时忽略。nginx与jboss之间加密传输在本文最后说明用户首先和Nginx建立连接,完成SSL握手,而后Nginx 作为代理以 http 协议将请求转给 tomcat 处理,Nginx再把 Tomcat/jboss 的输出通过SSL 加密发回给用户,这中间是透明的,Tomcat/jboss只是在处理 http 请求而已。因此,这种情况下不需要配置 Tomcat SSL,只需要配置 Nginx SSL 和 Proxy

    SSL比 http 要消耗更多cpu资源(主要是在建立连接的阶段,之后还要对内容加密),所以对一般网站,只需要对部分地方采用https,大部分开放内容是没必要的,具体取决于你的业务要求。比如对于很多安全要求较低的网站,完全不用https也是可接受的。


某些页面是同时支持 http 和 https ,还是只支持 https、强制 https


同时支持就是用户用什么协议访问都可以,那么用户的请求主要就是由页面本身的链接引导来的,因为一般用户不会自己特意去修改地址栏的。

一般我们的网站可以做成同时支持httphttps,都可以访问。但是这就容易有后面说的混合内容或混合脚本的问题。

还可以规划为部分页面支持 https,一般公开页面不用https,只是将部分地方的链接改为 https 就可以了。专门期望以 https 访问的页面中,引用的绝对URL可以明确的使用 https链接。

是否强制 https ?对于安全性高的网站或网站中的部分页面,可以强制使用https访问, 即使用户在地址栏里手工把 https 改为 http, 也会被自动重定向回 https 上。比如可以通过配置web服务器 rewrite 规则将这些 http url 自动重定向到对应的 https url 上(这样维护比较简单),而不用改应用


解决混合内容问题(httphttps)


混合内容是指:在https的页面中混合了非https的资源请求,比如图片、cssjs 等等。如果是混合了非 https 的 js 代码,则被称为混合脚本。

特别注意:

(1)在http页面混有https内容时,页面排版不会发生乱排现象

(2)在https页面,只有包含以http方式引入的资源(如图片,js等)时,才算作混合内容,如果https页面有超链接(如http:www.baidu.com),但是该超链接并没有引入资源,不算做混合内容,页面显示正常,鼠标放在该超链接时,页脚显示:http://www.baidu.com或者www.baidu.com

混合内容的危害:如果只是混合了不安全的图片和css,那么受中间人攻击篡改,一般只会影响页面的显示,危害相对小一点。如果是混合了不安全的 js 代码,则这个不安全的 js 可以完全访问和修改页面中的任何内容,这是非常危险的。

所以,只有页面本身和所有引用的资源都是 https 的浏览器才认为是安全的,只要其中引用了非安全资源(即使图片),浏览器都会给出不安全的提示,特别是有 js 的情况。如果浏览器提示不安全,那样我们就达不到原来目的了。我们费了半天功夫去申请 SSL 证书,配置Web服务器,最后如果因为混合内容而前功尽弃就太糟了。

理论上,混合了第三方的内容,即使是SSL的第三方内容也不是很好。因为用户信任的是你,而不是第三方,即使第三方也支持https,但你能保证第三方就绝对安全吗。不引用任何第三方才是绝对安全的,但这样太严格了,安全其实也是一个 tradeoff 的问题,需要考虑很多方面的平衡。

Chrome出绝招阻断混合脚本漏洞:http://news.mydrivers.com/1/197/197058.htm

谷歌浏览器混合显示内容会这样指示:

                     

谷歌浏览器混合脚本得以执行时,整个原始页面都会受到影响,原因是浏览器阻止混合内容的加载。如果Chrome的UI显示网站上存在混合内容问题,可以尝试Google的开发工具定位问题。有用的信息通常记录在JavaScript控制台(菜单->工具->JavaScript控制台),只要把提示的非https传送内容改为https传送的就可以了,这个在后面的代码中展示。

在其他主流浏览器(如IE9FF4)需要点击确认对话框来确定是否显示混合内容。


Nginx+jboss+http/https详细配置


1、nginx.conf 中的配置示例

http {

upstream cluster{

                server 172.18.0.33:80 weight=1;

                server 172.18.0.101:8088 weight=5;

        }

upstream clusterssl{

                server 172.18.0.33:8443 weight=1;

                server 172.18.0.101:8443 weight=5;

        }

    server {

        listen       80;

        server_name  www.AAA.com;

        location / {

            proxy_pass http://cluster;

            index  index.htm;

            proxy_set_header Host $host;

            proxy_set_header X-Real-Ip $remote_addr;

            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_connect_timeout 10;

            proxy_read_timeout 120;

        }

        location ~* /*login.htm {

            #rewrite ^(.*) https://$host$1 permanent;

            rewrite ^(.*) https://www.BBB.com$1 permanent;

        }

        location ~ \.(css|js|gif)$ {

            #rewrite ^(.*) https://$host$1 permanent;

            rewrite ^(.*) https://www.BBB.com$1 permanent;

        }

    # HTTPS server

    server {

        listen 443;

        server_name  www.BBB.com;

        ssl                  on;

        ssl_certificate      server.pem;

        ssl_certificate_key  server.key;

        ssl_session_cache    shared:SSL:10m;

        ssl_session_timeout  5m;

        ssl_protocols  SSLv3 TLSv1;

        ssl_ciphers  HIGH:!ADH:!EXPORT56:RC4+RSA:+MEDIUM;

        ssl_prefer_server_ciphers   on;

       

        location / {

            rewrite ^(.*) http://www.AAA.com$1 permanent;

        }

        location ~* /*login.htm {

            proxy_pass http://cluster;

            proxy_redirect off;

            proxy_set_header Host $host;

            proxy_set_header X-Real-Ip $remote_addr;

            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

            proxy_set_header X-Forwarded-Proto $scheme;

        }

        location ~ \.(css|js|gif)$ {

            proxy_pass http://cluster;

            proxy_set_header Host $host;

            proxy_set_header X-Real-Ip $remote_addr;

            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

            proxy_set_header X-Forwarded-Proto $scheme;

        }

         

    }

}

首先,用户访问http://www.AAA.com,进入网站首页,当点击登陆页面http://www.AAA.com/login.htm页面时,由于在80端口进行如下配置:

        location ~* /*login.htm {

            #rewrite ^(.*) https://$host$1 permanent;

            #当AAABBB相同时,可用$host常量

            rewrite ^(.*) https://www.BBB.com$1 permanent;

        }

Url重写之后,到443端口,然后通过443端口的代理配置: 

        proxy_pass http://cluster;

Nginxhttps请求转发给后台的jboss应用服务器。由于https状态会保持,在登陆之后跳转到其它页面时,如果不进行强制使用http,会一直保持https状态,443端口的如下配置:

    location / {

            rewrite ^(.*) http://www.AAA.com$1 permanent;

        }

会使得https状态下的非login.htm链接使用http协议。

在登录页面引入的cssjsgif等资源,由于是后端的jbosshttp状态返回给nginx的,所以login.htm页面会有混合内容,浏览器认为是不安全的,不进行加载,会出现页面排版乱排等现象,谷歌浏览器提示如下:



打开谷歌浏览器:菜单->工具->JavaScript控制台,信息如下



IE9显示如下:




80端口下进行如下配置:

        location ~ \.(css|js|gif)$ {

            #rewrite ^(.*) https://$host$1 permanent;

            rewrite ^(.*) https://www.BBB.com$1 permanent;

        }

443端口进行如下配置:

        location ~ \.(css|js|gif)$ {

            proxy_pass http://cluster;

        }

可以解决页面有混合内容的问题。

现在,另一个问题出现了,如果按照上面进行配置,那么其它非login页面的cssjsgif也都会走https,影响效率,又使得http页面存在https方式引入的内容,解决办法是把登录页面需要的资源放在一个可以区分的路径下面,location匹配的时候,让该路径下的cssjsgif等资源走https,其他路径下面的资源走http


在代理模式下,jboss 如何识别用户的直接请求(URLIPhttps还是http )


在透明代理下,如果不做任何配置jboss认为所有的请求都是 Nginx 发出来的,这样会导致如下的错误结果:

request.getScheme()  //总是 http,而不是实际的httphttps

request.isSecure()  //总是false(因为总是http

request.getRemoteAddr()  //总是 nginx 请求的 IP,而不是用户的IP

request.getRequestURL()  //总是 nginx 请求的URL 而不是用户实际请求的 URL

response.sendRedirect( 相对url )  //总是重定向到 http 上 (因为认为当前是 http 请求)

如果程序中把这些当实际用户请求做处理就有问题了。解决方法很简单,只需要配置一下 Nginx 就好了,而不用改程序。

配置 Nginx 的转发选项:

proxy_set_header       Host $host;

proxy_set_header  X-Real-IP  $remote_addr;

proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_set_header X-Forwarded-Proto  $scheme;


优化


1、优化rewrite语句:

rewrite复杂而且低效,return语句代替,如

    rewrite  (.*)  http://www.example.org$1;

改为

    retrun 301 http://www.example.org$request_uri;


2、优化SSL配置


    SSL操作需要消耗CPU资源,所以在多处理器的系统,需要启动多个工作进程,而且数量需要不少于可用CPU的个数。最消耗CPU资源的SSL操作是SSL握手,有两种方法可以将每个客户端的握手操作数量降到最低:第一种是保持客户端长连接,在一个SSL连接发送多个请求;第二种是在并发的连接或者后续的连接中重用SSL会话参数,这样可以避免SSL握手的操作。会话缓存用于保存SSL会话,这些缓存在工作进程间共享,可以使用ssl_session_cache指令进行配置。1M缓存可以存放大约4000个会话。默认的缓存超时是5分钟,可以使用ssl_session_timeout加大它。下面是一个针对4核系统的配置优化的例子,使用10M的共享会话缓存:

worker_processes  4;

http {

    ssl_session_cache    shared:SSL:10m;

    ssl_session_timeout  10m;

    server {

        listen              443;

        server_name         www.example.com;

        keepalive_timeout   70;

        ssl                 on;

        ssl_certificate     www.example.com.crt;

        ssl_certificate_key www.example.com.key;

        ssl_protocols       SSLv3 TLSv1 TLSv1.1 TLSv1.2;

        ssl_ciphers         HIGH:!aNULL:!MD5;

        ...


证书密钥的保护:


服务器证书是公开的,会被传送到每一个连接到服务器的客户端,而私钥不是公开的,不会被发送,在服务器上要保护好它,比如存放在访问受限的文件中,例如:chmod 400 ssl.key (仅root可读),当然,nginx主进程必须有读取密钥的权限;或者为私钥文件设置密码时,这样私钥虽然很安全,但是每次重启nginx服务都要输入一次密码,比较麻烦


Nginx前端机与后端jboss间部分http部分https通道实现


如果想要在nginxjboss之间也实现加密传输,仅需要做如下关键点的修改:

(1)jboss端配置服务器证书,并开启https端口(下面以8443端口为例)

(2)配置jboss端的部分https部分http

(2)nginx监听443端口的服务修改如下:

        location ~* /*login.htm {

            proxy_pass https://clusterssl;

            proxy_set_header Host $host;

            proxy_set_header X-Real-Ip $remote_addr;

            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

            proxy_set_header X-Forwarded-Proto $scheme;

        }

(3)修改其它混合内容







解决Nginx+Tomcat下客户端https请求跳转成http的问题

Nginx上开启https,  后端使用Tomcat,  两者间走http协议, 但发现如果tomcat应用存在跳转时, 则客户端浏览器会出现400 Bad Request的错误, 通过抓包发现原因是...
  • wooderin
  • wooderin
  • 2014-04-17 18:36:29
  • 6867

nginx反向代理配置

nginx反向代理配置什么是代理代理在普通生活中的意义就是本来应该你做的事情,你让别人代你做了,那么那个帮你做的人就是你的代理。而在计算机网络中代理的概念差不多,就是本来要客户端要做的网络访问,现在移...
  • physicsdandan
  • physicsdandan
  • 2015-05-12 11:36:53
  • 34385

Nginx + Tomcat + HTTPS 配置不需要在 Tomcat 上启用 SSL 支持

最近做了个Web项目, 架构上使用了 Nginx +tomcat 集群, 且全站HTTPS,用nginx 做负载,nginx和tomcat 使用内网http通信,遇到http css,js静态资源被浏...
  • vfush
  • vfush
  • 2016-04-07 15:20:53
  • 17051

在nginx配置部分https

在昨天的文章(配置https实现请求安全 )里,我介绍了nginx配置全站的https访问,这样对所有请求都会加密,会减慢响应速度。 在实际的项目中,我们也没有必要对所有请求加密,比如浏览一个帖子列表...
  • leiswpu
  • leiswpu
  • 2015-09-18 17:50:25
  • 3360

Nginx实现静态资源服务器

我们在上一篇文章中已经分析了实现静态资源服务器的多种思路。本篇文章记录 使用Nginx实现静态资源服务器的步骤。首先需要安装Nginx和了解Nginx的配置文件。CentOS系统可参考如下帖子:Ngi...
  • q383965374
  • q383965374
  • 2017-05-31 21:33:16
  • 11568

nginx静态资源文件无法访问,403 forbidden错误

今天在搭建nginx环境时出现一个奇怪问题,配置的静态资源目录下面文件无法访问,浏览器访问出现403 forbidden,环境是centos7 + nginx 1.6。nginx.conf中http配...
  • ngcsnow
  • ngcsnow
  • 2014-09-19 10:34:30
  • 11445

Nginx(一):静态资源web服务器配置详解

一、Nginx概述 1.Nginx简介          解决基于进程模型产生的C10k问题,请求时即使无状态连接如web服务都无法达到并发响应量级一万现状。2006年俄罗斯编写。全称为engine ...
  • chengwangbaiko
  • chengwangbaiko
  • 2017-06-05 09:51:06
  • 818

Nginx的静态资源缓存以及压缩

Nginx是一款轻量级的网页服务器、反向代理器以及电子邮件代理服务器。Nginx采用的是异步非阻塞的通信机制(epoll模型),支持更大的并发连接.所谓的epoll模型:当事件没有准备好时,就放入ep...
  • JY_He
  • JY_He
  • 2016-08-22 19:18:08
  • 13858

nginx 之 注意事项

1。识别 X-Forwarded- style headers: nginx 设置的X-Forwarded- 格式的header,如 X-Forwarded-Proto,若要让被代理的web服务...
  • zhongzh86
  • zhongzh86
  • 2017-04-14 16:04:36
  • 1114

nginx配置子域名跳转到后端请求

nginx配置子域名跳转到后端请求
  • newtelcom
  • newtelcom
  • 2016-05-19 11:27:29
  • 5875
收藏助手
不良信息举报
您举报文章:Nginx部署部分https与部分http
举报原因:
原因补充:

(最多只允许输入30个字)