Whois和RDAP:怎么查询域名注册信息?

Linus
Linus

原文发布于

2025年03月17日

/

最新更新于

2025年03月22日

/

阅读

68
0

域名是互联网的基石,为网站提供易记的地址。理解域名背后的管理机制对于网页开发、数字营销或域名注册者都很重要。当前已全面取代 WHOIS 的 RDAP 协议已经是主流了,如何使用 Python 脚本来做到域名查询、域名抢注,可以看下方内容。

简单解释版

域名注册局与注册商的角色

  • 注册局(Registry): 负责管理特定顶级域名(TLD)或国家代码顶级域名(ccTLD)。例如,VeriSign 管理 .com 和 .net,维护这些 TLD 下的所有域名数据库,确保唯一性。

  • 注册商(Registrar): 作为代理,代表注册局向公众销售域名。常见的注册商包括 GoDaddy、Namecheap 和 Google Domains。注册商是用户与注册局之间的中介。

  • 关系与外包: 一些注册局可能不直接管理操作,而是外包给技术服务商。这些公司既提供技术支持,也可作为注册商。一个注册商可以连接多个注册局,提供多种 TLD 的注册服务。此外,一些提供域名注册的网站实际上只是注册商的代理,而非注册商本身。

WHOIS 系统的详细说明

WHOIS 是一种协议,允许用户查询域名注册数据库,获取如注册人信息、注册时间和到期时间等详情。

  • IANA 的角色: IANA 维护顶级 WHOIS 服务器 whois.iana.org,存储注册局信息和其 WHOIS 服务器地址。

  • 查询过程: 要找到某个 TLD 的 WHOIS 服务器,可先查询 IANA 的服务器。例如,输入 “com” 可得到 .com 域名的 WHOIS 服务器为 whois.verisign-grs.com。接着,可连接到该服务器的 43 端口,发送完整域名(如 qq.com)并回车,获取详细信息。

  • 格式差异: 不同注册局的 WHOIS 响应格式可能不同,需编写程序并使用正则表达式解析提取有用信息。例如,查询已注册域名可得注册人信息和时间,未注册域名则返回明确标志。

  • 隐私保护: 由于隐私问题,近年注册商的 WHOIS 服务器已不再返回详细联系信息,仅提供基本注册信息。

RDAP 协议的介绍与过渡

RDAP(注册数据访问协议)是 WHOIS 的继任者,使用 HTTP 接口返回 JSON 数据,具有以下优势:

  • 支持国际化,适合多语言环境。

  • 提供更安全的访问控制。

  • 数据格式标准化,便于解析。

ICANN 宣布,自 2025 年 1 月 28 日起,RDAP 将成为通用顶级域名(gTLD)注册信息的权威来源,取代 WHOIS 服务。这一日期基于 ICANN 的公告,标志着 WHOIS 服务的逐步退出。用户可使用 ICANN 的 RDAP 查找工具 或 GitHub 上的开源命令行客户端(如 ICANN RDAP Lookup Client)进行查询。

实践中的注意事项

  • 批量查询: 进行大量域名查询时,部分注册局可能限制单个 IP 的短时间内查询次数。为此,建议使用多个 IP 地址或实现查询速率限制,以避免触发限制。

  • TLD 特定信息: 不同注册局提供的信息可能有所不同。例如,.ai 域名的注册局不返回注册时间和到期时间,需特别注意。

以下是通过 AI 整理的、经过核验详细版本,有点 AI 味儿,但信息是没错的。

1. 域名注册体系详解

1.1 注册局与注册商的角色区分

域名注册局 (Registry)是特定顶级域名 (TLD) 的管理机构,负责维护该 TLD 下所有域名的中央数据库。例如:

  • VeriSign 管理.com 和.net

  • Public Interest Registry 管理.org

  • CNNIC 管理.cn

  • Afilias 管理.info

域名注册商 (Registrar)是获得 ICANN(互联网名称与数字地址分配机构) 认证的实体,作为注册局与终端用户之间的中介。知名注册商包括:

  • GoDaddy

  • Namecheap

  • Google Domains(现已被 Squarespace 收购)

  • NameSilo

  • Cloudflare Registrar

1.2 注册体系的层级结构

域名注册体系呈现明确的层级结构:

  1. ICANN:位于顶层,制定政策并认证注册商

  2. 注册局:负责特定 TLD 的技术运营

  3. 注册商:向用户提供域名注册服务

  4. 用户:最终的域名持有者

1.3 特殊情况与变体

某些情况下,注册体系的角色可能出现交叉:

  • 技术服务外包:部分注册局将技术运营外包给第三方公司,这些公司既提供注册局服务,也可能作为注册商

  • 注册商代理:市场上存在许多域名注册服务提供商,它们实际上只是注册商的代理或分销商,不具备 ICANN 认证资格

  • 垂直整合:某些大型公司同时扮演注册局和注册商的角色,如 Verisign 既管理.com 和.net,也提供注册服务

2. WHOIS 系统全面解析

2.1 WHOIS 的定义与历史

WHOIS(读作 "who is") 是一个查询和响应协议,用于查询域名的注册信息。它起源于 1982 年,最初设计用于识别负责特定互联网资源的实体。随着互联网的发展,WHOIS 成为查询域名注册信息的标准方式。

2.2 WHOIS 服务器层级

WHOIS 系统由多层服务器组成:

  1. IANA 的顶级 WHOIS 服务器:whois.iana.org,存储所有 TLD 的注册局信息

  2. 注册局 WHOIS 服务器:每个 TLD 的注册局维护自己的 WHOIS 服务器

  3. 注册商 WHOIS 服务器:每个注册商也维护自己的 WHOIS 服务器

2.3 WHOIS 查询的详细步骤

以查询 "example.com" 为例,完整的 WHOIS 查询流程如下:

步骤 1:查询 IANA 的顶级 WHOIS 服务器

# 使用命令行工具
whois -h whois.iana.org com

# 或使用Socket连接
telnet whois.iana.org 43
# 然后输入"com"并回车

返回结果将包含.com 的注册局信息和 WHOIS 服务器地址:whois.verisign-grs.com

步骤 2:查询注册局的 WHOIS 服务器

# 使用命令行工具
whois -h whois.verisign-grs.com example.com

# 或使用Socket连接
telnet whois.verisign-grs.com 43
# 然后输入"example.com"并回车

返回结果将包含域名的基本注册信息,包括:

  • 域名状态 (如已注册、转移锁定等)

  • 注册日期和到期日期

  • 域名服务器信息

  • 注册商信息及其 WHOIS 服务器

步骤 3:查询注册商的 WHOIS 服务器 (可选)

# 假设注册商的WHOIS服务器是whois.registrar.example
whois -h whois.registrar.example example.com

然而,由于隐私保护政策,现在注册商的 WHOIS 服务器通常不会返回详细的注册人信息。

2.4 WHOIS 信息解析挑战

不同注册局的 WHOIS 响应格式各不相同,这给自动化解析带来了挑战。以下是几个主要 TLD 的 WHOIS 格式差异示例:

  • .com/.net:由 Verisign 管理,格式相对标准化

  • .org:提供更详细的状态信息

  • .io:格式简洁,但包含完整的注册日期

  • .ai:不返回注册日期和到期日期

解析 WHOIS 信息通常需要为每个 TLD 编写专门的正则表达式。以下是一个简单的 Python 示例,用于解析.com 域名的 WHOIS 信息:

import re
import socket

def query_whois(domain, server, port=43):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((server, port))
    s.send((domain + "\r\n").encode())
    
    response = b""
    while True:
        data = s.recv(4096)
        if not data:
            break
        response += data
    
    s.close()
    return response.decode('utf-8', errors='ignore')

def parse_com_whois(whois_data):
    # 解析注册日期
    creation_date_match = re.search(r'Creation Date: (.+)', whois_data)
    creation_date = creation_date_match.group(1) if creation_date_match else "未找到"
    
    # 解析到期日期
    expiration_date_match = re.search(r'Registry Expiry Date: (.+)', whois_data)
    expiration_date = expiration_date_match.group(1) if expiration_date_match else "未找到"
    
    # 解析注册商
    registrar_match = re.search(r'Registrar: (.+)', whois_data)
    registrar = registrar_match.group(1) if registrar_match else "未找到"
    
    return {
        "creation_date": creation_date,
        "expiration_date": expiration_date,
        "registrar": registrar
    }

# 使用示例
domain = "example.com"
whois_data = query_whois(domain, "whois.verisign-grs.com")
parsed_data = parse_com_whois(whois_data)
print(parsed_data)

2.5 WHOIS 的局限性

WHOIS 系统存在多项局限性,这也是推动 RDAP 协议发展的原因:

  • 格式不统一:不同注册局的响应格式各异

  • 国际化支持有限:不支持非 ASCII 字符的域名 (IDN)

  • 隐私问题:早期 WHOIS 公开了太多个人信息

  • 查询限制:没有标准化的速率限制机制

  • 缺乏身份验证:无法区分不同用户的访问权限

3. RDAP 协议:WHOIS 的现代替代品

3.1 RDAP 的定义与优势

注册数据访问协议 (Registration Data Access Protocol, RDAP) 是 WHOIS 的现代替代品,由 IETF 在 RFC 7480-7484 中定义。RDAP 通过 HTTP/HTTPS 提供服务,返回标准化的 JSON 格式数据。

RDAP 相比 WHOIS 具有显著优势:

  • 标准化 JSON 格式:便于程序解析和处理

  • 支持国际化域名 (IDN):完全支持 Unicode 字符

  • 分层访问控制:可根据用户身份提供不同级别的信息

  • 标准化查询参数:统一的查询语法

  • 内置分页机制:适合大量数据返回

  • 安全传输:支持 HTTPS 加密

3.2 ICANN 政策变更与 RDAP 过渡

ICANN 于 2025 年 1 月 27 日发布重要公告,宣布从 2025 年 1 月 28 日起,RDAP 将成为提供通用顶级域名 (gTLD) 注册信息的权威来源,正式取代 WHOIS 服务。这一决定基于 2023 年全球修订的 gTLD 注册协议,标志着域名查询系统的重大转变。

过渡时间表:

  • 2023 年 5 月:ICANN 董事会批准 RDAP 修订

  • 2024 年:过渡准备期

  • 2025 年 1 月 28 日:RDAP 正式成为 gTLD 注册信息的权威来源

  • 2025 年后:WHOIS 服务将逐步停用

3.3 RDAP 查询详细步骤

RDAP 查询比 WHOIS 更加直观,遵循 RESTful API 设计原则:

步骤 1:确定 RDAP 服务器

IANA 维护着 RDAP 服务器的 JSON 列表,可通过以下 URL 获取:

https://data.iana.org/rdap/dns.json

这个文件包含了各 TLD 对应的 RDAP 服务器地址。

步骤 2:构建 RDAP 查询 URL

RDAP 查询 URL 的一般格式为:

https://{rdap-server}/domain/{domain-name}

例如,查询 example.com 的 RDAP 信息:

https://rdap.verisign.com/com/v1/domain/example.com

步骤 3:发送 HTTP 请求并解析 JSON 响应

使用 HTTP 客户端发送 GET 请求,并解析返回的 JSON 数据。以下是使用 Python 的示例:

import requests
import json

def query_rdap(domain):
    # 这里简化处理,实际应先查询IANA的RDAP服务器列表
    tld = domain.split('.')[-1]
    if tld == 'com':
        rdap_server = "https://rdap.verisign.com/com/v1"
    else:
        # 处理其他TLD的逻辑
        return {"error": "Unsupported TLD"}
    
    url = f"{rdap_server}/domain/{domain}"
    
    try:
        response = requests.get(url)
        if response.status_code == 200:
            return response.json()
        else:
            return {"error": f"HTTP error: {response.status_code}"}
    except Exception as e:
        return {"error": str(e)}

# 使用示例
domain = "example.com"
rdap_data = query_rdap(domain)
print(json.dumps(rdap_data, indent=2))

RDAP 返回的 JSON 数据通常包含以下信息:

  • 域名状态

  • 注册日期和到期日期

  • 域名服务器信息

  • 注册商信息

  • 联系人信息 (如果可用)

  • 事件历史 (如创建、更新、转移等)

3.4 RDAP 工具与资源

以下是一些有用的 RDAP 工具和资源:

  • ICANN RDAP 查找工具:https://lookup.icann.org/en

  • RDAP 演示客户端:https://client.rdap.org/

  • RDAP 服务器列表:https://data.iana.org/rdap/dns.json

  • RDAP 支持的域名列表:https://deployment.rdap.org/

  • ICANN RDAP 命令行客户端:https://github.com/icann/rdap-lookup-client

4. 实用查询策略与最佳实践

4.1 批量查询策略

进行大规模域名查询时,需要注意以下几点:

查询速率限制

不同注册局和注册商对 WHOIS/RDAP 查询有不同的速率限制。例如:

  • Verisign(.com/.net):每 IP 每天约 1000-2000 次查询

  • Afilias(.org/.info):每 IP 每小时约 60-100 次查询

  • 某些小型 TLD:限制更严格,可能只允许每 IP 每小时 10-20 次查询

多 IP 轮询策略

为避免触发速率限制,可采用多 IP 轮询策略:

import requests
import time
import random

def query_with_ip_rotation(domains, proxy_list):
    results = {}
    
    for domain in domains:
        # 随机选择一个代理
        proxy = random.choice(proxy_list)
        
        try:
            # 使用选定的代理发送请求
            response = requests.get(
                f"https://rdap.verisign.com/com/v1/domain/{domain}",
                proxies={"http": proxy, "https": proxy},
                timeout=10
            )
            
            if response.status_code == 200:
                results[domain] = response.json()
            else:
                results[domain] = {"error": f"HTTP error: {response.status_code}"}
                
        except Exception as e:
            results[domain] = {"error": str(e)}
        
        # 添加随机延迟,避免请求过于集中
        time.sleep(random.uniform(1, 3))
    
    return results

# 使用示例
domains = ["example1.com", "example2.com", "example3.com"]
proxy_list = [
    "http://proxy1.example:8080",
    "http://proxy2.example:8080",
    "http://proxy3.example:8080"
]

results = query_with_ip_rotation(domains, proxy_list)

指数退避策略

当遇到限制时,可采用指数退避策略:

import time
import random

def exponential_backoff(max_retries=5):
    for attempt in range(max_retries):
        try:
            # 执行查询操作
            # ...
            return result  # 成功则返回结果
        except RateLimitException:
            if attempt < max_retries - 1:  # 如果不是最后一次尝试
                # 计算等待时间:2^尝试次数 + 随机数(0-1秒)
                wait_time = (2 ** attempt) + random.random()
                print(f"Rate limited, retrying in {wait_time:.2f} seconds...")
                time.sleep(wait_time)
            else:
                raise  # 达到最大重试次数,抛出异常

4.2 解析和存储查询结果

规范化数据结构

无论使用 WHOIS 还是 RDAP,都应将查询结果规范化为统一的数据结构:

def normalize_domain_data(data, source="rdap"):
    normalized = {
        "domain": "",
        "status": [],
        "created_date": None,
        "updated_date": None,
        "expiration_date": None,
        "registrar": "",
        "nameservers": [],
        "raw_data": data  # 保留原始数据以备后用
    }
    
    if source == "rdap":
        # 解析RDAP JSON数据
        normalized["domain"] = data.get("ldhName", "")
        normalized["status"] = data.get("status", [])
        
        # 解析事件日期
        for event in data.get("events", []):
            if event.get("eventAction") == "registration":
                normalized["created_date"] = event.get("eventDate")
            elif event.get("eventAction") == "expiration":
                normalized["expiration_date"] = event.get("eventDate")
            elif event.get("eventAction") == "last update":
                normalized["updated_date"] = event.get("eventDate")
        
        # 解析注册商信息
        for entity in data.get("entities", []):
            if "registrar" in entity.get("roles", []):
                normalized["registrar"] = entity.get("ldhName", "")
        
        # 解析域名服务器
        for ns in data.get("nameservers", []):
            normalized["nameservers"].append(ns.get("ldhName", ""))
    
    elif source == "whois":
        # 使用正则表达式解析WHOIS文本数据
        # ...
    
    return normalized

数据存储选项

根据查询规模和需求,可选择不同的存储方案:

  • 小规模查询:CSV 或 JSON 文件

  • 中等规模:SQLite 数据库

  • 大规模查询:PostgreSQL 或 MongoDB

示例 SQLite 模式:

CREATE TABLE domains (
    id INTEGER PRIMARY KEY,
    domain TEXT UNIQUE,
    status TEXT,
    created_date TEXT,
    updated_date TEXT,
    expiration_date TEXT,
    registrar TEXT,
    query_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE nameservers (
    id INTEGER PRIMARY KEY,
    domain_id INTEGER,
    nameserver TEXT,
    FOREIGN KEY (domain_id) REFERENCES domains(id)
);

CREATE TABLE raw_data (
    domain_id INTEGER PRIMARY KEY,
    data TEXT,
    FOREIGN KEY (domain_id) REFERENCES domains(id)
);

4.3 特殊 TLD 的处理策略

不同 TLD 的 WHOIS/RDAP 响应可能有显著差异,需要特别处理:

.ai 域名 (安圭拉)

.ai 域名的注册局不返回注册日期和到期日期,可通过以下方法估算:

  • 使用历史 WHOIS 记录 (如有)

  • 通过域名的 DNS 记录创建时间推测

  • 使用 Internet Archive 的首次抓取时间作为参考

新 gTLD

对于.app、.dev 等新 gTLD,RDAP 是首选查询方式,因为这些 TLD 从设计之初就支持 RDAP。

国家代码 TLD(ccTLD)

某些 ccTLD(如.de、.uk) 有自己的查询系统和格式,可能需要特定的适配器。

5. 域名监控与安全应用

5.1 域名到期监控系统

利用 WHOIS/RDAP 数据构建域名到期监控系统:

import datetime
import smtplib
from email.mime.text import MIMEText

def check_expiring_domains(domains, days_threshold=30):
    today = datetime.datetime.now()
    expiring_soon = []
    
    for domain in domains:
        # 查询RDAP信息
        data = query_rdap(domain)
        normalized = normalize_domain_data(data)
        
        if normalized["expiration_date"]:
            expiry_date = datetime.datetime.fromisoformat(normalized["expiration_date"].replace("Z", "+00:00"))
            days_remaining = (expiry_date - today).days
            
            if days_remaining <= days_threshold:
                expiring_soon.append({
                    "domain": domain,
                    "expiry_date": expiry_date,
                    "days_remaining": days_remaining
                })
    
    return expiring_soon

def send_expiry_notification(expiring_domains, email):
    if not expiring_domains:
        return
    
    # 构建邮件内容
    subject = f"域名到期提醒:{len(expiring_domains)}个域名即将到期"
    
    body = "以下域名即将到期,请及时续费:\n\n"
    for domain in expiring_domains:
        body += f"- {domain['domain']}: 将在{domain['days_remaining']}天后到期 ({domain['expiry_date'].strftime('%Y-%m-%d')})\n"
    
    msg = MIMEText(body)
    msg['Subject'] = subject
    msg['From'] = "noreply@example.com"
    msg['To'] = email
    
    # 发送邮件
    # ...

# 使用示例
domains = ["example1.com", "example2.com", "example3.com"]
expiring = check_expiring_domains(domains, days_threshold=45)
send_expiry_notification(expiring, "admin@example.com")

5.2 域名抢注监控

监控高价值域名的到期状态,为可能的抢注做准备:

def monitor_valuable_domains(domains_list, check_interval_days=7):
    # 读取域名列表
    with open(domains_list, 'r') as f:
        domains = [line.strip() for line in f if line.strip()]
    
    results = {}
    
    for domain in domains:
        try:
            data = query_rdap(domain)
            
            # 检查域名是否已注册
            if "errorCode" in data and data["errorCode"] == 404:
                results[domain] = "未注册,可立即注册"
            else:
                # 域名已注册,检查到期日期
                normalized = normalize_domain_data(data)
                
                if normalized["expiration_date"]:
                    expiry_date = datetime.datetime.fromisoformat(normalized["expiration_date"].replace("Z", "+00:00"))
                    today = datetime.datetime.now()
                    days_remaining = (expiry_date - today).days
                    
                    results[domain] = f"已注册,还有{days_remaining}天到期"
                else:
                    results[domain] = "已注册,到期日期未知"
        
        except Exception as e:
            results[domain] = f"查询错误: {str(e)}"
    
    return results

5.3 网络安全应用

WHOIS/RDAP 数据在网络安全领域有广泛应用:

钓鱼域名检测

检测与特定品牌相似的可疑域名:

import re
from difflib import SequenceMatcher

def detect_suspicious_domains(brand_name, tlds=["com", "net", "org"]):
    suspicious = []
    
    # 生成可能的变体
    variants = [
        brand_name,  # 完全匹配
        brand_name.replace("o", "0"),  # 字母替换为数字
        brand_name.replace("i", "1"),
        brand_name.replace("l", "1"),
        brand_name.replace("e", "3"),
        brand_name + "secure",  # 常见后缀
        brand_name + "login",
        "my" + brand_name,
        # 添加更多变体...
    ]
    
    # 检查每个变体在不同TLD下是否已注册
    for variant in variants:
        for tld in tlds:
            domain = f"{variant}.{tld}"
            
            try:
                data = query_rdap(domain)
                
                # 如果域名已注册
                if "errorCode" not in data:
                    # 获取注册日期
                    normalized = normalize_domain_data(data)
                    created_date = normalized["created_date"]
                    
                    # 如果是最近注册的域名,更可疑
                    if created_date:
                        created = datetime.datetime.fromisoformat(created_date.replace("Z", "+00:00"))
                        days_since_creation = (datetime.datetime.now() - created).days
                        
                        if days_since_creation <= 30:  # 30天内注册的域名
                            suspicious.append({
                                "domain": domain,
                                "created_date": created,
                                "days_since_creation": days_since_creation,
                                "suspicion_level": "高"
                            })
                        else:
                            suspicious.append({
                                "domain": domain,
                                "created_date": created,
                                "days_since_creation": days_since_creation,
                                "suspicion_level": "中"
                            })
            except Exception:
                # 查询失败,继续下一个
                continue
    
    return suspicious

6. 未来趋势与发展

6.1 RDAP 的全面普及

随着 ICANN 正式将 RDAP 确立为 gTLD 注册信息的权威来源,我们可以预期:

  • WHOIS 服务将在未来几年内逐步淘汰

  • 更多 ccTLD 将采用 RDAP 标准

  • RDAP 客户端工具将更加丰富和易用

6.2 隐私保护的加强

随着全球隐私法规 (如 GDPR) 的实施,域名注册信息的隐私保护将进一步加强:

  • 个人信息将默认隐藏

  • 分层访问控制将更加精细

  • 合法执法和知识产权保护需求与隐私保护之间的平衡将继续调整

6.3 API 集成与自动化

RDAP 的 JSON 格式天然适合 API 集成,未来将看到:

  • 更多域名管理平台集成 RDAP 查询

  • 自动化域名监控和安全系统的普及

  • 基于机器学习的域名分析工具

7. 总结

域名注册系统和查询协议是互联网基础设施的重要组成部分。从早期的 WHOIS 到现代的 RDAP,查询机制不断演进,以适应互联网的发展需求。随着 ICANN 宣布 RDAP 将在 2025 年 1 月 28 日成为 gTLD 注册信息的权威来源,我们正在见证一个重要的技术过渡期

对于开发者、网络管理员和域名投资者而言,掌握这些知识不仅有助于进行域名管理和监控,还能帮助识别潜在的网络安全威胁。通过本文提供的详细步骤和代码示例,读者可以构建自己的域名查询和监控系统,充分利用 WHOIS 和 RDAP 提供的信息。

随着互联网的不断发展,域名注册和查询系统也将继续演进。保持对最新标准和实践的了解,将有助于更高效地管理域名资产和保护网络安全。

参考资源