本文目录导读:

我来提供几个不同语言的SSL证书检测脚本实现方案:
Python版本(推荐)
#!/usr/bin/env python3
"""
SSL证书检测脚本
支持检测:证书有效期、颁发者、主题、SAN、证书链等
"""
import ssl
import socket
import datetime
import argparse
import json
from urllib.parse import urlparse
def get_certificate_info(hostname, port=443, timeout=5):
"""获取SSL证书信息"""
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
try:
with socket.create_connection((hostname, port), timeout=timeout) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
cert = ssock.getpeercert()
# 解析证书信息
cert_info = {
'hostname': hostname,
'port': port,
'checked_at': datetime.datetime.now().isoformat(),
'subject': dict(x[0] for x in cert['subject']),
'issuer': dict(x[0] for x in cert['issuer']),
'version': cert.get('version'),
'serial_number': cert.get('serialNumber'),
}
# 有效期
not_before = datetime.datetime.strptime(
cert['notBefore'], '%b %d %H:%M:%S %Y %Z'
)
not_after = datetime.datetime.strptime(
cert['notAfter'], '%b %d %H:%M:%S %Y %Z'
)
cert_info['valid_from'] = not_before.isoformat()
cert_info['valid_until'] = not_after.isoformat()
cert_info['days_remaining'] = (not_after - datetime.datetime.now()).days
cert_info['is_expired'] = datetime.datetime.now() > not_after
# SAN (Subject Alternative Names)
san = []
for ext in cert.get('subjectAltName', []):
san.append(ext[1])
cert_info['san'] = san
# 加密算法和密钥
cert_info['cipher'] = ssock.cipher()
return cert_info
except Exception as e:
return {'error': str(e), 'hostname': hostname, 'port': port}
def check_certificate_chain(hostname, port=443):
"""检查SSL证书链"""
import OpenSSL
try:
context = ssl.create_default_context()
with socket.create_connection((hostname, port)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
# 获取证书链
cert_chain = []
for cert in ssock.get_peer_cert_chain():
cert_chain.append({
'subject': cert.get_subject().get_components(),
'issuer': cert.get_issuer().get_components(),
'serial_number': cert.get_serial_number(),
'not_before': cert.get_notBefore().decode(),
'not_after': cert.get_notAfter().decode(),
})
return cert_chain
except Exception as e:
return {'error': str(e)}
def format_output(cert_info, format_type='text'):
"""格式化输出"""
if 'error' in cert_info:
return f"错误: {cert_info['error']}"
if format_type == 'json':
return json.dumps(cert_info, indent=2)
# 文本格式
output = []
output.append(f"=== SSL证书检测报告 ===")
output.append(f"主机: {cert_info['hostname']}:{cert_info['port']}")
output.append(f"检测时间: {cert_info['checked_at']}")
output.append("")
output.append(f"主题 (Subject):")
for key, value in cert_info['subject'].items():
output.append(f" {key}: {value}")
output.append("")
output.append(f"颁发者 (Issuer):")
for key, value in cert_info['issuer'].items():
output.append(f" {key}: {value}")
output.append("")
output.append(f"有效期:")
output.append(f" 开始: {cert_info['valid_from']}")
output.append(f" 结束: {cert_info['valid_until']}")
output.append(f" 剩余天数: {cert_info['days_remaining']}")
output.append(f" 已过期: {'是' if cert_info['is_expired'] else '否'}")
output.append("")
output.append(f"SAN (Subject Alternative Names):")
for san in cert_info['san']:
output.append(f" - {san}")
output.append("")
output.append(f"证书版本: {cert_info['version']}")
output.append(f"序列号: {cert_info['serial_number']}")
return '\n'.join(output)
def main():
parser = argparse.ArgumentParser(description='SSL证书检测工具')
parser.add_argument('hostname', help='要检测的主机名或URL')
parser.add_argument('-p', '--port', type=int, default=443, help='端口号 (默认: 443)')
parser.add_argument('-t', '--timeout', type=int, default=5, help='超时时间 (秒)')
parser.add_argument('-o', '--output', choices=['text', 'json'], default='text', help='输出格式')
parser.add_argument('--check-chain', action='store_true', help='检查证书链')
args = parser.parse_args()
# 从URL中提取主机名
hostname = args.hostname
if hostname.startswith('http'):
hostname = urlparse(hostname).hostname
# 获取证书信息
cert_info = get_certificate_info(hostname, args.port, args.timeout)
# 输出结果
print(format_output(cert_info, args.output))
# 检查证书链
if args.check_chain:
print("\n=== 证书链检查 ===")
chain = check_certificate_chain(hostname, args.port)
if isinstance(chain, list):
for i, cert in enumerate(chain):
print(f"\n证书 {i+1}:")
print(f" 颁发者: {cert['issuer']}")
print(f" 有效期至: {cert['not_after']}")
else:
print(f"错误: {chain['error']}")
if __name__ == '__main__':
main()
Bash脚本版本
#!/bin/bash
# SSL证书检测脚本
usage() {
echo "用法: $0 [-h 主机] [-p 端口] [-t 超时秒]"
echo "示例: $0 -h google.com -p 443"
exit 1
}
HOST=""
PORT=443
TIMEOUT=5
while getopts "h:p:t:" opt; do
case $opt in
h) HOST="$OPTARG" ;;
p) PORT="$OPTARG" ;;
t) TIMEOUT="$OPTARG" ;;
*) usage ;;
esac
done
if [ -z "$HOST" ]; then
usage
fi
echo "========================================"
echo "SSL证书检测报告"
echo "主机: $HOST:$PORT"
echo "检测时间: $(date)"
echo "========================================"
# 获取证书信息
cert_info=$(echo | openssl s_client -connect $HOST:$PORT -servername $HOST 2>/dev/null | openssl x509 -text -noout)
if [ $? -ne 0 ]; then
echo "错误: 无法连接到 $HOST:$PORT"
exit 1
fi
# 提取证书信息
subject=$(echo "$cert_info" | grep "Subject:" | head -1)
issuer=$(echo "$cert_info" | grep "Issuer:" | head -1)
valid_from=$(echo "$cert_info" | grep "Not Before" | head -1)
valid_until=$(echo "$cert_info" | grep "Not After" | head -1)
serial=$(echo "$cert_info" | grep "Serial Number:" | head -1)
# 计算剩余天数
if command -v date &> /dev/null; then
expiry_date=$(echo "$valid_until" | sed 's/Not Before: //' | sed 's/Not After : //')
expiry_epoch=$(date -d "$expiry_date" +%s 2>/dev/null)
now_epoch=$(date +%s)
if [ ! -z "$expiry_epoch" ]; then
remaining_days=$(( ($expiry_epoch - $now_epoch) / 86400 ))
echo ""
echo "剩余天数: $remaining_days 天"
if [ $remaining_days -le 30 ]; then
echo "⚠️ 警告: 证书即将过期!"
elif [ $remaining_days -le 0 ]; then
echo "❌ 证书已过期!"
fi
fi
fi
# 提取SAN
echo ""
echo "证书详细信息:"
echo "$cert_info" | grep -A 1 "Subject Alternative Name" | head -2
echo ""
echo "主题 (Subject):"
echo "$subject"
echo ""
echo "颁发者 (Issuer):"
echo "$issuer"
echo ""
echo "有效期:"
echo "$valid_from"
echo "$valid_until"
echo ""
echo "序列号:"
echo "$serial"
批量检测脚本(Python)
#!/usr/bin/env python3
"""
批量SSL证书检测脚本
支持从文件读取主机列表
"""
import json
import sys
import concurrent.futures
from ssl_cert_checker import get_certificate_info, format_output
def load_hosts_from_file(filename):
"""从文件加载主机列表"""
hosts = []
with open(filename, 'r') as f:
for line in f:
line = line.strip()
if line and not line.startswith('#'):
parts = line.split(':')
host = parts[0]
port = int(parts[1]) if len(parts) > 1 else 443
hosts.append((host, port))
return hosts
def check_multiple_hosts(hosts, max_workers=10):
"""并发检测多个主机"""
results = []
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
future_to_host = {
executor.submit(get_certificate_info, host, port): (host, port)
for host, port in hosts
}
for future in concurrent.futures.as_completed(future_to_host):
host, port = future_to_host[future]
try:
result = future.result()
results.append(result)
except Exception as e:
results.append({
'hostname': host,
'port': port,
'error': str(e)
})
return results
def main():
if len(sys.argv) < 2:
print("用法: python batch_check.py <主机列表文件> [输出格式]")
print("主机列表文件格式: 每行一个主机名或 host:port")
print("输出格式: text (默认) 或 json")
sys.exit(1)
filename = sys.argv[1]
output_format = sys.argv[2] if len(sys.argv) > 2 else 'text'
hosts = load_hosts_from_file(filename)
if not hosts:
print("错误: 没有找到有效的主机")
sys.exit(1)
print(f"开始检测 {len(hosts)} 个主机...")
results = check_multiple_hosts(hosts)
# 按剩余天数排序
results.sort(key=lambda x: x.get('days_remaining', 999), reverse=True)
# 输出汇总
if output_format == 'json':
print(json.dumps(results, indent=2))
else:
print("\n" + "="*60)
print("SSL证书检测汇总报告")
print("="*60)
for result in results:
print("\n" + format_output(result))
print("-"*40)
if __name__ == '__main__':
main()
安装依赖
# Python依赖 pip install pyOpenSSL # 或者使用requirements.txt # pip install -r requirements.txt # requirements.txt内容: # pyOpenSSL>=21.0.0
使用示例
# 基础用法 python ssl_checker.py example.com # 指定端口 python ssl_checker.py example.com -p 8443 # JSON输出 python ssl_checker.py example.com -o json # 检查证书链 python ssl_checker.py example.com --check-chain # Bash脚本 ./ssl_check.sh -h example.com -p 443 # 批量检测 python batch_check.py hosts.txt
主机列表文件格式
# hosts.txt 格式 example.com google.com:443 github.com:443 api.example.com:8443
这个脚本集提供了完整的SSL证书检测功能,包括:
- 单个主机检测
- 批量检测
- 证书详情查看
- 有效期监控
- 证书链检查
- 多种输出格式