Nginx 配置 SSL 证书支持 Https

确保机器上安装了 openssl 和 openssl-devel

yum install openssl
yum install openssl-devel

注意:如果 Nginx 以后要开启 HTTP2,那么 OpenSSL 库必须是 1.0.2 以上,CentOS 通过 yum 安装的版本太旧,只有 1.0.1e。我们需要去官网下载最新版,并且在重新编译升级 Nginx 时指定 OpenSSL 的源码目录(--with-openssl='path/to/openssl')。如果不带这个参数,Nginx 只会去读系统自带的 OpenSSL 库。

所以也可以用更彻底的方法:升级系统全局 OpenSSL 版本,那么 Nginx 时就不用指定 OpenSSL 源码目录了。

确保 Nginx 支持 SSL 模块,编译时带 --with-http_ssl_module 参数(可通过 nginx -V 查看 configure 时的参数),否则会报错

[emerg] 10464#0: unknown directive "ssl" in /usr/local/nginx/conf/nginx.conf:74”

创建服务端私钥(第三方 SSL 证书签发机构都要求起码 2048 位的 RSA 加密的私钥)

cd /usr/local/nginx/
mkdir ssl && cd ssl
openssl genrsa -des3 -out hicrew.key 2048

创建证书请求文件(CSR = SSL Certificate Signing Request)

openssl req -new -nodes -sha256 -key hicrew.key -out hicrew.csr

依次输入密码、国家代码、省份城市、邮箱等信息即可。

Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Shanghai
Locality Name (eg, city) [Default City]:Shanghai
Organization Name (eg, company) [Default Company Ltd]:Morecruit
Organizational Unit Name (eg, section) []:RD
Common Name (eg, your name or your server's hostname) []:api.hicrew.cn
Email Address []:support@morecruit.cn

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:hicrew
An optional company name []:qa.api.hicrew.cn

特别注意

Common Name 和 An optional company name 是证书的生效域名。 如果只是同一个站点下面分出很多个子域名,那么可以直接申请通配证书,将证书的 Common Name 填写为 *.hicrew.cn,但 这种写法只能匹配二级域名,根域名 hicrew.cn 和三级域名 qa.api.hicrew.cn 都无法匹配,所以如果有更多的域名,可以填入“使用者可选名称”。参考《SSL多域名绑定证书的解决方案》

去除私钥里的密码信息(否则以SSL启动Nginx时会提示必须输入密钥)

openssl rsa -in hicrew.key -out hicrew_nopwd.key

使用刚生成的私钥和CSR进行证书签名(10年有效期)

或者到 StartSSL 上传 CSR 后获得经 CA 机构签名后的证书,如:1_study.hicrew.cn_bundle.crt

openssl x509 -req -days 3650 -sha256 -in hicrew.csr -signkey hicrew_nopwd.key -out hicrew.crt

如果需要用 pfx 可以用以下命令生成

openssl pkcs12 -export -inkey hicrew.key -in hicrew.crt -out hicrew.pfx

修改 Nginx 配置文件,让其包含新标记的证书和私钥:

server
{
    listen 443;
    server_name api.hicrew.cn;

    ssl on;
    ssl_certificate /usr/local/nginx/ssl/hicrew.crt;
    ssl_certificate_key /usr/local/nginx/ssl/hicrew_nopwd.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers AESGCM:ALL:!DH:!EXPORT:!RC4:+HIGH:!MEDIUM:!LOW:!aNULL:!eNULL;
    ssl_prefer_server_ciphers on;

    # HSTS (HTTP Strict Transport Security, ngx_http_headers_module is required)
    # 让浏览器访问 HTTP 时强制 307 内部跳转到 HTTPS
    add_header Strict-Transport-Security max-age=15768000;
}

全部 CipherSuite 可以在 IANA 的 TLS Cipher Suite Registry 页面查看。

协商算法配置务必参考权威 Mozilla 的推荐配置 或者 CloudFlare 使用的配置

另外还可以实现访问 80 端口直接重定向到 443(其实 HSTS 307 Internal Redirect 已经可以实现这个效果)但为了双保险,再加一个 vhost 做 302 重定向:

server
{
    listen 80;
    server_name api.hicrew.cn;
    rewrite ^(.*) https://$server_name$1 permanent;
}

重启 nginx 就可以通过以下方式访问了

https://api.hicrew.cn

Chrome 浏览器可以安装 HTTP/2 and SPDY indicator 插件看到『蓝色闪电』表示本站启用了 HTTP2。

或者在线测试:https://tools.keycdn.com/http2-test

FAQ

问:如何让浏览器信任自己办法的证书,以IE为例:

答:

IE:控制面板 -> Internet选项 -> 内容 -> 发行者 -> `受信任的根证书颁发机构` -> 导入 -> 选择 hicrew.crt
Chrome:设置 -> 显示高级设置 -> HTTPS/SSL 管理证书 -> `受信任的根证书颁发机构` -> 导入 -> 选择 hicrew.crt

问:什么是针对企业的 EV SSL

答:EV SSL,是 Extended Validation 的简称,更注重于对企业网站的安全保护以及严格的认证。最明显的区别就是,通常 EV SSL 显示都是绿色的条

参考文章:

数字签名是什么?(HTTPS 原理)

转帖自:阮一峰:http://www.ruanyifeng.com/blog/2011/08/what_is_a_digital_signature.html

原文链接:David Youd:http://www.youdzone.com/signature.html

今天,我读到一篇好文章。它用图片通俗易懂地解释了,”数字签名”(digital signature)和”数字证书”(digital certificate)到底是什么。

我对这些问题的理解,一直是模模糊糊的,很多细节搞不清楚。读完这篇文章后,发现思路一下子就理清了。为了加深记忆,我把文字和图片都翻译出来了。

==============================

1.鲍勃有两把钥匙,一把是公钥,另一把是私钥。

2.鲍勃把公钥送给他的朋友们—-帕蒂、道格、苏珊—-每人一把。

3.苏珊要给鲍勃写一封保密的信。她写完后用鲍勃的公钥加密,就可以达到保密的效果。

4.鲍勃收信后,用私钥解密,就看到了信件内容。这里要强调的是,只要鲍勃的私钥不泄露,这封信就是安全的,即使落在别人手里,也无法解密。

5.鲍勃给苏珊回信,决定采用”数字签名”。他写完后先用Hash函数,生成信件的摘要(digest)。

6.然后,鲍勃使用私钥,对这个摘要加密,生成”数字签名”(signature)。

7.鲍勃将这个签名,附在信件下面,一起发给苏珊。

8.苏珊收信后,取下数字签名,用鲍勃的公钥解密,得到信件的摘要。由此证明,这封信确实是鲍勃发出的。

9.苏珊再对信件本身使用Hash函数,将得到的结果,与上一步得到的摘要进行对比。如果两者一致,就证明这封信未被修改过。

10.复杂的情况出现了。道格想欺骗苏珊,他偷偷使用了苏珊的电脑,用自己的公钥换走了鲍勃的公钥。此时,苏珊实际拥有的是道格的公钥,但是还以为这是鲍勃的公钥。因此,道格就可以冒充鲍勃,用自己的私钥做成”数字签名”,写信给苏珊,让苏珊用假的鲍勃公钥进行解密。

11.后来,苏珊感觉不对劲,发现自己无法确定公钥是否真的属于鲍勃。她想到了一个办法,要求鲍勃去找”证书中心”(certificate authority,简称CA),为公钥做认证。证书中心用自己的私钥,对鲍勃的公钥和一些相关信息一起加密,生成”数字证书”(Digital Certificate)。

12.鲍勃拿到数字证书以后,就可以放心了。以后再给苏珊写信,只要在签名的同时,再附上数字证书就行了。

13.苏珊收信后,用CA的公钥解开数字证书,就可以拿到鲍勃真实的公钥了,然后就能证明”数字签名”是否真的是鲍勃签的。

14.下面,我们看一个应用”数字证书”的实例:HTTPS 协议。这个协议主要用于网页加密。

15.首先,客户端向服务器发出加密请求。

16.服务器用自己的私钥加密网页以后,连同本身的数字证书,一起发送给客户端。证书包含以下信息:

  • 服务器公钥
  • 申请者的组织信息和个人信息
  • 签发机构 CA 的信息
  • 有效时间、证书序列号等信息的明文
  • 发行者的数字签名:使用散列函数计算公开的明文信息的信息摘要,然后采用 CA 的私钥对信息摘要进行加密,密文即签名

17.客户端(浏览器)的”证书管理器”,有”受信任的根证书颁发机构”列表。客户端会根据这张列表,查看解开数字证书的公钥是否在列表之内。同时验证证书合法性:

  • 证书是否过期
  • 签发机构 CA 是否可靠
  • 签发机构 CA 的公钥能否正确解开服务器证书的“发行者的数字签名”
  • 证书上的域名和服务器的实际域名是否一致

18.如果数字证书记载的网址,与你正在浏览的网址不一致,就说明这张证书可能被冒用,浏览器会发出警告。

19.如果这张数字证书不是由受信任的机构颁发的,浏览器会发出另一种警告。

20.如果数字证书是可靠的,客户端就可以使用证书中的服务器公钥,对信息进行加密,然后与服务器交换加密信息。

了解Javascript模块化开发

转贴自:https://www.markdream.com/technologies/programs/understanding-of-javascript-module-development.shtml

小A是某个创业团队的前端工程师,负责编写项目的Javascript程序。

全局变量冲突

根据自己的经验,小A先把一些常用的功能抽出来,写成函数放到一个公用文件base.js中:

var _ = {
    $: function(id) { return document.getElementById(id); },
    getCookie: function(key) { ... },
    setCookie: function(key, value) { ... }
};

小A把这些函数都放在_对象内,以防过多的全局变量造成冲突。他告诉团队的其他成员,如果谁想使用这些函数,只要引入base.js就可以了。

小C是小A的同事,他向小A反映:自己的页面引入了一个叫做underscore.js的类库,而且,这个类库也会占用_这个全局变量,这样一来就会跟base.js中的_冲突了。小A心想,underscore.js是第三方类库,估计不好改,但是base.js已经在很多页面铺开,不可能改。最后小A只好无奈地把underscore.js占用的全局变量改了。

此时,小A发现,把函数都放在一个名字空间内,可以减少全局变量冲突的概率,却没有解决全局变量冲突这个问题。

依赖

随着业务的发展,小A又编写了一系列的函数库和UI组件,比方说标签切换组件tabs.js,此组件需调用base.js以及util.js中的函数。

有一天,新同事小D跟小A反映,自己已经在页面中引用了tabs.js,功能却不正常。小A一看就发现问题了,原来小D不知道tabs.js依赖于base.js以及util.js,他并没有添加这两个文件的引用。于是,他马上进行修改:

<script src="tabs.js"></script>
<script src="base.js"></script>
<script src="util.js"></script>

然而,功能还是不正常,此时小A教训小D说:“都说是依赖,那被依赖方肯定要放在依赖方之前啊”。原来小D把base.js和util.js放到tabs.js之后了。

小A心想,他是作者,自然知道组件的依赖情况,但是别人就难说了,特别是新人。

过了一段时间,小A给标签切换组件增加了功能,为了实现这个功能,tabs.js还需要调用ui.js中的函数。这时,小A发现了一个严重的问题,他需要在所有调用了tabs.js的页面上增加ui.js的引用!!!

又过了一段时间,小A优化了tabs.js,这个组件已经不再依赖于util.js,所以他在所有用到tabs.js的页面中移除了util.js的引用,以提高性能。他这一修改,出大事了,测试组MM告诉他,有些页面不正常了。小A一看,恍然大悟,原来某些页面的其他功能用到了util.js中的函数,他把这个文件的引用去掉导致出错了。为了保证功能正常,他又把代码恢复了。

小A又想,有没有办法在修改依赖的同时不用逐一修改页面,也不影响其他功能呢?

模块化

小A逛互联网的时候,无意中发现了一种新奇的模块化编码方式,可以把它之前遇到的问题全部解决。

在模块化编程方式下,每个文件都是一个模块。每个模块都由一个名为define的函数创建。例如,把base.js改造成一个模块后,代码会变成这样:

define(function(require, exports, module) {
    exports.$ = function(id) { return document.getElementById(id); };
    exports.getCookie = function(key) { ... };
    exports.setCookie = function(key, value) { ... };
});

base.js向外提供的接口都被添加到exports这个对象。而exports是一个局部变量,整个模块的代码都没有占用半个全局变量。

那如何调用某个模块提供的接口呢?以tabs.js为例,它要依赖于base.js和util.js:

define(function(require, exports, module) {
    var _ = require('base.js'), util = require('util.js');
    var div_tabs = _.$('tabs');
    // .... 其他代码
});

一个模块可以通过局部函数require获取其他模块的接口。此时,变量_和util都是局部变量,并且,变量名完全是受开发者控制的,如果你不喜欢_,那也可以用base:

define(function(require, exports, module) {
    var base = require('base.js'), util = require('util.js');
    var div_tabs = base.$('tabs');
    // .... 其他代码
});

一旦要移除util.js、添加ui.js,那只要修改tabs.js就可以了:

define(function(require, exports, module) {
    var base = require('base.js'), ui = require('ui.js');
    var div_tabs = base.$('tabs');
    // .... 其他代码
});

加载器

由于缺乏浏览器的原生支持,如果我们要用模块化的方式编码,就必须借助于一个叫做加载器(loader)的东西。

目前加载器的实现有很多,比如 RequireJs、SeaJs、LABJs

参考文章:

从七牛同步备份资源到阿里云OSS

先下载并解压

wget http://oss.aliyuncs.com/import-service-package/ossimport4linux.zip
unzip ./ossimport4linux.zip -d /root/aliyun-oss

修改配置文件

vim /root/aliyun-oss/conf/sys.properties
workingDir=/root/aliyun-oss
slaveUserName=
slavePassword=
privateKeyFile=
slaveTaskThreadNum=60
slaveMaxThroughput(KB/s)=100000000
slaveAbortWhenUncatchedException=false
dispatcherThreadNum=5

新增任务配置文件(按69发布机上的样例填写)

vi /root/aliyun-oss/stay-user.cfg
vi /root/aliyun-oss/stay-event.cfg

开始守护进程

nohup java -jar /root/aliyun-oss/bin/ossimport2.jar -c /root/aliyun-oss/conf/sys.properties start > /root/aliyun-oss/logs/ossimport2.log 2>&1 &

提交新的任务

java -jar /root/aliyun-oss/bin/ossimport2.jar -c /root/aliyun-oss/conf/sys.properties submit /root/aliyun-oss/stay-event.cfg
java -jar /root/aliyun-oss/bin/ossimport2.jar -c /root/aliyun-oss/conf/sys.properties submit /root/aliyun-oss/stay-user.cfg

重置任务进度

java -jar /root/aliyun-oss/bin/ossimport2.jar -c /root/aliyun-oss/conf/sys.properties clean stay-event
java -jar /root/aliyun-oss/bin/ossimport2.jar -c /root/aliyun-oss/conf/sys.properties clean stay-user

查看任务执行状态

java -jar /root/aliyun-oss/bin/ossimport2.jar -c /root/aliyun-oss/conf/sys.properties stat detail

如需要开启OSS的图片处理服务,需要开通CDN域名,否则浏览器打开会直接下载。

官方文档:

MySQL 中 trim 处理字段多余字符

删除两侧空格

SELECT trim(`path`) as paths FROM `ts_back_pic`

删除左侧斜杠(头部)

SELECT trim(LEADING '/' FROM `path`) as paths FROM `ts_back_pic`

删除右侧斜杠(尾部)

SELECT trim(TRAILING '/' FROM `path`) as paths FROM `ts_back_pic`

删除两侧斜杠

SELECT trim(BOTH '/' FROM `path`) as paths FROM `ts_back_pic`

删除两侧空格+回车

SELECT trim(BOTH '\r\n' FROM trim(`path`)) as paths FROM `ts_back_pic`

CentOS 安装 Java

下载安装 JDK 查看官方最新版本

wget wget http://download.oracle.com/otn-pub/java/jdk/8u73-b02/jdk-8u73-linux-x64.rpm?AuthParam=1456243902_0c6c969e56ef0f0d93e786fc8691d178
rpm -ivh *.rpm

增加全局变量

vi /etc/profile

在底部增加

JAVA_HOME=/usr/java/latest
CLASSPATH=$JAVA_HOME/lib:$JAVA_HOME/jre/lib
PATH=$PATH:$JAVA_HOME/bin:$JAVA_HOME/jre/bin
export PATH CLASSPATH JAVA_HOME

使立即生效

source /etc/profile

查看系统环境状态

echo $PATH