阿里云Whois域名解析开发

个人博客地址:阿里云Whois域名解析开发
微信公众号:Code技术资讯,每日为你带来各种开发/运维干货。


由于最近在做一个域名监控网站,需要用到whois功能,于是通过调用阿里云提供的API,用java开发了一套Whois解析功能,本文主要描述开发的过程以及遇到的一个大坑!
注:从2018年5月开始,受欧盟最新《通用数据保护条例》影响,阿里云Whois已不能查询到域名注册人的相关信息,本文解析Whois结果时未做修改,仅供参考。

什么是Whois?

阿里云:通过 WHOIS 查询,可以了解到域名背后的拥有者或拥有机构,获取域名注册联系信息,包括注册人、管理者和技术联系人等信息,还能够提供该域名的注册商信息(比如阿里云)、域名状态和其他重要日期(注册日期、过期日期等)。
WHOIS 域名查询通常被用于多种法律相关的查询目的。网络管理者通过 WHOIS 数据来认定和确定问题。
例如,WHOIS 信息可以用来判断域名用途是否合规,商标是否侵权,追踪生产违法内容或参与网络诈骗的域名注册者。
此外,ICANN 的协议也声明要保护域名注册人的利益,禁止他人利用 WHOIS 信息来自动判断并向特定注册局或注册商的用户名单,推送营销、诈骗信息或发送大量垃圾信息等行为。为了避免您的信息被其他人获取,您还可以开启域名隐私保护服务。

作者:简单来说,就是每个域名在注册之后都会被记录下域名拥有者的相关信息以及域名的注册信息等等,而whois就是用来查询域名的这些信息的。(未备案的域名可以开启域名保护功能,此时whois中是查不到的。)
Whois查询-中国万网

我们今天要做的,就是在我们的网站上集成whois功能。

阿里云Whois API

阿里云官方API请点击:阿里云whois 开发文档,下面摘取API部分主要内容。

请求方式
http://alidns.aliyuncs.com/?Action=DescribeDomainWhoisInfo
&DomainName=example.com
&<公共请求参数>
公共请求参数

公共请求参数是指每个接口都需要使用到的请求参数。

名称 类型 是否必须 描述
Format String 返回值的类型,支持JSON与XML。默认为XML
Version String API版本号,为日期形式:YYYY-MM-DD,本版本对应为2015-01-09
AccessKeyId String 阿里云颁发给用户的访问服务所用的密钥ID
Signature String 签名结果串,关于签名的计算方法,请参见 签名机制
SignatureMethod String 签名方式,目前支持HMAC-SHA1
Timestamp String 请求的时间戳。日期格式按照ISO8601标准表示,并需要使用UTC时间。格式为YYYY-MM-DDThh:mm:ssZ 例如,2015-01-09T12:00:00Z(为UTC时间2015年1月9日12点0分0秒)
SignatureVersion String 签名算法版本,目前版本是1.0
SignatureNonce String 唯一随机数,用于防止网络重放攻击。用户在不同请求间要使用不同的随机数值
返回参数
名称 类型 描述
RequestId String 唯一请求识别码
StatusList DomainStatusType 域名状态列表
DnsServers DnsServerType 域名当前使用的DNS列表
RegistrantName String 所有者
RegistrantEmail String 所有者联系邮箱
Registrar String 注册商
RegistrationDate String 注册日期
ExpirationDate String 到期日期
返回示例

XML格式

<DescribeDomainWhoisInfoResponse>
    <RequestId>536E9CAD-DB30-4647-AC87-AA5CC38C5382</RequestId>
    <RegistrantName>Alibaba Cloud Computing Ltd.</RegistrantName>
    <RegistrantEmail>dnsadmin@hk.alibaba-inc.com</RegistrantEmail>
    <Registrar>MARKMONITOR INC.</Registrar>
    <RegistrationDate>28-sep-2007</RegistrationDate>
    <ExpirationDate>28-sep-2016</ExpirationDate>
    <StatusList>
        <Status>clientDeleteProhibited</Status>
        <Status>clientTransferProhibited</Status>
        <Status>clientUpdateProhibited</Status>
    </StatusList>
    <DnsServers>
        <DnsServer>A.IANA-SERVERS.NET</DnsServer>
        <DnsServer>B.IANA-SERVERS.NET</DnsServer>
    </DnsServers>
</DescribeDomainWhoisInfoResponse>

JSON示例

{
    "RegistrantName": "Alibaba Cloud Computing Ltd.",
    "RegistrantEmail": "dnsadmin@hk.alibaba-inc.com",
    "Registrar": "MARKMONITOR INC.",
    "RegistrationDate": "28-sep-2007",
    "ExpirationDate": "28-sep-2016",
    "StatusList": {
        "Status": [
            "clientDeleteProhibited",
            "clientTransferProhibited",
            "clientUpdateProhibited"
        ]
    },
    "DnsServers": {
        "DnsServer": [
            "A.IANA-SERVERS.NET",
            "B.IANA-SERVERS.NET"
        ]
    }
}

java调用API

1、请求参数的构建

首先创建请求参数集合,将API中需要的参数都放进去:

public class DNSUtils {
  private static Logger logger = Logger.getLogger("DNS");
  public static Map<String, Object> getWhois(String domainName) throws UnsupportedEncodingException, SignatureException {
        //字典序排序
    Map<String, Object> map = new TreeMap<String, Object>();
    map.put("Action", "DescribeDomainWhoisInfo");
    map.put("DomainName", domainName);
    map.put("Format", "json");
    map.put("Version", "2015-01-09");  // 选择API版本,由于只发现了这一个可用的版本号,就用了这个版本
    map.put("SignatureNonce", UUID.randomUUID().toString());
    map.put("SignatureVersion", "1.0");
    map.put("SignatureMethod", "HMAC-SHA1");
    map.put("AccessKeyId", "XXX");  // 此ID为阿里云提供的AccessKeyId
    String now = DateUtils.formatISO8601Date(new Date());
    map.put("Timestamp", now);
    ......
  }
}

上面用到的AccessKeyId是阿里云所提供,如何获取请点击:如何获取AccessKey ID和AccessKey Secret
Timestamp时间戳使用的是ISO8601日期,需要进行日期格式的转换:

/**
   * 获取ISO8601日期
   *
   * @param date
   * @return
   */
  public static String formatISO8601Date(Date date) {
    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
    df.setTimeZone(new SimpleTimeZone(0, "GMT"));
    return df.format(date);
  }

2、数字签名(Signature)的生成

数字签名是API请求的参数之一,生成签名也是访问API最为复杂的一步。数字签名生成规则请参考:签名机制
java生成签名代码:

  //字典序排序
    Map<String, Object> map = new TreeMap<String, Object>();
    map.put("Action", "DescribeDomainWhoisInfo");
    map.put("DomainName", domainName);
    map.put("Format", "json");
    map.put("Version", "2015-01-09");  // 选择API版本,由于只发现了这一个可用的版本号,就用了这个版本
    map.put("SignatureNonce", UUID.randomUUID().toString());
    map.put("SignatureVersion", "1.0");
    map.put("SignatureMethod", "HMAC-SHA1");
    map.put("AccessKeyId", "XXX");  // 此ID为阿里云提供的AccessKeyId
    String now = DateUtils.formatISO8601Date(new Date());
    map.put("Timestamp", now);
    /********** 以下过程为生成数字签名过程 **********/
    // url参数序列化
    String urlParams = CommonUtils.formDataOrderSerialize(map);
    String encodeUrlParam = URLEncoder.encode(urlParams, "utf-8");
    // 阿里云算法修正,解决TimeStamp冒号被转义成%253A的问题。
    // 这是个大坑,阿里云自己的算法在进行encode字符串时,冒号被错误的转换成了%253A,正确应为%3A,导致发送请求时总是提示失败!
    // 最终还是靠着本博主坚强的毅力一个字符一个字符对出来的。此处只能将错就错,把%3A替换为%253A,这样才能和阿里云的计算结果对上号。
    encodeUrlParam = encodeUrlParam.replaceAll("%3A", "%253A");
    logger.info("Whois解析:" + domainName);
    String tosign = "POST" + "&" + "%2F" + "&" + encodeUrlParam;
    String hmacSHA1 = SignatureUtils.hmacSHA1Base64(tosign, "DxgPChG1Z6D8mVV72Yc2hmhjoKnuoi&").trim();
    String signature = URLEncoder.encode(hmacSHA1, "utf-8");
    map.put("Signature", signature);

表单参数序列化:

/**
   * 表单参数序列化(依据阿里云的规则)
   *
   * @param formMap
   * @return
   */
  public static String formDataOrderSerialize(Map<String, Object> formMap) throws UnsupportedEncodingException {
    if (formMap != null && formMap.isEmpty()) {
      return null;
    }
    TreeMap<String, Object> orderedMap = new TreeMap<>();
    for (String key : formMap.keySet()) {
      orderedMap.put(key, formMap.get(key));
    }
    String result = formDataSerialize(orderedMap);
    return result;
  }

基于SHA1算法,计算签名HMAC值

public class SignatureUtils {

  private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";

  /**
   * Computes RFC 2104-compliant HMAC signature. * @param data The data to be
   * signed.
   *
   * @param key The signing key.
   * @return The Base64-encoded RFC 2104-compliant HMAC signature.
   * @throws java.security.SignatureException when signature generation fails
   */
  public static String hmacSHA1Base64(String data, String key)
      throws java.security.SignatureException {
    String result;
    try {

      // get an hmac_sha1 key from the raw key bytes
      SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(),
          HMAC_SHA1_ALGORITHM);

      // get an hmac_sha1 Mac instance and initialize with the signing key
      Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
      mac.init(signingKey);

      // compute the hmac on input data bytes
      byte[] rawHmac = mac.doFinal(data.getBytes());

      // base64-encode the hmac
      result = Base64.encode(rawHmac);

    } catch (Exception e) {
      throw new SignatureException("Failed to generate HMAC : "
          + e.getMessage());
    }
    return result;
  }
}

3、发送请求

String responseStr = HttpUtils.sendPost("https://alidns.aliyuncs.com/", CommonUtils.formDataSerialize(map), null);
    logger.debug("result:" + responseStr);
    HashMap<String, Object> resultMap = new HashMap<>();
    try {
      JSONObject domainInfoJson = JSON.parseObject(responseStr);
      resultMap.put("RegistrantEmail", domainInfoJson.get("RegistrantEmail"));
      resultMap.put("RegistrantName", domainInfoJson.get("RegistrantName"));
      resultMap.put("Registrar", domainInfoJson.get("Registrar"));
      resultMap.put("RegistrationDate", domainInfoJson.get("RegistrationDate").toString());
      resultMap.put("ExpirationDate", domainInfoJson.get("ExpirationDate").toString());
    } catch (Exception e) {
      logger.error("whois解析异常:" + e.getMessage());
    }
return resultMap;

发送请求并解析返回字符串,最终得到一个包含域名whois新的map,然后处理下,在页面上展示就OK了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,924评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,781评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,813评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,264评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,273评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,383评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,800评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,482评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,673评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,497评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,545评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,240评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,802评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,866评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,101评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,673评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,245评论 2 341

推荐阅读更多精彩内容

  • 点击查看原文 Web SDK 开发手册 SDK 概述 网易云信 SDK 为 Web 应用提供一个完善的 IM 系统...
    layjoy阅读 13,634评论 0 15
  • 转载自公众号:freebuf 前言 前段时间,看了一本书名为《Kali Linux 渗透测试的艺术》,我发现书中第...
    苍简阅读 1,860评论 0 8
  • 来源:《Detecting APT Malware Infections Basedon Malicious DN...
    Threathunter阅读 10,685评论 3 9
  • 去年有段时间得空,就把谷歌GAE的API权威指南看了一遍,收获颇丰,特别是在自己几乎独立开发了公司的云数据中心之后...
    骑单车的勋爵阅读 20,421评论 0 41
  • 一辈子那么长,我才不会只喜欢你一个人呢!一辈子那么长,没想到我真的只喜欢你一个人! “我喜欢你”“可我不喜欢你”“...
    曦轮阅读 192评论 0 0