使用ssl自签证书搭建 Nodejs https 服务器, 并采用 AFNetworking 调用示例接口


使用 openssl 生成证书

openssl 说明: 使用 openssl 命令会把生成的证书输出到当前目录.

  1. 创建 CA 证书: 此证书是自签证书的根本, 创建了此证书相当于你自己就是第三方证书签发机构 (CA)了.
    生成步骤:
  1. 生成 CA 秘钥   
    openssl genrsa -out ca-key.pem -des3 2048
  2. 通过CA私钥生成CSR(证书请求文件)
    openssl req -new -key ca-key.pem -out ca-csr.pem
  3. 通过CSR文件和私钥生成CA证书(我理解为公钥, 包含了CA的信息)
    openssl x509 -req -in ca-csr.pem -signkey ca-key.pem -out ca-cert.pem

如果遇到权限问题

你需要root或者admin的权限 Unable to load config info from /user/local/ssl/openssl.cnf 对于这个问题,你可以从网上下载一份正确的openssl.cnf文件, 然后set OPENSSL_CONF=openssl.cnf文件的本地路径

  1. 创建服务器端证书: 此证书主要是在创建服务器时使用的, 在不同的认证方式中使用的证书不同, 下面会给出一些区别例子.
    在当前目录新建 openssl.cnf 文件
    模板:
[req]  
    distinguished_name = req_distinguished_name  
    req_extensions = v3_req  
  
    [req_distinguished_name]  
    countryName = Country Name (2 letter code)  
    countryName_default = CN  
    stateOrProvinceName = State or Province Name (full name)  
    stateOrProvinceName_default = BeiJing  
    localityName = Locality Name (eg, city)  
    localityName_default = YaYunCun  
    organizationalUnitName  = Organizational Unit Name (eg, section)  
    organizationalUnitName_default  = Domain Control Validated  
    commonName = Internet Widgits Ltd  
    commonName_max  = 64  
  
    [ v3_req ]  
    # Extensions to add to a certificate request  
    basicConstraints = CA:FALSE  
    keyUsage = nonRepudiation, digitalSignature, keyEncipherment  
    subjectAltName = @alt_names  
  
    [alt_names]  
    #注意这个IP.1的设置,IP地址需要和你的服务器的监听地址一样
    IP.1 = 127.0.0.1

生成步骤:

  1. 生成服务器秘钥   
    openssl genrsa -out server-key.pem 2048
  2. 通过服务器私钥生成CSR(证书请求文件)
    openssl req -new -key server-key.pem -config openssl.cnf -out server-csr.pem
  3. 通过CSR文件和私钥以及CA证书生成服务器证书(我理解为公钥, 包含了 CA 证书,服务器信息(域名等..), 和服务器公钥)
    openssl x509 -req -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -in server-csr.pem -out server-cert.pem -extensions v3_req -extfile openssl.cnf
  1. 创建客户端证书: 此证书,在某些情况下可以不使用. 比如我们下面的 iOS 端使用 AFNetworking 调用接口的例子.
    生成步骤:
生成客户端私钥
  openssl genrsa -out client-key.pem
生成CSR
  openssl req -new -key client-key.pem -out client-csr.pem
生成客户端证书(我理解为公钥)
openssl x509 -req -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -in client-csr.pem -out client-cert.pem

参考:

HTTPS单向认证和双向认证


使用express框架创建 nodejs 服务器

  1. 安装express generator , 我使用的是4.13.4版本, nodejs 的版本为v5.11.1, npm 的版本为3.8.6
    npm install -g express-generator #必要时可能需要 sudo
  2. 安装完成后使用 express 命令,生成 express app
    express httpsapp #执行结束后会在当前目录下生成 nodejs 项目 httpsapp
  3. 安装依赖,测试项目创建是否成功
cd httpsapp
npm install
//執行
npm start

在浏览器中打开http://localhost:3000查看是否启动成功.

使用ssl自签证书搭建 Nodejs https 服务器, 并采用 AFNetworking 调用示例接口_第1张图片
启动成功返回的页面

  1. 在项目根目录下创建 ssl 文件夹, 并把刚刚生成的证书放到其中.
  2. 修改bin/www的代码, 把 http服务器改成 https 服务器
    以下是修改后的代码: 保证核心代码一样就行.
#!/usr/bin/env node
var app = require('../app');
var debug = require('debug')('httpsApp:server');
// var http = require('http');
var https = require('https');
var fs = require('fs');
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
 * 创建 https 服务器
*/
// 获取证书
var options = {
  key: fs.readFileSync('./ssl/server-key.pem'),
  ca: [fs.readFileSync('./ssl/ca-cert.pem')],
  cert: fs.readFileSync('./ssl/server-cert.pem')
};
var server = https.createServer(options, app).listen(app.get('port'),'127.0.0.1');
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
function normalizePort(val) {
  var port = parseInt(val, 10);
  if (isNaN(port)) {
    // named pipe
    return val;
  }
  if (port >= 0) {
    // port number
    return port;
  }
  return false;
}
function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }
  var bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}
function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
}
  1. 再次打开浏览器查看https://localhost:3000.如下图则服务器创建成功.
使用ssl自签证书搭建 Nodejs https 服务器, 并采用 AFNetworking 调用示例接口_第2张图片
修改为 https 服务器后的页面
  1. 打开routs/users.js 文件(或者自己根据路由创建自己的测试接口)
    修改为:
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
  res.send({
    "code" : "1100",
    "message" : "test success"
  });
});
module.exports = router;

这样就完成了一个简单的测试接口.

  1. 编写客户端代码测试接口是否可用.
    在任意目录创建文件 client.js
    内容为:
var https = require('https');
var fs = require('fs');
var options = {
    hostname:'127.0.0.1',
    port:3000,
    path:'/users',
    method:'GET',
    key:fs.readFileSync('../ssl/client-key.pem'),
    cert:fs.readFileSync('../ssl/client-cert.pem'),
    ca: [fs.readFileSync('../ssl/ca-cert.pem')],
    agent:false
};
options.agent = new https.Agent(options);
var req = https.request(options,function(res){
console.log("statusCode: ", res.statusCode);
  console.log("headers: ", res.headers);
    res.setEncoding('utf-8');
    res.on('data',function(d){
        console.log(d);
    })
});
req.end();
req.on('error',function(e){
    console.log(e);
})

最后执行命令
node client.js
返回结果为:

使用ssl自签证书搭建 Nodejs https 服务器, 并采用 AFNetworking 调用示例接口_第3张图片
返回结果

说明接口没有问题.

以上过程, 可以参考 :

用Node.js创建自签名的HTTPS服务器
Node.js - Express 4.x 使用 HTTPS/SSL


在 iOS 端使用 AFNWorking 调用接口

  1. ** 在 iOS 中使用 https 需要注意 **
    首先必须要基于TLS 1.2版本协议。再来就是连接的加密方式要提供Forward Secrecy (这个不太懂)。最后就是证书至少要使用一个SHA256的指纹与任一个2048位或者更高位的RSA密钥,或者是256位或者更高位的ECC密钥。如果不符合其中一项,请求将被中断并返回nil。从我们生成证书的过程中也看到秘钥的长度是2048.

  2. ** 转换证书格式**
    此部分参考使用openssl进行证书格式转换
    其中 cer 和 der 是基本通用的,由于 AFNWorking 推荐使用 cer 类型的证书,所以我们可以使用一下命令把我们生成的 pem 证书转换成 cer.

openssl x509 -outform der -in server-cert.pem -out server-cert.cer

基于AFNWorking 的验证方式我们只需要 server 的证书(公钥)就可以了.

  1. 把生成的 cer 证书拖到项目中.
  2. 使用一下代码条用接口查看返回数据
//把服务端证书(需要转换成cer格式)放到APP项目资源里,AFSecurityPolicy会自动寻找根目录下所有cer文件
    NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"server-cert" ofType:@"cer"];
    NSData *cerData = [NSData dataWithContentsOfFile:cerPath];
    NSSet *cerSet = [[NSSet alloc] initWithObjects:cerData, nil];
    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey withPinnedCertificates:cerSet];
    securityPolicy.allowInvalidCertificates = YES;
    securityPolicy.validatesDomainName = NO;
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.requestSerializer = [AFHTTPRequestSerializer serializer];
    manager.responseSerializer = [AFJSONResponseSerializer serializer]; // 这一步需要注意否者返回的数据可能是 NSData 需要自行转换成 json.
    manager.securityPolicy = securityPolicy;
    manager.responseSerializer.acceptableContentTypes=[NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", @"text/plain", nil];
//关闭缓存避免干扰测试
    manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;   [manager GET:@"https://127.0.0.1:3000/users" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        DDLogDebug(@"%@", responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        DDLogError(@"%@", error);
    }];

返回结果为

使用ssl自签证书搭建 Nodejs https 服务器, 并采用 AFNetworking 调用示例接口_第4张图片
iOS 控制台返回结果

以上内容很多地方引用自iOS中AFNetworking HTTPS的使用

你可能感兴趣的:(使用ssl自签证书搭建 Nodejs https 服务器, 并采用 AFNetworking 调用示例接口)