域名数字证书安全漫谈(4)-假冒证书、DNS劫持、钓鱼攻击

2022-06-02 15:22:23 浏览数 (1)

以往,钓鱼网站都是采用跟目标网站相似的域名,这种情况下,钓鱼网站完全可以使用自己申请的证书,直接通过关键词竞价排名等手段将流量吸引过来,达到欺骗用户的目的。这类网站稍加留意,即可发现破绽。

那么有没有使用完全相同的域名,通过自签发的假冒证书,配合DNS劫持进行钓鱼攻击的网站呢?

在常见的Web网站类业务场景,主流的浏览器都会主动校验服务器证书的合法性,如果证书存在异常,浏览器会给出警告,提醒用户不要继续浏览该网站。所以,这类证书域名相同需要用户交互的钓鱼场景比较少见。

那么在不需要用户交互的情况下,有没有使用完全相同的域名,通过自签发的假冒证书,配合DNS劫持进行钓鱼攻击的后台服务器呢?

先给答案:有。

移动APP的后台,一般不需要用户交互,通常以Web Service的形式和移动APP客户端交互数据。鉴于此,一种非常隐蔽的钓鱼攻击开始出现,即通过假冒证书,配合DNS劫持,冒充移动APP的后台服务器,执行钓鱼攻击。

伪造证书 DNS劫持的钓鱼后台

下面自签发ROOT根证书和一张假冒的saas.janusec.com证书,配合DNS劫持(使用修改hosts的方式模仿真实的DNS劫持),进行浏览测试(访问的是被劫持后的地址):

可以看到,使用Chrome浏览器浏览被劫持的https网站时,浏览器会给出警告。

查看证书,可以看到这张自签发证书的路径和详细信息(而真实的网站证书是从合法的CA机构采购的):

那么问题来了,如果是APP中的代码去访问,结果会怎样?

同样简单测试一下(以脚本为例,移动APP原理相同):

首先使用Python脚本中常用的urllib库,去获取被劫持的https://saas.janusec.com的内容

代码语言:javascript复制
>>> import urllib
>>> f=urllib.urlopen('https://saas.janusec.com')
>>> firstline=f.readline()
>>> firstline
'Hijacked!'
>>> 

上述代码是获取https://saas.janusec.com返回的第一行。

在浏览器中,忽略警告,继续浏览,看看结果是否一致:

可以看到,返回的代码和忽略浏览器警告后返回的代码完全一致。

上述代码所获得的结果表示,用这张自签发的假冒的证书成功的实施了欺骗。

再看urllib2的情况

代码语言:javascript复制
>>> import urllib2
>>> response = urllib2.urlopen('https://saas.janusec.com')
>>> html = response.read()
>>> html
'Hijacked!'
>>> 

urlkib2也不会主动校验服务侧证书的合法性,得到的也是被劫持的结果。

可见,对于这种不使用浏览器访问的场景,在业务过程中,建立连接的过程是代码自己完成的。如果您所使用的代码或第三方库函数在请求https资源的时候,未对目标网站的数字证书进行校验,则业务过程存在被钓鱼的可能,且用户没有任何感知(看不到风险提示)。

可能被钓鱼网站劫持的典型场景:

  • 移动APP(iOS、Android等应用)、PC客户端应用、客户端脚本等,连接后台服务器(https web service);
  • 内置在客户端应用中的自开发Web组件(如果不校验证书合法性);
  • B2B业务集成,己方服务器需要访问对方的Web Service。

事实上,目前的绝大部分移动APP都没有主动去校验服务侧证书的合法性

估计也只有等到某几个著名的APP被劫持并被曝光之后才会引起大家的重视。

如何校验证书是否合法?

如果您的APP所使用的网络连接库函数未校验服务侧证书,则需要程序员自行编写代码来完成校验。

数字证书是依赖根证书的信任传递机制的,所以验证一张数字证书的合法性,需要其上级证书参与进来进行验证。除了根证书,每一张数字证书都包含了其上级证书对其的签名,也就是用上级证书的私钥对证书摘要(简记为H1)进行加密。

除了上面提到的自签发假冒证书,还有伪造证书的场景(2008年出现了伪造的使用MD5签名哈希算法的数字证书,使用SHA1作为签名哈希算法的伪造证书目目前虽未发现,但业界估计快了)。

验证数字证书合法性的方法总结为:

  • 验证根证书是否为受信任的根证书;(必须,根证书是信任的基础,如果根证书有问题,应直接拒绝)
  • 验证根证书是否为公司指定的根证书颁发机构所颁发的;(建议高安全级别的应用启用,理论上不排除另一家受信任的根证书厂商的代理机构,由于失误或测试用途,向某个域名所有者之外的其他人,错误的颁发了该域名的证书,并用于测试目的)
  • 验证证书链中每一张数字证书用上级证书公钥解密后的证书摘要(H1)是否与基于证书内容重新计算得出的摘要(H2)一致;(必须,防止伪造,由于根证书为自签名证书,使用自己的公钥解密来验证)
  • 验证最后一级证书的Common name是否跟访问的域名一致;(必须)
  • 验证证书是否在有效期内及证书是否被吊销。(建议高安全级别的应用启用,消除证书泄密的风险)

一般来说,建议高安全等级的应用在和服务侧建立连接的时候,采取上述全部步骤进行验证,其它字段的验证根据业务实际,也可酌情验证(比如代表组织名称的O字段)。

普通的应用可以适当降低标准,但也必然会导致漏洞,要分析存在的漏洞是否会给业务带来损失。

如果只校验最后一级证书(即域名证书)而不校验根证书,很轻易的就可以绕过(因为该证书是自签发的,颁给谁,域名和组织名等信息都是可以自行填写的)。

总结:在存在网络劫持的情况下,客户端应用(含手机客户端)在与服务器建立业务联系之前,验证服务器证书的合法性非常有必要,希望能够引起各公司的重视,特别是移动APP开发人员。

0 人点赞