关注小编微信公众号公众号【前端基础教程从0开始】回复“1”,拉你进程序员技术讨论群,群内有大神,可以免费提供问题解答。公众号回复“小程序”,领取300个优秀的小程序开源代码+一套入门教程。公众号回复“领取资源”,领取300G前端,Java,产品经理,微信小程序,Python等资源合集大放送,让我们一起学前端。
https可以防止http劫持,但是无法防止dns劫持,因为dns劫持发生在你和web 服务器建立连接之前。
打个比方,你要#去超市买东西,dns是出租车,把你送到超市门口(web服务器),https能防止超市给你的商品里加了假货,但是你一开始就上了黑车(dns劫持)!后面的就不可能会发生了!
防止dns劫持,很难,尤其对于小运营商的用户,被劫持的概率非常大。如果你认为用户只要使用8.8.8.8或者119.29.29.29等公共dns就可以避免劫持,那说明你还没发现运营商有多险恶,他们甚至在网关处伪造dns应答,抢答了目标递归dns给你的应答。看你的提问,是站在网站服务提供者的角度来问的,那就更难了,还是上面那个例子,你作为一个超市,想要防止客人被黑车拐跑,你觉得可能吗?我提供三种思路:
第一个(我没试过),发现网站在某些地区运营商被劫持了,投诉工信部,让他们放开劫持。
第二个,选用cdn服务。大部分小运营商dns劫持,是由于你的网站流量大,而源站又在网外,他们为了避免产生高额的网间结算费用,将被网内的dns请求劫持到网内他们自己的缓存服务器集群里。如果你用了cdn,被劫持的概率会略有下降,因为cdn厂商大多节点很多,以我司为例,国内几乎无孔不入,既然都在网内,他们就不会盯上你。即使被劫持,cdn厂商凭借和小运营商良好的沟通渠道(至少我司是这样,经常一个电话或者社交软件上和对方负责人说一句就会放开了),也很容易放开劫持。
第三个,选用httpdns,利用腾讯httpDns应对dns劫持来举例:
主要有三个步骤
1、自制DNS服务器,监听127.0.0.1:53
2、修改网络连接里面的首选DNS服务器为:127.0.0.1
3、服务器收到DNS请求后,从腾讯的httpDns接口查询,再返回给请求端,接口:http://119.29.29.29/d?dn=域名
防劫持源码地址:
https://gitee.com/fz6/mobile_h5_antihijacking
代码:
import hpsocket;
import hpsocket.udpServer;
import wsock;
namespace hpsocket
class dnsServer{
ctor(initFile, dnsApp ){
this = ..hpsocket.udpServer()
if(!this){
return null;
}
this.threadGlobal = {
_dnsApp = dnsApp;
_initFile = initFile;
response = {};
request = {};
}
this.onThreadCreated = function(){
import web.json;
import hpsocket.dnsServer;
import console;
log=function(...){
console.dump(...)
}
if(_initFile){
loadcodex(_initFile)
}
response.close = function(){
if(owner.resultStr and #owner.resultStr){
hpUdpServerEx.send(connId,owner.resultStr,#owner.resultStr)
}
owner.resultStr = "";
}
response.write = function(s,...){
if( s === null ) return;
var ts = type(s);
if( ts == 'table' ){
if(s[["_struct"]]) {
if( s@[["_tostring"]] ) s = tostring(s);
}
else s = web.json.stringify(s,owner.jsonPrettyPrint);
}
elseif( (ts != 'string') && (ts != 'buffer') ){
s = tostring(s);
};
owner.resultStr ++= s;
s = null;
ts=null
if(...===null) return;
return owner.write(...);
}
response.loadcode = function(path){
loadcodex( path );
}
global.print = function(...){
response.write(...);
};
}
this.onReceive = function(hpUdpServerEx,connId,pData,length){
global.hpUdpServerEx = hpUdpServerEx;
global.connId = connId
if(_dnsApp){
request.body = ..raw.tostring(pData,1,length)
request.domains = hpsocket.dnsServer.dealDNSbyte(request.body);
response.resultStr = "";
_dnsApp(request,response);
response.close();
}
}
};
}
namespace dnsServer{
class TDNSBitCode{
Word QR=0; //Query/Response Flag
Word OpCode=0; //
Word AA=0; //Authoritative Answer Flag
Word TC=0; //Truncation Flag
Word RD=0; //Recursion Desired
Word RA=0; //Recursion Available:
Word Z=0; //Zero
Word RCode=0; //Response Code
}
class TDNSHeader{
Word ID=0; //Identifier:
Word BitCode=0; //从中分析出TDNSBitCode
Word QDCount=0;
Word ANCount=0;
Word NSCount=0;
Word ARCount=0;
}
class dns_packet{
WORD Id=0;
WORD Flags=0;
WORD Questions=0;
WORD Answers=0;
WORD Authoritys=0;
WORD Additionals=0;
}
class DnsQuery{
Word TheType=0; //记录类型 A NS CNAME
Word TheClasses=0;
}
class DnsResponse{
Word TheName=0;
Word TheType=0;
Word TheClasses=0;
INT ttl=0;
Word length=0;
INT addr=0;
}
GetDNSBitCode = function( BitCode){
var result = TDNSBitCode();
result.QR = BitCode >> 15;
result.OpCode = ((BitCode & 0x7800) >> 11) & 0x000F;
result.AA = (BitCode & 0x0700) >> 10;
result.TC = (BitCode & 0x0200) >> 9;
result.RD = (BitCode & 0x0100) >> 8;
result.RA = (BitCode & 0x0800) >> 7;
result.Z = 0;
result.RCode = BitCode & 0x000F;
return result;
}
DNSStrToDomain = function(SrcStr, Idx){
var Result = '' ;
var fRPackSize = #SrcStr;
var SavedIdx = 0;
do{
var Len = SrcStr[Idx];
while( (Len & 0xC0)==0xC0 ){
if (SavedIdx == 0){
SavedIdx = Succ(Idx)
}
var aChar = Len & 0x3F;
Idx = twoCharToWord(aChar, SrcStr[Idx + 1]) + 1;
Len := SrcStr[Idx];
}
if (Idx >= fRPackSize){
return ;
}
var LabelStr='';
if (Len > 0){
LabelStr = ..string.sub(SrcStr,Idx+1,Idx+Len);
Idx += Len+1;
}
if (Idx+1 > fRPackSize){
return ;
}
Result ++= LabelStr ++ '.';
}while(!(SrcStr[Idx] == 0 or Idx > #SrcStr))
if (Result[#Result] == '.'#){
Result = ..string.left(Result,#Result-1)
}
if (SavedIdx > 0){
Idx = SavedIdx
}
Idx++;
return Result, Idx;
}
long2str=function(src,len=2){
if(type(src)==type.number){
var bytes
if(len==2){
bytes = ..raw.convert({WORD n=src},{BYTE s[2]={}});
}elseif(len==4) {
bytes = ..raw.convert({INT n=src},{BYTE s[4]={}});
}elseif(len==8) {
bytes = ..raw.convert({LONG n=src},{BYTE s[8]={}});
}
return ..string.pack(bytes.s)//..raw.malloc(#bytes.s,bytes);
}
}
BuilderDNSResponse = function(pDnsQuery, nQueryLen, SnoopIP){
if(pDnsQuery){
var dnsr = dns_packet();
var dnslen = ..raw.sizeof(dnsr);
var dnss = dns_packet();
var queryr = DnsQuery();
var str = ..string.left(pDnsQuery,dnslen);
..raw.convert(str,dnsr);
//标识字段
dnss.Id := dnsr.Id;
//标志字段,其中设置了QR = 1,RD = 1,RA = 1
dnss.Flags := ..wsock.htons(0x8180);
//问题数量
dnss.Questions := ..wsock.htons(1);
if(type(SnoopIP)==type.table){
//回答数量
dnss.Answers := ..wsock.htons(#SnoopIP);
}else {
//回答数量
dnss.Answers := ..wsock.htons(1);
}
dnss.Authoritys := 0;
dnss.Additionals := 0;
var querylen = ..raw.sizeof(queryr);
var ulen = nQueryLen - dnslen - querylen;
var start = dnslen+ ulen
start += 1;
var dname = ..string.sub(pDnsQuery, dnslen+1, dnslen+ulen)
str = ..string.sub(pDnsQuery, start, start+3)
..raw.convert(str,queryr);
start += 4;
var responses = DnsResponse();
var responselen = ..raw.sizeof(responses)
var usBufferLen
if(type(SnoopIP)==type.table){
usBufferLen = start + responselen*#SnoopIP;
}else {
usBufferLen = start + responselen;
}
var result = ..raw.malloc(usBufferLen,dnss);
var len = dnslen;
len = ..raw.concat(result,dname,len,#dname);
var queryr1 = ..raw.malloc(queryr);
len = ..raw.concat(result,queryr1,len,#queryr1);
if(type(SnoopIP)==type.table){
for(i=1;#SnoopIP;1){
//域名指针
str = long2str(..wsock.htons(0xC00C));
len =..raw.concat(result,str,len,#str);
//0005 CNAME
str = long2str(queryr.TheType);
len =..raw.concat(result,str,len,#str);
//0001 类,表示为Internet数据
str = long2str(queryr.TheClasses);
len =..raw.concat(result,str,len,#str);
//TTL 生存时间
str = long2str(0x0000000A,4);
len =..raw.concat(result,str,len,#str);
//数据长度 127 0 0 1
str = long2str(..wsock.htons(4));
len =..raw.concat(result,str,len,#str);
//内容 127 0 0 1
str = long2str(..wsock.inet_addr(SnoopIP[ i ]),4);
len =..raw.concat(result,str,len,#str);
}
}else {
//域名指针
str = long2str(..wsock.htons(0xC00C));
len = ..raw.concat(result,str,len,#str);
//0005 CNAME
str = long2str(queryr.TheType);
len = ..raw.concat(result,str,len,#str);
//0001 类,表示为Internet数据
str = long2str(queryr.TheClasses);
len = ..raw.concat(result,str,len,#str);
//TTL 生存时间
str = long2str(0xFFFFFFFF,4);
len = ..raw.concat(result,str,len,#str);
//数据长度 127 0 0 1
str = long2str(..wsock.htons(4));
len = ..raw.concat(result,str,len,#str);
//内容 127 0 0 1
str = long2str(..wsock.inet_addr(SnoopIP),4);
len = ..raw.concat(result,str,len,#str);
}
return ..raw.tostring(result,0,len);
}
}
twoCharToWord = function(b1,b2){
return ((b1 << 8) & 0xFF00) | (b2 & 0x00FF)
}
dealDNSbyte = function(strRecvData){
var id = twoCharToWord(strRecvData[1], strRecvData[2]);
var Code = twoCharToWord(strRecvData[3], strRecvData[4]);
var BitCode = GetDNSBitCode(Code);
if( BitCode.QR != 0){return}; //0表示查询,1表示反馈
var QDCount = twoCharToWord(strRecvData[5], strRecvData[6]);
if (QDCount <= 0) {return }
var APos = 13; // DNS头恒为12字节
var DomainName
var domains = {}
for(i=1;QDCount;1){
DomainName,APos = DNSStrToDomain(strRecvData, APos);
if (!DomainName){return };
var QueryType = twoCharToWord(strRecvData[APos], strRecvData[APos + 1]);
APos += 2;
var QueryClass = twoCharToWord(strRecvData[APos], strRecvData[APos + 1]);
APos += 2;
..table.push(domains,DomainName);
}
return domains;
}
}