Friday, November 1, 2024

Kiểm tra thông tin SSL bằng Python

-

1. Giới thiệu.

Đoạn code Python này là một script được sử dụng để kiểm tra và in thông tin cơ bản về chứng chỉ SSL/TLS của một danh sách các máy chủ.

Script này được thiết kế để kiểm tra và in thông tin cơ bản về chứng chỉ SSL/TLS của các máy chủ được chỉ định.

Có thể sử dụng để đảm bảo rằng các máy chủ đang sử dụng chứng chỉ hợp lệ và cấu hình đúng cách.

2. Kiến Thức Cần Thiết.

  • SSL/TLS và Chứng Chỉ SSL/TLS:
    • SSL (Secure Sockets Layer) và TLS (Transport Layer Security) là các giao thức bảo mật được sử dụng để bảo vệ dữ liệu truyền tải qua mạng.
    • Chứng chỉ SSL/TLS là các chứng chỉ số liệu số được sử dụng để xác nhận danh tính của máy chủ và bảo vệ sự toàn vẹn và bí mật của thông tin giao tiếp.
  • Python Thư Viện:
    • OpenSSL: Thư viện Python cung cấp giao diện để tương tác với SSL/TLS.
    • cryptography: Thư viện để xử lý và thao tác với chứng chỉ SSL/TLS.
    • idna: Thư viện để mã hóa và giải mã tên miền (Internationalized Domain Names in Applications).
  • Socket Programming:
    • Sử dụng module socket để thiết lập và quản lý kết nối mạng.
  • Concurrent Programming:
    • Sử dụng concurrent.futures.ThreadPoolExecutor để thực hiện đồng thời nhiều nhiệm vụ, cải thiện hiệu suất.
from OpenSSL import SSL
from cryptography import x509
from cryptography.x509.oid import NameOID
import idna

from socket import socket
from collections import namedtuple

HostInfo = namedtuple(field_names='cert hostname peername', typename='HostInfo')

HOSTS = [('wiki.hoanghd.com', 443)]

def verify_cert(cert, hostname):
    cert.has_expired()

def get_certificate(hostname, port):
    hostname_idna = idna.encode(hostname)
    sock = socket()

    sock.connect((hostname, port))
    peername = sock.getpeername()
    ctx = SSL.Context(SSL.SSLv23_METHOD) # most compatible
    ctx.check_hostname = False
    ctx.verify_mode = SSL.VERIFY_NONE

    sock_ssl = SSL.Connection(ctx, sock)
    sock_ssl.set_connect_state()
    sock_ssl.set_tlsext_host_name(hostname_idna)
    sock_ssl.do_handshake()
    cert = sock_ssl.get_peer_certificate()
    crypto_cert = cert.to_cryptography()
    sock_ssl.close()
    sock.close()

    return HostInfo(cert=crypto_cert, peername=peername, hostname=hostname)

def get_alt_names(cert):
    try:
        ext = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName)
        return ext.value.get_values_for_type(x509.DNSName)
    except x509.ExtensionNotFound:
        return None

def get_common_name(cert):
    try:
        names = cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)
        return names[0].value
    except x509.ExtensionNotFound:
        return None

def get_issuer(cert):
    try:
        names = cert.issuer.get_attributes_for_oid(NameOID.COMMON_NAME)
        return names[0].value
    except x509.ExtensionNotFound:
        return None

def print_basic_info(hostinfo):
    s = '''» {hostname} « … {peername}
    \tcommonName: {commonname}
    \tSAN: {SAN}
    \tissuer: {issuer}
    \tnotBefore: {notbefore}
    \tnotAfter:  {notafter}
    '''.format(
            hostname=hostinfo.hostname,
            peername=hostinfo.peername,
            commonname=get_common_name(hostinfo.cert),
            SAN=get_alt_names(hostinfo.cert),
            issuer=get_issuer(hostinfo.cert),
            notbefore=hostinfo.cert.not_valid_before,
            notafter=hostinfo.cert.not_valid_after
    )
    print(s)

def check_it_out(hostname, port):
    hostinfo = get_certificate(hostname, port)
    print_basic_info(hostinfo)


import concurrent.futures
if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=4) as e:
        for hostinfo in e.map(lambda x: get_certificate(x[0], x[1]), HOSTS):
            print_basic_info(hostinfo)

Kết quả.

» wiki.hoanghd.com « … ('113.161.201.128', 443)
        commonName: wiki.hoanghd.com
        SAN: ['wiki.hoanghd.com']
        issuer: R3
        notBefore: 2023-10-11 01:20:31
        notAfter:  2024-01-09 01:20:30

3. Cách hoạt động.

Import các thư viện: Code sử dụng các thư viện cần thiết để làm việc với chứng chỉ SSL/TLS và kết nối mạng. OpenSSL được sử dụng cho các chức năng liên quan đến SSL, cryptography được sử dụng để thao tác với chứng chỉ và idna được sử dụng để mã hóa tên miền.

from OpenSSL import SSL
from cryptography import x509
from cryptography.x509.oid import NameOID
import idna

Named Tuple: Định nghĩa một named tuple (HostInfo) để lưu trữ thông tin về chứng chỉ SSL của máy chủ, tên miền và thông tin peername của socket.

from collections import namedtuple

HostInfo = namedtuple(field_names='cert hostname peername', typename='HostInfo')

Danh sách các máy chủ: Chỉ định một danh sách các máy chủ cần kiểm tra, mỗi mục trong danh sách là một tuple chứa tên miền và cổng.

HOSTS = [
    ('wiki.hoanghd.com', 443)
]

Hàm xác minh chứng chỉ: Hàm này được thiết kế để thực hiện xác minh bổ sung trên chứng chỉ SSL, nó kiểm tra xem chứng chỉ đã hết hạn hay chưa.

def verify_cert(cert, hostname):
    # Hàm để xác minh chứng chỉ SSL
    # (Chưa được triển khai đầy đủ trong mã nguồn)

Hàm lấy chứng chỉ: Hàm này kết nối đến máy chủ và cổng được chỉ định, lấy chứng chỉ SSL, chuyển đổi nó thành chứng chỉ cryptography và trả về một named tuple HostInfo.

def get_certificate(hostname, port):
    # Hàm để thiết lập kết nối đến máy chủ và lấy chứng chỉ SSL của nó
    # ...

Các hàm thông tin chứng chỉ: Các hàm này trích xuất thông tin cụ thể từ chứng chỉ, chẳng hạn như Subject Alternative Names, Common Name và thông tin nhà cung cấp.

def get_alt_names(cert):
    # Hàm để lấy Subject Alternative Names (SAN) từ một chứng chỉ
    # ...

def get_common_name(cert):
    # Hàm để lấy Common Name (CN) từ một chứng chỉ
    # ...

def get_issuer(cert):
    # Hàm để lấy thông tin người phát hành từ một chứng chỉ
    # ...

Hàm in thông tin cơ bản: Hàm này nhận một tuple HostInfo và in thông tin về chứng chỉ, bao gồm tên phổ biến, SAN, nhà cung cấp, notBefore và notAfter.

def print_basic_info(hostinfo):
    # Hàm để in thông tin cơ bản về chứng chỉ SSL của máy chủ
    # ...

Hàm kiểm tra và in thông tin: Hàm này gọi get_certificateprint_basic_info để kiểm tra và in thông tin chứng chỉ SSL cho một máy chủ và cổng cụ thể.

def check_it_out(hostname, port):
    # Hàm để kiểm tra và in thông tin cơ bản cho một máy chủ
    # ...

ThreadPoolExecutor cho Thực hiện đồng thời: Script sử dụng ThreadPoolExecutor để thực hiện hàm get_certificate đối với nhiều máy chủ đồng thời. Kết quả sau đó được chuyển đến print_basic_info để in thông tin chứng chỉ cơ bản.

import concurrent.futures

if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=4) as e:
        for hostinfo in e.map(lambda x: get_certificate(x[0], x[1]), HOSTS):
            print_basic_info(hostinfo)

5. Bổ sung thêm thời gian hết hạn SSL.

Để thêm thông tin về số ngày hết hạn của chứng chỉ SSL/TLS vào đoạn mã, bạn có thể sử dụng thuộc tính not_valid_after của đối tượng chứng chỉ. Dưới đây là cách bạn có thể cập nhật mã để in thêm thông tin này:

Thêm import cho module datetime:

from datetime import datetime

Cập nhật hàm print_basic_info để bao gồm thông tin về ngày hết hạn:

def print_basic_info(hostinfo):
    not_before = hostinfo.cert.not_valid_before
    not_after = hostinfo.cert.not_valid_after

    s = '''» {hostname} « … {peername}
        \tcommonName: {commonname}
        \tSAN: {SAN}
        \tissuer: {issuer}
        \tnotBefore: {notbefore}
        \tnotAfter:  {notafter}
        \tdaysUntilExpiration: {days_until_expiration}
    '''.format(
        hostname=hostinfo.hostname,
        peername=hostinfo.peername,
        commonname=get_common_name(hostinfo.cert),
        SAN=get_alt_names(hostinfo.cert),
        issuer=get_issuer(hostinfo.cert),
        notbefore=not_before,
        notafter=not_after,
        days_until_expiration=(not_after - datetime.utcnow()).days
    )
    print(s)

Trong đoạn code cập nhật trên, not_valid_beforenot_valid_after là các thuộc tính của đối tượng chứng chỉ và days_until_expiration tính số ngày còn lại cho đến khi chứng chỉ hết hạn.

Sau đó, khi bạn gọi print_basic_info(hostinfo), thông tin về ngày hết hạn và số ngày còn lại sẽ được hiển thị như dưới.

» wiki.hoanghd.com « … ('113.161.201.128', 443)
                commonName: wiki.hoanghd.com
                SAN: ['wiki.hoanghd.com']
                issuer: R3
                notBefore: 2023-10-11 01:20:31
                notAfter:  2024-01-09 01:20:30
                daysUntilExpiration: 17

4. Kết Luận.

Đoạn code giúp tự động hóa quá trình kiểm tra chứng chỉ SSL/TLS cho nhiều máy chủ một cách hiệu quả.

Đây là công cụ hữu ích trong việc duyệt qua các máy chủ và đảm bảo tính an toàn của kết nối SSL/TLS.

Chú ý rằng đoạn code này có thể cần được mở rộng thêm để thực hiện các kiểm tra bảo mật chi tiết hơn tùy thuộc vào yêu cầu cụ thể của ứng dụng.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

4,956FansLike
256FollowersFollow
223SubscribersSubscribe
spot_img

Related Stories