본문 바로가기

Code

SSL 인증서 만료일 확인하는 스크립트

728x90
반응형

SSL 인증서 만료일 확인하는 스크립트

  • sslinfo.py 파일 생성
vim sslinfo.py
import ssl
import socket
from datetime import datetime
import argparse

def get_ssl_info(domain):
    try:
        # 도메인과 포트 분리
        if ':' in domain:
            domain, port = domain.split(':')
            port = int(port)
        else:
            port = 443

        # 도메인의 IP 주소 가져오기
        ip = socket.gethostbyname(domain)

        # 도메인에 대한 소켓 객체 가져오기
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(10)
        sock.connect((ip, port))

        # 소켓 객체를 SSL 컨텍스트로 감싸기
        context = ssl.create_default_context()
        context.check_hostname = False  # 호스트 이름 검증 비활성화
        ssl_sock = context.wrap_socket(sock, server_hostname=domain)

        # SSL 객체에서 인증서 가져오기
        cert = ssl_sock.getpeercert()

        # 인증서의 시작일, 만료일 및 남은 일 수 가져오기
        start_date = datetime.strptime(cert['notBefore'], "%b %d %H:%M:%S %Y %Z").strftime("%Y-%m-%d")
        expiration_date = datetime.strptime(cert['notAfter'], "%b %d %H:%M:%S %Y %Z").strftime("%Y-%m-%d")
        remaining_days = (datetime.strptime(expiration_date, "%Y-%m-%d") - datetime.now()).days

        # 등록행자(Registrar) 가져오기
        registrar = ""
        issuer = dict(x[0] for x in cert['issuer'])
        if 'organizationName' in issuer:
            registrar = issuer['organizationName']

        return domain, ip, start_date, expiration_date, int(remaining_days), registrar
    except (socket.timeout, socket.gaierror, ssl.SSLCertVerificationError):
        return domain, "N/A", "N/A", "N/A", "N/A", "N/A"

def generate_html_table(table_rows):
    html_table = "<html>"
    html_table += "<head>"
    html_table += "<meta charset='utf-8'>"
    html_table += "<meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>"
    html_table += "<style>"
    html_table += "table {"
    html_table += "width: 80%;"
    html_table += "border-top: 1px solid #444444;"
    html_table += "border-collapse: collapse;"
    html_table += "font-family: Monaco;"
    html_table += "font-size:90%;"
    html_table += "}"
    html_table += "th, td {"
    html_table += "border-bottom: 1px solid #444444;"
    html_table += "padding: 10px;"
    html_table += "text-align: center;"
    html_table += "}"
    html_table += "th {"
    html_table += "background-color: #e3f2fd;"
    html_table += "}"
    html_table += "td {"
    html_table += "background-color: #FFFFFF;"
    html_table += "}"
    html_table += "</style>"
    html_table += "</head>"
    html_table += "<body>"
    html_table += "<h1>SSL Certificate Expiration Date</h1>"
    html_table += "<table style='border-collapse: collapse; border: 1px solid black;'>\n"
    html_table += "<tr>"
    html_table += "<th style='border: 1px solid black;'>Domain</th>"
    html_table += "<th style='border: 1px solid black;'>IP Addresses</th>"
    html_table += "<th style='border: 1px solid black; text-align: center;'>Start Date</th>"
    html_table += "<th style='border: 1px solid black; text-align: center;'>Expiration Date</th>"
    html_table += "<th style='border: 1px solid black; text-align: center;'>Remaining Days</th>"
    html_table += "<th style='border: 1px solid black;'>Registrar</th>"
    html_table += "</tr>\n"

    for row in table_rows:
        html_table += "<tr>"
        for i, cell in enumerate(row):
            # 특정 열에 가운데 정렬 적용하기
            if i in [2, 3, 4]:
                html_table += f"<td style='border: 1px solid black; text-align: center;'>{cell}</td>"
            else:
                html_table += f"<td style='border: 1px solid black;'>{cell}</td>"
        html_table += "</tr>\n"

    html_table += "</table>"
    html_table += "</body>"
    html_table += "</html>"

    return html_table

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='SSL Certificate Expiration Date Checker')
    parser.add_argument('input_file', help='Path to the input file (domains.txt)')
    parser.add_argument('output_file', help='Path to the output file (result.html)')
    args = parser.parse_args()

    # 파일에서 도메인 이름 가져오기
    with open(args.input_file, 'r') as f:
        domains = f.readlines()

    table_rows = []

    # 각 도메인에 대한 SSL 정보 가져오기
    for domain in domains:
        ssl_info = get_ssl_info(domain.strip())

        # SSL 정보를 테이블 행에 추가하기
        table_rows.append(ssl_info)

    # "N/A" 값을 처리하여 남은 일 수(`remaining_days`)를 기준으로 테이블 행 정렬하기 (오름차순)
    table_rows.sort(key=lambda x: x[4] if isinstance(x[4], int) else float('inf'))

    # HTML 테이블 생성하기
    html_table = generate_html_table(table_rows)

    # HTML 테이블을 결과 파일에 저장하기
    with open(args.output_file, 'w') as file:
        file.write(html_table)

    print("SSL 정보가 result.html 파일에 저장되었습니다.")
    
### SSL 인증서 만료일 조회
# echo "" | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -startdate -enddate

또는 github에서 sslinfo.py 파일 다운로드 받기

https://raw.githubusercontent.com/anti1346/SSL-Certificate-Verify/master/sslinfo.py -o sslinfo.py
  • docker_container_start.sh 파일 생성
vim docker_container_start.sh
#!/bin/bash

docker run -d -p 8080:80 -v $(pwd)/result.html:/usr/share/nginx/html/index.html nginx

echo -e "\nhttp://localhost:8080\n"
chmod +x docker_container_start.sh
  • 도메인 리스트 파일 생성
vim domains.txt
www.google.com
www.daum.net
www.yahoo.com
example.com:443

실행 순서

1. sslinfo.py 실행

python sslinfo.py domains.txt result.html

2. docker_container_start.sh 실행

bash docker_container_start.sh
$ bash docker_container_start.sh
5184d39ceac05b7d0d05aa3bdc3641ba55ef1bbc8a9874eb8e796e61c30313ee

http://localhost:8080

3. 웹 브라우저에서 SSL 인증서 만료일 확인

ssl1

도커 컨테이너로 실행하는 방법

  • 도메인 리스트 파일 생성
vim domains.txt
www.google.com
www.daum.net
www.yahoo.com
example.com:443
ssl.example.com:8443
  • 도커 컨테이너 실행
docker run -d -p 8080:80 -v $(pwd)/domains.txt:/sslchecker/domains.txt --name sslchecker anti1346/ubuntu2204:sslchecker

 

참고URL

- github : https://github.com/anti1346/SSL-Certificate-Verify

 

728x90
반응형