Skip to content

使用xca自签证书

https://www.hohnstaedt.de/xca/index.php

https://blog.mojijs.com/post/https-server.html

自签名证书是什么原理?我们的系统中会带有一些公认被信任的根证书,用受信任根证书私钥签发的证书也会被认为是安全可靠的。
如果我们自己弄一个根证书安装到系统中并且信任那么用这个根证书私钥签发的证书也就会被信任。说起来简单,其实背后有特别多的知识。

我不认为公网服务用自签证书合适,对用户的要求太高,但是实现公司范围内的https化或者测试使用是没问题的,在公司范围内可操作性非常高,更何况我们还可以开发一个客户端来完成这件事儿,新员工入职系统中直接装根证书。

创建数据库

会要求输入密码,这个密码是你以后打开数据库文件需要使用的,为了安全,建议大家设置的复杂一些。

创建模板

先创建模板有利于减少以后重复工作。

模板分为三类,根证书模板(ca模板),服务端证书模板,客户端证书模板。

切换到Templates标签页,先创建ca模板。

按照实际情况输入信息

服务端证书模板,这里commonName不填写,这以后填写具体域名。

客户端证书模板。

设置证书有效日期

以下所有创建证书的过程中,都可以切换到Extensions标签页设置证书的有效期限

创建根证书

切换到Certificates标签页。
选择右侧的New Certificate。
注意下图的所选择的信息。Apply All是一定要点击的,以后的服务端证书和客户端证书同理。

切换到弹出窗的Subject标签页,其实之前模板填写的大部分信息这里都已经自动填充了。只填写其他一些信息即可,如下图。

创建服务端证书

首先在证书列表中选中刚才的根证书,之后点击 New Certificate,如下图。

注意框出来的部分。

添加信任的 ip 和 dns

点击Apply All之后切换到Extensions,在Subject alternative name(别名)中添加一个127.0.0.1的 IP 和一个 localhost的 DNS

导出根证书并安装根证书

如下图,注意证书格式,可别把私钥导出去发给别人了

mac直接双击即可打开钥匙串管理,然后还需要设置根证书始终信任。

导出服务端证书

创建客户端证书

导出客户端证书

测试

服务端测试代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
from aiohttp import web
import ssl
def extract_cert(request):
    peercert = request.transport.get_extra_info("peercert")
    subject = peercert['subject']
    ans = {}
    for k in subject:
        for k, v in k:
            ans[k] = v
    return ans
async def handle(request):
    user = extract_cert(request)
    text = f"Hello, {user['commonName']}"
    return web.Response(text=text)
app = web.Application()
app.add_routes([web.get('/', handle),
                web.get('/{name}', handle)])
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile='nocilantro_root_cert.pem') # 根CA证书
# ssl_context.verify_mode = ssl.CERT_OPTIONAL
ssl_context.verify_mode = ssl.CERT_REQUIRED
ssl_context.load_cert_chain('nocilantro_crt.pem', 'nocilantro_server.pem') # 服务端证书
web.run_app(app, ssl_context=ssl_context)

客户端测试代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import ssl 
import aiohttp
import asyncio
sslcontext = ssl.create_default_context(cafile='nocilantro_root_cert.pem') # 根CA证书
sslcontext.load_cert_chain('test_client1_crt.pem',
                           'test_client1_key.pem') # 客户端证书
async def test():
    async with aiohttp.ClientSession() as session:
        async with session.get("https://nocilantro.cn:8443", ssl=sslcontext) as r:
            html = await r.text()
            print(html)
loop = asyncio.get_event_loop()
loop.run_until_complete(test())

服务器实测

假设服务器证书的 commonName 为 hhhh.com
生成服务端证书后,导出 crt 和 key 为 hhhh.com.crt 和 hhhh.com.key.pem

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from aiohttp import web
import ssl
def extract_cert(request):
    peercert = request.transport.get_extra_info("peercert")
    subject = peercert['subject']
    ans = {}
    for k in subject:
        for k, v in k:
            ans[k] = v
    return ans
async def handle(request):
    user = extract_cert(request)
    print(request)
    text = f"Hello, {user['commonName']}"
    return web.Response(text=text)
app = web.Application()
app.add_routes([web.get('/', handle),
                web.get('/{name}', handle)])
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile='nocilantro_root_cert.pem') # 根CA证书
# ssl_context.verify_mode = ssl.CERT_OPTIONAL
ssl_context.verify_mode = ssl.CERT_REQUIRED
ssl_context.load_cert_chain('hhhh.com.crt', 'hhhh.com.key.pem') # 服务端证书
# ssl_context.load_cert_chain('nocilantro_crt.pem', 'nocilantro_server.pem') # 服务端证书

web.run_app(app, port=11493, ssl_context=ssl_context)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import ssl 
import aiohttp
import asyncio
sslcontext = ssl.create_default_context(cafile='nocilantro_root_cert.pem') # 根CA证书
sslcontext.load_cert_chain('test_client1_crt.pem',
                           'test_client1_key.pem') # 客户端证书
async def test():
    async with aiohttp.ClientSession() as session:
        async with session.get("https://hhhh.com:11493/", ssl=sslcontext) as r:
            html = await r.text()
            print(html)
loop = asyncio.get_event_loop()
loop.run_until_complete(test())