SSL证书与Https应用部署小结

为了提升网站的安全性,通常会在比较敏感的部分页面采用https传输,好比注册、登陆、控制台等。像Gmail、网银等所有采用https传输。php

https/ssl 主要起到两个做用:网站认证、内容加密传输和数据一致性。经CA签发的证书才起到认证可信的做用,全部有效证书都可以起到加密传输的做用。
 
 
浏览器与SSL证书
SSL应用部署小结 - hanguokai - 韩国恺的博客
上图是IE和Chrome上对https的不一样表现。
 
SSL最主要应用是在浏览器和Web服务器之间,尽管不限于此。固然,安全自己是重要的内在属性。但在表面上看,部署SSL 就是为了让用户浏览器里看起来更安全一些,以增长用户的信任感。因此不少企业更把它看成门面,而签发机构也为此卖高价,尤为是国内的价格明显高于国外的。
 
实际上SSL证书也能够作客户端认证,用户拥有本身特有的证书,用它能够证实本身的身份,固然也就用不着用户名和密码了。但这种用的不多,通常web服务器也不支持。
 
内容加密传输更安全,若是只是为了加密,使用自签发的证书也能够,但浏览器没法验证证书,因此会给出一个很是吓人的警告,因此自签发证书不适合给外人使用,只适合内部使用,把这个证书 加入到本身的信任列表或忽略证书验证便可,之后就不会继续拦截了。
 
证书须要被少数一级或二级 CA 认证才有效。计算机安全中的信任就是一个信任链的关系,信任链最顶端的被称为根证书。
自签发的证书在技术上是彻底同样的,仅用于加密传输是没问题的。可是不能被外人信任,因此通常仅用于内部使用。除了自签发不被信任,若是证书过时、已被吊销或者非证书所表明的域名也都是不被信任的,致使证书验证出错。
 
用于网站的证书须要被大众信任,因此不能自签发的证书,那就申请(购买)一个吧。

 

申请证书
 
1.证书类别
按证书包含域名数量分为:
  • 单域名:只针对这个域名有效,不能用在其它域名下。
  • 多域名:只针对列出的多个域名有效。
  • 通配符域名(wildcard):对任意子域名有小,显示的是 *.example.com。
注意:SSL所说的单个域名是一个完整的域名,一个子域名就算一个,而非一个顶级域名。
若是网站有不少子域名,只须要申请真正须要的域名证书。
 
按验证的类别分:
  • 域名认证(Domain Validation):认证你的域名全部权和网站,申请验证简单,几分钟便可。
  • 组织机构认证(Organization Validation):认证的域名和公司信息,须要提交公司资料认证。
  • 扩展认证(Extended Validation,简称EV):这种证书会在浏览器中出现“很明显”的绿色地址栏,给用户的可信度最高。有安全评估保证。
我的或小站点可用一类或二类,企业通常用二类认证,少数企业会用到EV认证。
 
2. 证书价格
看了看网上SSL证书的价格,便宜的通常都是10美圆左右一个子域名/每一年,按不一样类别、不一样品牌等价格在几十美圆到几百美圆一年。好比能显示绿色地址栏的EV证书和通配符证书贵一些。国内本身的或代理的,比国外贵很多,动辄几千元。其实就是由可信源认证了一下,相似于办证,用起来没什么差异,并不是越贵越好。
 
3. 签发机构(“卖家”)
 
SSL应用部署小结 - hanguokai - 韩国恺的博客
国外常见的SSL提供商有:Thawte,Go Daddy,VeriSign,RapidSSL,GeoTrust(QuickSSL),StartSSL,Comodo。
StartSSL、Go Daddy的比较便宜,GeoTrust、Comodo的价格适中,Thawte和VeriSign的价格较贵。
 
VeriSign如今归属赛门铁克,在国内是由天威诚信代理的。世界真小,天威诚信就在我不少年之前的东家(启明星辰)大楼里,地下一层是他们的机房,我还进去过一次。
 
4. 免费的StartSSL
惟一免费的是StartSSL,其它的通常只提供30免费试用。
 
但 StartSSL 提供的免费证书是一类的、仅对域名和email进行验证,不对组织作验证(也就是面向天然人的,非面向组织机构的),不过
仅做为域名验证和数据加密也够了,而且浏览器也认它,通常人也不会去看你的证书级别。适合我的和初创网站使用,之后有钱了再申请个收费的替换便可。
 
我很顺利地申请到了免费的StartSSL证书,分别用在两个子域上。
 
最后,证书签发给你后,最主要是保护好私钥证书,这个丢失或泄漏就完了。由于若是被别人利用也就毫无安全性了,须要向证书签发机构申请撤销证书并申请新的证书,这固然也是要收费的。
 
 
应用规划、配置和调整
并非说有了SSL证书就没事了,还要考虑应用中的使用问题,须要规划、服务器配置、应用调整等多个环节。
 
SSL比 http 要消耗更多cpu资源(主要是在创建链接的阶段,以后还要对内容加密),因此对通常网站,只须要对部分地方采用https,大部分开放内容是不必的,具体取决于你的业务要求。好比对于不少安全要求较低的网站,彻底不用https也是可接受的。
 
某些页面是同时支持 http 和 https ,仍是只支持 https、强制 https?
同时支持就是用户用什么协议访问均可以,那么用户的请求主要就是由页面自己的连接引导来的,由于通常用户不会本身特地去修改地址栏的。
通常咱们的网站能够作成同时支持http和https,均可以访问。可是这就容易有后面说的混合内容或混合脚本的问题。
 
还能够规划为部分页面支持 https,通常公开页面不用https,只是将部分地方的连接改成 https 就能够了。专门指望以 https 访问的页面中,引用的绝对URL能够明确的使用 https连接。
 
是否强制 https ?对于安全性高的网站或网站中的部分页面,能够强制使用https访问, 即便用户在地址栏里手工把 https 改成 http, 也会被自动重定向回 https 上。好比能够经过配置web服务器 rewrite 规则将这些 http url 自动重定向到对应的 https url 上(这样维护比较简单),而不用改应用。
 
解决混合内容问题( http和https)
 
混合内容是指:在https的页面中混合了非https的资源请求,好比图片、css、js 等等。若是是混合了非 https 的 js 代码,则被称为混合脚本。
混合内容的危害:若是只是混合了不安全的图片和css,那么受中间人攻击篡改,通常只会影响页面的显示,危害相对小一点。若是是混合了不安全的 js 代码,则这个不安全的 js 能够彻底访问和修改页面中的任何内容,这是很是危险的。
 
另请参看,Chrome对混合脚本危害的说明与提示: Trying to end mixed scripting vulnerabilities
 
因此,只有页面自己和全部引用的资源都是 https 的浏览器才认为是安全的,只要其中引用了非安全资源(即便图片),浏览器都会给出 不安全的提示,特别是有 js 的状况。若是浏览器提示不安全,那样咱们就达不到原来目的了。咱们费了半天功夫去申请 SSL 证书,配置Web服务器,最后若是由于混合内容而前功尽弃就太糟了。咱继续努力吧,想办法让全部引用资源都是安全的。
 
理论上,混合了第三方的内容,即便是SSL的第三方内容也不是很好。由于用户信任的是你,而不是第三方,即便第三方也支持https,但你能保证第三方就绝对安全吗。不引用任何第三方才是绝对安全的,但这样太严格了,安全其实也是一个 tradeoff 的问题,须要考虑不少方面的平衡。还好,起码如今浏览器认为已是安全的了。
 
引用第三方文件的问题(如 CDN 分发的文件)
 
简单地说,这个问题要么有第三方提供 https 支持,要么不用它(用本身本地的)。
 
通常咱们会引用由 CDN 分发的文件,好比某个 js 库文件,而不用访问本身网站上的,这样借助 CDN 网络能够加快速度,这固然很好。
可是,若是咱们在页面中使用绝对 URL 直接引用这个文件就没法自动使用 https 了!出现了混合协议内容,浏览器又该“变脸”了。
 
当SSL 赶上CDN 或 其它第三方文件就有点麻烦,由于不少CDN还不支持SSL。若是支持 https 的话就能够直接用 https 的绝对URL了,即便是同时支持http 和 https 的页面,这样作也不算太浪费,起码解决了问题。
 
由于CDN的云文件提供者,通常为每一个cdn用户建立一个单独的子域名来使用,这样的话,CDN提供者要想支持 https 就必须支持全部可能的子域名,所以要求CDN提供方使用那种通配符子域名的证书。
 
相对 URL、绝对 URL 与 只缺协议的URL( Protocol Relative URL )
相对路径比较简单,自动匹配用户请求的 http 或 https 协议。
 
可是绝对 url 则不成,由于绝对 url 已经明确地写上了协议: http://www.example.com/jquery.js 。
这个问题还有一个办法解决,你必定没见过这种形式:  //www.example.com/jquery.js
哈哈,一个缺乏协议的URL(实际上还算是相对URL),这种形式能够在浏览器中被正确补充上合适的协议!不少人都用这种方法。
可是,这里有点小问题,IE7 和 IE8 处理这种缺乏协议的URL的css 文件时,同一个css文件会下载两次,详见 Steve的文章 。
 
JS 自动判断当前协议
如今咱们常常用 js 来加载其它 js 文件或 其它别的文件,若是是请求是相对URL则没问题,若是是绝对URL怎么办?
其实 js 脚本能够这样: document.location.protocol 等于 'http:' 仍是 'https:' 来判断。例如在 Google Analytics 的嵌入代码中:
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
 
应用程序中如何判断访问协议
对于动态页面,如 jsp、php等,也是能够动态判断当前是否使用了 https 协议的。因此应用能够根据动态判断,来生成不一样的引用 URL。这样虽然有点麻烦,但也算是解决了自动识别协议的问题,固然相对路径老是不须要处理的。
好比在 jsp 中:
  • request.isSecure() 为true 表示当前为 https ,false表示 http 访问
  • request.getScheme() 返回字符串 https 或 http
注意,若是 tomcat 部署在其它web服务器代理的后面,须要正确配置好才能返回正确结果,见本文最后一部分。
 
同源策略的问题
最后提醒一点:http 和 https是不一样源的!即便后面的内容都同样。因此 ajax 发请求的时候要使用正确协议的绝对URL才行。
相对URL的 ajax 请求不要紧。
 
 
Nginx 配置
小结一下 Nginx 配置SSL注意的问题,详细安装配置内容请参考其它资料,如官方  SSL模块 和  https配置文档
1. 首先检查一下是否已安装了 SSL模块,由于默认是不包含的。
 
用 nginx -V 命令检查一下。若是没有ssl模块则须要从新安装(建议升级到最新版本),注意安装时加上ssl 选项:
./configure --with-http_ssl_module
 
另外,nginx须要依赖 openssl 提供ssl支持,这个也要有。
 
2. nginx.conf 中的典型配置示例
listen     80;
listen    443 ssl;
ssl_certificate      cert.pem; #修改具体文件
ssl_certificate_key  ssl.key; #修改具体文件
 
ssl_session_cache    shared:SSL:10m;
ssl_session_timeout  10m;
 
ssl_protocols  SSLv2 SSLv3 TLSv1;
ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers   on;
 
上面第2-4项是关键。这些配置放在 server 块就能够对其中的全部 location 生效了,而且同时支持 http 和 https 。或者把 http 和 https 分开配置也很常见。
 
3. 合并证书配置文件
和Apache配置不一样,Nginx须要将服务器证书和ca证书链合并到一个文件中,做为 ssl_certificate 配置的内容。
例如,按照证书链从下向上的顺序,我有三个证书:
  1. ssl.crt(本身域名的服务器证书)
  2. sub.class1.server.ca.pem(startssl 的一类证书)
  3. ca.pem(startssl 的根证书)
把它们的内容按顺序链接到的一个文件中,每一个内容另起一行,中间没有空行或空格。
 
4. 避免启动时输入密码
配好以后,启动nginx 要你输入密钥的密码。这是由于 ssl_certificate_key 配置对应的文件(也就是 startssl 给你的私钥文件)内容是加密的,须要输入你建立这个时设置的密码才能解密。这样私钥虽然很安全,可是每次重启服务都要输入一次密码也太麻烦了。其实,只要证书改成解密了的内容,就能够避免每次输入密码。用以下命令便可:
openssl rsa -in ssl.key -out newssl.key  输入密码,就生成了解密后的私钥内容,使用这个就OK了。
 
可是就像前面说的,必定要在服务器上保护好它,例如:
chmod 400 ssl.key (仅root可读)
 
5. 优化SSL配置
SSL 很消耗 CPU 资源,尤为是在创建链接的握手阶段。一是经过开启 keepalive 能够重用链接。二是能够重用和共享ssl session,见上面ssl_session相关配置。
 
 
 
独立Tomcat+SSL
Tomcat 是很常见的 Java应用服务器,固然也能够做为独立的 Web服务器,全部用户请求直接访问 tomcat。
 
若是 Tomcat 做为独立的Web服务器,那么就须要配置Tomcat就能够了,文档参考 这里 和  这个。主要是配置存放证书的 Keystore 和 链接器Connector。
 
Java的keystore
keystore 是 Java 中专用并内置的一个相似于 openssl 的工具,一个 keystore 文件就是一个“保险箱”(database),专门存放证书和密钥,和相关的管理功能:生成自签发的证书、密钥、导入导出等。能够经过 keytool 命令或 Java api 交互。
利用keytool 命令将你的证书导入进去。
 
Tomcat中Connector
tomcat中有三种 Connector 实现:block、nio 和 APR。前二者使用Java SSL(这须要 keystore 的配置 ),APR使用OpenSSL(不须要用keystore,直接指定证书),配置略有不一样。
 
 
 
Nginx+Tomcat+SSL
实际上,大规模的网站都有不少台Web服务器和应用服务器组成,用户的请求多是经由 Varnish、HAProxy、Nginx以后才到应用服务器,中间有好几层。而中小规模的典型部署常见的是 Nginx+Tomcat 这种两层配置,而Tomcat 会多于一台,Nginx 做为静态文件处理和负载均衡。
 
若是Nginx做为前端代理的话,则Tomcat根本不须要本身处理 https,全是Nginx处理的。用户首先和Nginx创建链接,完成SSL握手,然后Nginx 做为代理以 http 协议将请求转给 tomcat 处理,Nginx再把 tomcat 的输出经过SSL 加密发回给用户,这中间是透明的,Tomcat只是在处理 http 请求而已。所以,这种状况下不须要配置 Tomcat 的SSL,只须要配置 Nginx 的SSL 和 Proxy。
 
在代理模式下,Tomcat 如何识别用户的直接请求(URL、IP、https仍是http )?
在透明代理下,若是不作任何配置Tomcat 认为全部的请求都是 Nginx 发出来的,这样会致使以下的错误结果:
  • request.getScheme()  //老是 http,而不是实际的http或https
  • request.isSecure()  //老是false(由于老是http)
  • request.getRemoteAddr()  //老是 nginx 请求的 IP,而不是用户的IP
  • request.getRequestURL()  //老是 nginx 请求的URL 而不是用户实际请求的 URL
  • response.sendRedirect( 相对url )  //老是重定向到 http 上 (由于认为当前是 http 请求)
 
若是程序中把这些当实际用户请求作处理就有问题了。解决方法很简单,只须要分别配置一下 Nginx 和 Tomcat 就行了,而不用改程序。
配置 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;
 
配置Tomcat server.xml 的 Engine 模块下配置一个 Value:
<Valve className="org.apache.catalina.valves.RemoteIpValve" remoteIpHeader="X-Forwarded-For" protocolHeader="X-Forwarded-Proto" protocolHeaderHttpsValue="https"/>
 
配置双方的 X-Forwarded-Proto 就是为了正确地识别实际用户发出的协议是 http 仍是 https。X-Forwarded-For 是为了得到实际用户的 IP。
这样以上5项测试就都变为正确的结果了,就像用户在直接访问 Tomcat 同样。
 
http://han.guokai.blog.163.com/blog/static/136718271201211631456811/
相关文章
相关标签/搜索