• Python:获取域名ssl证书信息和到期时间!


    大家注意:因为微信最近又改了推送机制,经常有小伙伴说错过了之前被删的文章,比如前阵子冒着风险写的爬虫,再比如一些限时福利,错过了就是错过了。

    所以建议大家加个星标,就能第一时间收到推送!

    60d2b5b57c4b2d99d032af316bb68f4f.gif


    文档

    https://docs.python.org/zh-cn/3/library/socket.html

    https://docs.python.org/zh-cn/3/library/ssl.html

    1、通过openssl证书获取

    openssl x509 -in .pem -noout -dates

    2、通过openssl域名获取

    echo | openssl s_client -servername  -connect :443 2>/dev/null | openssl x509 -noout -dates

    3、通过脚本获取curl

    1. # coding: utf-8 
    2. # 查询域名证书到期情况
    3. import re
    4. import subprocess
    5. from datetime import datetime
    6. def get_re_match_result(pattern, string):
    7.     match = re.search(pattern, string)
    8.     return match.group(1)
    9. def parse_time(date_str):
    10.     return datetime.strptime(date_str, "%b %d %H:%M:%S %Y GMT")
    11. def format_time(date_time):
    12.     return datetime.strftime(date_time, "%Y-%m-%d %H:%M:%S")
    13. def get_cert_info(domain):
    14.     """获取证书信息"""
    15.     cmd = f"curl -Ivs https://{domain} --connect-timeout 10"
    16.     exitcode, output = subprocess.getstatusoutput(cmd)
    17.     # 正则匹配
    18.     start_date = get_re_match_result('start date: (.*)', output)
    19.     expire_date = get_re_match_result('expire date: (.*)', output)
    20.     # 解析匹配结果
    21.     start_date = parse_time(start_date)
    22.     expire_date = parse_time(expire_date)
    23.     return {
    24.         'start_date': start_date,
    25.         'expire_date': expire_date
    26.     }
    27. def get_cert_expire_date(domain):
    28.     """获取证书剩余时间"""
    29.     info = get_cert_info(domain)
    30.     print(info)
    31.     expire_date = info['expire_date']
    32.     # 剩余天数
    33.     return (expire_date - datetime.now()).days
    34. if __name__ == "__main__":
    35.     domain = 'www.baidu.com'
    36.     expire_date = get_cert_expire_date(domain)
    37.     print(expire_date)

    4、通过socket 获取域名ssl 证书信息

    核心代码

    1. # -*- coding: utf-8 -*-
    2. import socket
    3. import ssl
    4. def get_domain_cert(domain):
    5.     """
    6.     获取证书信息
    7.     :param domain: str
    8.     :return: dict
    9.     """
    10.     socket.setdefaulttimeout(5)
    11.     cxt = ssl.create_default_context()
    12.     skt = cxt.wrap_socket(socket.socket(), server_hostname=domain)
    13.     skt.connect((domain, 443))
    14.     cert = skt.getpeercert()
    15.     skt.close()
    16.     return cert
    17. if __name__ == "__main__":
    18.     print(get_domain_cert("www.baidu.com"))

    还有一种方式也记录一下

    1. import socket
    2. import ssl
    3.     
    4. def get_domain_cert(host, port=443, timeout=3):
    5.     """
    6.     获取证书信息
    7.     存在问题:没有指定主机ip,不一定能获取到正确的证书信息
    8.     :param host: str
    9.     :param port: int
    10.     :param timeout: int
    11.     :return: dict
    12.     """
    13.     context = ssl.create_default_context()
    14.     with socket.create_connection(address=(host, port), timeout=timeout) as sock:
    15.         with context.wrap_socket(sock, server_hostname=host) as wrap_socket:
    16.             return wrap_socket.getpeercert()

    输出

    1. {
    2. 'subject': ((('countryName''CN'),), (('stateOrProvinceName''beijing'),), (('localityName''beijing'),), (('organizationalUnitName''service operation department'),), (('organizationName''Beijing Baidu Netcom Science Technology Co., Ltd'),), (('commonName''baidu.com'),)), 
    3. 'issuer': ((('countryName''BE'),), (('organizationName''GlobalSign nv-sa'),), (('commonName''GlobalSign RSA OV SSL CA 2018'),)), 
    4. 'version'3
    5. 'serialNumber''4417CE86EF82EC6921CC6F68'
    6. 'notBefore''Jul  5 05:16:02 2022 GMT'
    7. 'notAfter''Aug  6 05:16:01 2023 GMT'
    8. 'subjectAltName': (('DNS''baidu.com'), ), 
    9. 'OCSP': ('http://ocsp.globalsign.com/gsrsaovsslca2018',), 
    10. 'caIssuers': ('http://secure.globalsign.com/cacert/gsrsaovsslca2018.crt',), 
    11. 'crlDistributionPoints': ('http://crl.globalsign.com/gsrsaovsslca2018.crl',)
    12. }

    结构化输出内容后的完整代码

    1. # -*- coding: utf-8 -*-
    2. import socket
    3. import ssl
    4. from dateutil import parser
    5. # requests.packages.urllib3.disable_warnings()
    6. try:
    7.     _create_unverified_https_context = ssl._create_unverified_context
    8. except AttributeError:
    9.     # Legacy Python that doesn't verify HTTPS certificates by default
    10.     pass
    11. else:
    12.     # Handle target environment that doesn't support HTTPS verification
    13.     ssl._create_default_https_context = _create_unverified_https_context
    14. DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
    15. socket.setdefaulttimeout(5)
    16. def get_domain_ip(domain):
    17.     """
    18.     获取ip地址
    19.     :param domain: str
    20.     :return: str
    21.     """
    22.     try:
    23.         addrinfo = socket.getaddrinfo(domain, None)
    24.         return addrinfo[0][-1][0]
    25.     except Exception as e:
    26.         pass
    27.     return None
    28. def get_domain_cert(domain):
    29.     """
    30.     获取证书信息
    31.     :param domain: str
    32.     :return: dict
    33.     """
    34.     cxt = ssl.create_default_context()
    35.     skt = cxt.wrap_socket(socket.socket(), server_hostname=domain)
    36.     skt.connect((domain, 443))
    37.     cert = skt.getpeercert()
    38.     skt.close()
    39.     return cert
    40. def get_cert_info(domain):
    41.     """
    42.     获取证书信息
    43.     :param domain: str
    44.     :return: dict
    45.     """
    46.     cert = get_domain_cert(domain)
    47.     issuer = _tuple_to_dict(cert['issuer'])
    48.     subject = _tuple_to_dict(cert['subject'])
    49.     return {
    50.         'domain': domain,
    51.         'ip': get_domain_ip(domain),
    52.         'subject': _name_convert(subject),
    53.         'issuer': _name_convert(issuer),
    54.         # 'version': cert['version'],
    55.         # 'serial_number': cert['serialNumber'],
    56.         'start_date': _parse_time(cert['notBefore']),
    57.         'expire_date': _parse_time(cert['notAfter']),
    58.     }
    59. def _tuple_to_dict(cert_tuple):
    60.     """
    61.     cert证书 tuple转dict
    62.     :param cert_tuple: tuple
    63.     :return:
    64.     """
    65.     data = {}
    66.     for item in cert_tuple:
    67.         data[item[0][0]] = item[0][1]
    68.     return data
    69. def _name_convert(data):
    70.     """
    71.     名字转换
    72.     :param data: dict
    73.     :return: dict
    74.     """
    75.     name_map = {
    76.         'C''countryName',
    77.         'CN''commonName',
    78.         'O''organizationName',
    79.         'OU''organizationalUnitName',
    80.         'L''localityName',
    81.         'ST''stateOrProvinceName'
    82.     }
    83.     dct = {}
    84.     for key, value in name_map.items():
    85.         dct[key] = data.get(value, '')
    86.     return dct
    87. def _parse_time(time_str):
    88.     """
    89.     解析并格式化时间
    90.     :param time_str: str
    91.     :return: str
    92.     """
    93.     return parser.parse(time_str).astimezone().strftime(DATETIME_FORMAT)
    94. if __name__ == "__main__":
    95.     print(get_cert_info("www.baidu.com"))

    输出

    1. {
    2.   "domain""www.baidu.com",
    3.   "ip""39.156.66.14",
    4.   "subject": {
    5.     "C""CN",
    6.     "CN""baidu.com",
    7.     "O""Beijing Baidu Netcom Science Technology Co., Ltd",
    8.     "OU""service operation department",
    9.     "L""beijing",
    10.     "ST""beijing"
    11.   },
    12.   "issuer": {
    13.     "C""BE",
    14.     "CN""GlobalSign RSA OV SSL CA 2018",
    15.     "O""GlobalSign nv-sa",
    16.     "OU""",
    17.     "L""",
    18.     "ST"""
    19.   },
    20.   "start_date""2022-07-05 13:16:02",
    21.   "expire_date""2023-08-06 13:16:01"
    22. }

    5、通过pyOpenSSL获取证书信息

    该方式,不校验证书合法性,只获取证书信息

    文档:https://pyopenssl.org/en/0.15.1/index.html#

    依赖

    pip install pyOpenSSL

    示例

    1. # -*- coding: utf-8 -*-
    2. import ssl
    3. import OpenSSL
    4. def get_ssl_expire_date(host, port=443):
    5.     cert = ssl.get_server_certificate((host, port))
    6.     x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
    7.     return x509.get_notAfter().decode()
    8. if __name__ == '__main__':
    9.     print(get_ssl_expire_date('www.baidu.com'))
    10.     # 20230806051601Z

    6、Domain Admin可视化管理域名证书到期

    项目地址:https://github.com/mouday/domain-admin

    运行环境:Python 3.7.0

    1. $ pip install domain_admin
    2. # 升级到最新版本,可选
    3. $ pip3 install -U domain-admin -i https://pypi.org/simple
    4. # 启动运行
    5. $ gunicorn 'domain_admin.main:app'

    访问地址:http://127.0.0.1:8000

    默认的管理员账号:admin 密码:123456

    a5f3d4cf655d333a66a3f371f8a85421.png

    交流群

    时隔2个月,摸鱼学习交流群再次限时开放了。

    d37cb381d56f31182de8f92eaf71d776.png

    Python技术交流群(技术交流、摸鱼、白嫖课程为主)又不定时开放了,感兴趣的朋友,可以在下方公号内回复:666,即可进入,一起 100 天计划

    老规矩,酱友们还记得么,右下角的 “在看” 点一下,如果感觉文章内容不错的话,记得分享朋友圈让更多的人知道!

    b75db7368c15453cbec7ff65366d8461.gif

    1. 【神秘礼包获取方式】
    2. 扫描下方二维码添加私人微信,再送一套精华电子书!,回复:电子书
  • 相关阅读:
    各位大佬,有什么办法能过滤掉箭头所示的标签呢
    为嵌入式设备编译Rust/dbus进程间通信组件
    今日论文阅读2022-11-10
    总结下.NET后端已经熟悉或者使用过了这么多东西,有没你喜欢用的
    【前端】webpack打包去除console.log
    晶圆盒RF载具ID读取器CK-S650-PA60E的1协议和N协议通信说明
    SSM+基于ssm的汽车租赁平台的设计与实现 毕业设计-附源码211708
    【Java八股文总结】之JDK8新特性
    Java(SpringBoot04)
    OpenAcc的使用
  • 原文地址:https://blog.csdn.net/weixin_48923393/article/details/132913786