Openssl实现双向认证教程(附服务端客户端代码)

yizhihongxing

OpenSSL实现双向认证教程

此教程将指导如何使用OpenSSL实现双向认证,包含服务端与客户端代码。在本教程中,我们将学习:

  • 什么是双向认证
  • 生成RSA密钥对
  • 生成自签名的根证书
  • 生成服务器证书请求(CSR)
  • 生成服务器证书
  • 配置服务端
  • 生成客户端证书请求(CSR)
  • 生成客户端证书
  • 配置客户端
  • 测试双向认证

什么是双向认证

在SSL/TLS连接中,通常只有服务器需要验证,因为它提供了服务(例如网站)给客户端。但是,在某些情况下,需要对客户端进行验证(例如API或者是移动设备上的应用程序)。这时就需要使用双向认证,确保只有经过认证的客户端可以访问服务器提供的服务。

生成RSA密钥对

首先,需要生成RSA密钥对。我们将使用OpenSSL生成2048位的RSA密钥对。以下命令可以生成密钥对:

openssl genrsa -out rootCA.key 2048

生成自签名的根证书

使用生成的RSA密钥对,可以生成自签名的根证书。以下命令可以生成根证书和私钥:

openssl req -x509 -new -key rootCA.key -days 3650 -out rootCA.crt

其中,-x509参数指定我们将要生成自签名证书,-new参数表示新建证书,-days参数指定证书的有效期天数,-out参数指定输出文件。执行完该命令后,将生成名为rootCA.crt的自签名根证书。

生成服务器证书请求(CSR)

使用以下命令生成服务器证书请求(CSR):

openssl req -new -key server.key -out server.csr

其中,-new参数表示新建证书请求,-key参数表示指定密钥文件,-out参数指定输出文件。执行完该命令后,将生成一个名为server.csr的证书请求文件。

生成服务器证书

使用以下命令生成服务器证书:

openssl x509 -req -in server.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out server.crt -days 3650

其中,-req参数表示该证书是从证书请求生成的,-in参数指定证书请求文件,-CA参数指定根证书,-CAkey指定RSA私钥,-CAcreateserial参数表示自动创建序列号,-out参数指定输出文件名,-days参数指定证书的有效期天数。执行完该命令后,会生成一个名为server.crt的服务器证书。

配置服务端

生成一个名为server.js的Node.js文件,将以下代码添加到文件中:

const fs = require('fs');
const https = require('https');
const express = require('express');

const app = express();

const options = {
    key: fs.readFileSync('server.key'),
    cert: fs.readFileSync('server.crt')
};

app.get('/', function(req, res) {
    res.send('Hello World!');
});

https.createServer(options, app).listen(8000, function() {
    console.log('Server started on port 8000.');
});

在代码运行之前,需要确保安装expresshttps模块。执行以下命令安装这两个依赖项:

npm install express https

要启动服务器,请运行以下命令:

node server.js

生成客户端证书请求(CSR)

使用以下命令生成客户端证书请求(CSR):

openssl req -new -key client.key -out client.csr

其中,-new参数表示新建证书请求,-key参数表示指定密钥文件,-out参数指定输出文件。执行完该命令后,将生成一个名为client.csr的证书请求文件。

生成客户端证书

使用以下命令生成客户端证书:

openssl x509 -req -in client.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out client.crt -days 3650

其中,-req参数表示该证书是从证书请求生成的,-in参数指定证书请求文件,-CA参数指定根证书,-CAkey指定RSA私钥,-CAcreateserial参数表示自动创建序列号,-out参数指定输出文件名,-days参数指定证书的有效期天数。执行完该命令后,会生成一个名为client.crt的客户端证书。

配置客户端

生成一个名为client.js的Node.js文件,将以下代码添加到文件中:

const fs = require('fs');
const https = require('https');

const options = {
    hostname: 'localhost',
    port: 8000,
    path: '/',
    method: 'GET',
    key: fs.readFileSync('client.key'),
    cert: fs.readFileSync('client.crt'),
    ca: fs.readFileSync('rootCA.crt')
};

https.request(options, function(res) {
    console.log('statusCode:', res.statusCode);
    console.log('headers:', res.headers);

    res.on('data', function(d) {
        process.stdout.write(d);
    });

}).end();

在运行代码之前,确保已经生成client.keyclient.crt文件。此外,还需要将rootCA.crt文件放置到运行代码的目录中。

要运行客户端,执行以下命令:

node client.js

测试双向认证

为了测试双向认证是否成功工作,您应该分别启动客户端和服务器,然后检查服务器的输出以查看是否成功。在终端运行以下两个命令:

$ node server.js
Server started on port 8000.

$ node client.js
Hello World!

如果您看到“Hello World!”的消息,则表明双向认证已成功工作!

示例

以下是使用双向认证的API服务器端和移动应用程序客户端的示例说明。

API服务器端

您可以使用此代码在API服务器端上实现双向认证。

const fs = require('fs');
const https = require('https');
const express = require('express');

const app = express();

const options = {
    key: fs.readFileSync('server.key'),
    cert: fs.readFileSync('server.crt'),
    requestCert: true,
    rejectUnauthorized: true,
    ca: [ fs.readFileSync('client.crt') ]
};

app.get('/', function(req, res) {
    res.send('Hello World!');
});

https.createServer(options, app).listen(8000, function() {
    console.log('Server started on port 8000.');
});

在客户端证书中指定完整的路径,而不是只指定文件名,例如:

ca: [ fs.readFileSync('/certs/client.crt') ]

移动应用程序客户端

您可以使用此代码在移动应用程序中实现双向认证。

try {
    // Create a KeyStore containing our trusted CA
    String keyStoreType = KeyStore.getDefaultType();
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);
    InputStream is = context.getAssets().open("rootCA.crt");
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    Certificate caCert = cf.generateCertificate(is);
    keyStore.setCertificateEntry("caCert", caCert);

    // Create a KeyStore containing our client certificate
    KeyStore clientKeyStore = KeyStore.getInstance("PKCS12");
    InputStream clientCert = context.getAssets().open("client.p12");
    clientKeyStore.load(clientCert, "client_password".toCharArray());

    // Create a TrustManager that trusts the CA in our KeyStore
    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keyStore);

    // Create a KeyManager that uses our client certificate
    String kmfAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
    KeyManagerFactory kmf = KeyManagerFactory.getInstance(kmfAlgorithm);
    kmf.init(clientKeyStore, "client_password".toCharArray());

    // Create an SSLContext that uses our TrustManager and KeyManager
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

    // Create an HTTPS connection and send a request
    URL url = new URL("https://example.com/api");
    HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
    conn.setSSLSocketFactory(sslContext.getSocketFactory());
    conn.setRequestMethod("GET");
    conn.connect();

    // Read the response
    InputStream in = conn.getInputStream();
    int bytesRead;
    byte[] buffer = new byte[1024];
    while ((bytesRead = in.read(buffer)) != -1) {
        System.out.write(buffer, 0, bytesRead);
    }
    in.close();
} catch (Exception e) {
    e.printStackTrace();
}

在客户端证书中指定完整的路径,而不是只指定文件名,例如:

InputStream clientCert = context.getAssets().open("client.p12");

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Openssl实现双向认证教程(附服务端客户端代码) - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • 易语言数据库操作“取字段数”命令

    下面是“易语言数据库操作-取字段数”命令的详细攻略。 1. 命令说明 “取字段数”命令是易语言中用于获取数据库表字段数量的命令。该命令需要使用到数据库对象,在执行该命令前需要先打开数据库。 2. 操作步骤 2.1 打开数据库 在使用“取字段数”命令前,需要先打开数据库。可使用“打开数据库”命令来打开数据库。以下是打开Access数据库的示例代码: //创建数…

    other 2023年6月25日
    00
  • 听说看了这篇文章就彻底搞懂了什么是OPC(上)

    OPC(OLE for Process Control)是一种用于工业自动化的通信协议,它允许不同的设备和系统之间进行数据交换和通信。在本文中,我们将详细介绍OPC的概念、架构、通信方式和应用场景,并提供两个示例说明。 OPC的概念 OPC是一种用于工业自动化的通信协议,它允许不同的设备和系统之间进行数据交换和通信。OPC协议的主要目的是提供一种标准化的接口…

    other 2023年5月5日
    00
  • MySQL表字段数量限制及行大小限制详情

    MySQL表字段数量限制及行大小限制详情 介绍 MySQL作为流行的关系型数据库管理系统,对于表的字段数量和行大小都做出了限制。本文将详细介绍这些限制规则。 表字段数量限制 MySQL限制表最多可包含的字段数量为4096个。当创建新表时,如果超过了这个限制,会弹出错误提示,例如: CREATE TABLE my_table ( column1 INT, co…

    other 2023年6月25日
    00
  • HTTP高并发调优小记

    HTTP高并发调优小记 HTTP高并发是指在同一时间内有大量的用户访问某一个网站,这就要求网站能够同时处理大量的请求,提供快速响应的服务。在高并发访问的情况下,网站可能会出现页面响应慢、无法访问等问题,给用户和运营带来很大的困扰。因此,对HTTP高并发的调优是一个网站必须重视的问题。 服务器硬件配置 在HTTP高并发的情况下,服务器的硬件配置至关重要。如果配…

    其他 2023年3月28日
    00
  • 关于android:如何在edittext中更改线条颜色

    关于Android:如何在EditText中更改线条颜色 在Android中,可以通过修改EditText的样式来更改其线条颜色。以下是关于如何在EditText中改线条颜色的完整攻略: 使用XML样式更改线条颜色 可以使用XML样式来更改EditText的线条颜色。可以按照以下步骤进行: 在res/values/styles文件中定义EditText的样式…

    other 2023年5月8日
    00
  • free 或delete后指针怎么样了

    Free 或 delete 后指针怎么样了? 当我们使用动态内存分配时,一个常见的问题是我们如何确保释放申请的内存以避免内存泄漏。释放内存通常涉及两种不同的操作:释放内存以便后续重用它,或者将指向该内存的指针删除。 但是,当我们使用 free() 或者将指针设置为 NULL 以删除指针时,究竟会发生什么呢?在本篇文章中,我们将讨论这两个操作以及它们对指针的影…

    其他 2023年3月28日
    00
  • Python批量安装卸载1000个apk的方法

    Python批量安装卸载1000个APK的方法 在Python中,我们可以使用subprocess模块来执行命令行操作,从而实现批量安装和卸载APK的功能。以下是详细的步骤: 导入所需的模块: import subprocess import os 定义APK文件夹路径和ADB命令路径: apk_folder = \"/path/to/apk/fo…

    other 2023年10月13日
    00
  • VC读配置文件实例

    下面是详细讲解“VC读配置文件实例”的完整攻略。 1. 为什么需要读取配置文件 在开发一些软件时,经常需要读取配置文件,用来存储一些应用程序的信息,如IP地址、端口号、密码等。配置文件通常是一个文本文件,可以使用文本编辑器打开修改。这些信息一般不会经常变化,所以将它们存储在配置文件中可以方便地进行修改。 2. 如何读取配置文件 在Visual C++中,可以…

    other 2023年6月25日
    00
合作推广
合作推广
分享本页
返回顶部