缘起

随着国内网络环境的持续恶化,各种篡改和劫持层出不穷,越来越多的网站选择了全站 HTTPS。HTTPS 通过 TLS 层和证书机制提供了内容加密、身份认证和数据完整性三大功能,可以有效防止数据被查看或篡改,以及防止中间人冒充。

在可见的未来,HTTP2 只在 HTTPS 环境下被支持,iOS9 要求应用程序必须采用 HTTPS 传输,升级HTTPS迫在眉睫。

实现

大概8-9月份的时候,在前端leader的主导,运维协助的情况下,M站已经基本完成HTTPS的升级;有了上次的技术摸底,这次APP全部升级HTTPS就显得顺风顺水了很多;接下来是今天的重点:测试静态资源https可用性检测。

静态资源https可用性检测

需求

对静态资源https的支持程度做统计

  1. 记录IP粒度的地域信息;

  2. 对所有域名(静态文件所有域名)进行测试;

  3. 劫持,内容是否一致;

分析

需求1中提到的记录IP粒度的地域信息,在服务器端很容易就能获取到;

需求2和3需要前端提供每个域名下的返回状态,以接口的方式传给后端,和1整合后统一存入数据库中

前端实现方案

  1. 图片所有域名需要返回加载状态

  2. js或css文件所有域名需要返回加载状态外,还需要对比是否被劫持

  3. 图片和js统一返回状态

  4. 将返回状态存入data中,以便后端调用

返回所有域名下js文件访问状态

function returnJsStatus(callback) {
    var domainStatus = {},
	domain = ['static01', 'static02'],
	i;
    for (i = 0; i < domain.length; i = i + 1) {
	var xhr = new XMLHttpRequest();
	xhr.open('GET','https://' + domain[i] + '.zepto/1.0.0/zepto.min.js');
	xhr.onload = (function (index) {
	    return function () {
		if (xhr.responseText.length !== 25768) {
		    domainStatus[domain[index]] = -200;
		} else {
		    domainStatus[domain[index]] = xhr.status;
		}

		if (count(domainStatus) === domain.length) {
		    callback(domainStatus);
		}
	    }
	})(i);
	xhr.send();
    }
}

返回所有域名下同一张图片访问状态

function returnImgStatus(callback) {
    var domainStatus = {},
	imgArr = [],
	domain = ['pic01', 'pic02', 'pic03', 'pic04', 'pic05'],
	i;
    for (i = 0; i < domain.length; i = i + 1) {
	imgArr[i] = new Image();
	imgArr[i].src = 'https://' + domain[i] + './img/default-avatar.png';
	imgArr[i].onload = (function (index) {
	    return function () {
		domainStatus[domain[index]] = 200;
		if (count(domainStatus) === domain.length) {
		    callback(domainStatus);
		}
	    }
	})(i);
	imgArr[i].onerror = (function(index){
	    return function () {
		domainStatus[domain[index]] = 404;
		if (count(domainStatus) === domain.length) {
		    callback(domainStatus);
		}
	    }
	})(i);
    }
}

将以上返回状态,存入data中,方便后端调用

var data = {};

function result () {
    if (data.js && data.img) {
	console.log(data);
	//最终返回的结果格式如下:
	/*
	{
	img:{ pic01: XXX, pic02: XXX, pic03: XXX, pic04: XXX, pic05: XXX },
	js:{ static01: XXX, static02: XXX }
	}
	*/
    }
}

function init() {
    returnJsStatus(function (status) {
	data.js = status;
	result();
    });
    returnImgStatus(function (status) {
	data.img = status;
	result();
    });
}
init();

上面用到的获取对象长度的方法

function count(o){
    var t = typeof o,
	n,
	i;
    if (t === 'object') {
	n = 0;
	for(i in o){
	    n++;
	}
	return n;
    }
    return false;
}; 

当然最终返回的数据格式需要和后端合作人员确定api后,转成对应格式,配合使用

升级HTTPS可参考如下:

HTTPS 改造初探

启用 HTTPS 过程中,如何与一些新出的安全规范配合使用

前端静态文件如何应对HTTPS的到来