You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

仅知IP地址,如何用Java获取HTTP服务器证书的CN与SAN?

通过IP地址用Java查询HTTPS服务器证书的通用名称与主题备用名称

假设已知某服务器的IP地址为1.2.3.4(示例虚构地址),通过在线工具查询该IP对应的证书信息,结果示例如下:

Common Name = fqdn.org
Organization = somebody
City/Locality = Somewhere
State/Province = Somestate
Country = US
Subject Alternative Names = www.fqdn.org, another.fqdn.org
....

可以通过Java自带的SSL相关API直接建立到目标IP的SSL连接,获取并解析服务器证书,无需依赖外部工具。以下是简便实现方案:

核心实现思路

  • 建立到目标IP指定端口(默认443)的SSL Socket连接
  • 临时跳过主机名验证(因用IP连接时,证书域名可能与IP不匹配,仅适用于测试场景,生产环境需谨慎)
  • 从连接中提取服务器证书链的第一个证书(即服务器端证书)
  • 解析证书的通用名称(Common Name)和主题备用名称(Subject Alternative Names)

完整代码示例

import javax.net.ssl.*;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SslCertificateChecker {

    public static void main(String[] args) {
        String targetIp = "1.2.3.4";
        int targetPort = 443;

        try {
            // 初始化SSL上下文与Socket工厂
            SSLContext sslContext = SSLContext.getDefault();
            SSLSocketFactory socketFactory = sslContext.getSocketFactory();

            // 创建并连接SSL Socket
            SSLSocket sslSocket = (SSLSocket) socketFactory.createSocket(targetIp, targetPort);

            // 禁用主机名验证(仅测试用,生产环境请勿保留)
            HostnameVerifier skipHostVerify = (hostname, session) -> true;
            HttpsURLConnection.setDefaultHostnameVerifier(skipHostVerify);

            // 触发SSL握手
            sslSocket.startHandshake();

            // 获取服务器证书,取证书链第一个元素
            Certificate[] certChain = sslSocket.getSession().getPeerCertificates();
            X509Certificate serverCert = (X509Certificate) certChain[0];

            // 解析通用名称(CN)
            String commonName = extractCommonName(serverCert);
            System.out.println("通用名称(Common Name): " + commonName);

            // 解析主题备用名称(SAN)
            List<String> sanList = extractSubjectAlternativeNames(serverCert);
            System.out.println("主题备用名称(Subject Alternative Names): " + String.join(", ", sanList));

            // 关闭连接
            sslSocket.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 从证书SubjectDN中提取通用名称
    private static String extractCommonName(X509Certificate cert) {
        String subjectDn = cert.getSubjectX500Principal().getName();
        Pattern cnPattern = Pattern.compile("CN=([^,]+)");
        Matcher matcher = cnPattern.matcher(subjectDn);
        return matcher.find() ? matcher.group(1) : null;
    }

    // 提取主题备用名称中的DNS条目
    private static List<String> extractSubjectAlternativeNames(X509Certificate cert) {
        List<String> sanList = new ArrayList<>();
        byte[] sanExtension = cert.getExtensionValue("2.5.29.17"); // SAN对应的OID标识

        if (sanExtension == null) {
            return sanList;
        }

        // 解析DER编码的SAN扩展内容
        int offset = 2; // 跳过序列长度字段
        int sanCount = (sanExtension[offset] & 0xFF) << 8 | (sanExtension[offset + 1] & 0xFF);
        offset += 2;

        for (int i = 0; i < sanCount; i++) {
            int tag = sanExtension[offset] & 0xFF;
            if (tag == 2) { // 仅提取DNS类型的SAN条目
                int length = sanExtension[offset + 1] & 0xFF;
                offset += 2;
                String dnsName = new String(sanExtension, offset, length);
                sanList.add(dnsName);
                offset += length;
            } else {
                // 跳过非DNS类型的条目(如IP、邮箱等)
                int length = sanExtension[offset + 1] & 0xFF;
                offset += 2 + length;
            }
        }
        return sanList;
    }
}

注意事项

  • 安全风险提示:代码中禁用主机名验证的逻辑仅用于快速测试,生产环境中必须替换为符合业务安全要求的HostnameVerifier实现,避免中间人攻击风险。
  • 异常处理:实际使用时需补充连接超时、证书信任异常等场景的捕获与处理,提升代码健壮性。
  • 端口适配:默认使用HTTPS标准443端口,若目标服务器使用自定义端口,需修改targetPort参数。

内容的提问来源于stack exchange,提问作者Bitbang3r

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 12:07:08