Maison  >  Article  >  Applet WeChat  >  Analyse du code JS dans la connexion au code QR WeChat

Analyse du code JS dans la connexion au code QR WeChat

PHPz
PHPzoriginal
2017-04-02 14:17:252298parcourir

Dans de nombreux endroits, il existe des applications telles que la connexion par code QR, le paiement par code QR, le compte par code QR (le goujon du code QR ici, sans parler de la fraude), la vérification du code QR, le multi-terminal Il existe de plus en plus d'applications d'autorisation auxiliaires . Parlons d'abord de ce qu'est un code QR. En fait, un code QR est un code noir et blanc qui stocke des données binaires Photos, lorsqu'un code QR est requis pour se connecter, le serveur générera une information de code QR unique temporaire et l'enverra au client avec le code QR (image) Rédigez le formulaire sur la page Web, puis vous verrez un code QR unifié à quatre carrés. Si c'est bien fait, les informations du code QR devraient être sensibles au temps. Nous ne les considérerons pas pour le moment. Prenons une simple connexion WeChat comme une simple connexion. exemple. Jetons un coup d'œil,

Parlons d'abord de l'ensemble du processus d'autorisation :

Après que la page Web du client enverra en continu des connexions https au serveur, et très peu de données seront transmises ici La connexion est déconnectée. Jetons un coup d'œil au fichier login1c709c.js dans la page Web WeChat :

(function($, _aoWin) {
_aoWin.QRLogin = {};
  _aoWin.LoginLog = "";
 var _sBaseHost = "",
    _oLoginQrCodeImg = document.getElementById("loginQrCode");
 if (document.domain == "qq.com") {
 _sBaseHost = "weixin.qq.com";
 } else if(location.hostname.match(/(wechat\.com)$/)){
 _sBaseHost = "wechat.com";
 }else{
    _sBaseHost = "wechatapp.com";
  }
 
 var show_tip = 1,
 _sCurUUId,
 _oResetTimeout,
    _aWebMMCallbacks = [],
    _oDetactWebMMInterval = setInterval(function(){
      if(_aoWin.WebMM){
        clearInterval(_oDetactWebMMInterval);
        var callback;
        while(callback = _aWebMMCallbacks.shift()){
          if(typeof(callback) != "function") continue;
          callback();
        }
      }
    }, 1000);

function _logInPage(_asLog){
    _aoWin.LoginLog = LoginLog + _asLog + "\n";
  }
 
  function _afterLoadWebMMDo(callback){
    if(!_aoWin.WebMM){
      _aWebMMCallbacks.push(callback);
    }else{
      callback();
    }
  }
 
  function _reportNow(text){
    _logInPage(text);
    _afterLoadWebMMDo(function(){
      WebMM.ossLog({Text: text});
      WebMM.flushOssLog();
    });
  }
 
  var reLoadQRImgCount = 0,
    loadQRCodeTime = 0,
    loadQRImgSucc = function(){
      clearInterval(loadQRImgWatchDog);
      _logInPage("Load QRCode Success, time=" + (new Date().getTime() - loadQRCodeTime) + "ms, reload count: " + reLoadQRImgCount);
    },
    loadQRImgFail = function(img){
      _reportNow("Load QRcode fail!" + status + ", src: " + img.src + ", time: " + (new Date().getTime() - loadQRCodeTime) + "ms");
    },
    loadQRImgWatchDog = null;
 function _loadQRImg(uuid) {
    _poll(uuid);
    _logInPage("Load QRCode Start");
    loadQRCodeTime = new Date().getTime();
 
    _oLoginQrCodeImg.onload = function(){
      loadQRImgSucc();
      _oLoginQrCodeImg.onload = null;
    };
    _oLoginQrCodeImg.onerror = function(){loadQRImgFail(this)};
    _oLoginQrCodeImg.src = "https://login."+_sBaseHost+"/qrcode/"+uuid+"?t=webwx";
 
    loadQRImgWatchDog = setInterval(function(){
      if (reLoadQRImgCount >= 5) {
        _reset();
        return;
      }
      reLoadQRImgCount++;
 
      var _img = new Image();
      _img.onload = function () {
        if(!_oLoginQrCodeImg.onload) return;
 
        _oLoginQrCodeImg.onload = null;
        _oLoginQrCodeImg.src = this.src;//replace
        loadQRImgSucc();
      };
      _img.onerror = function(){loadQRImgFail(this)};
      _img.src = _oLoginQrCodeImg.src + "&r=" + new Date().getTime();
    }, 5000);
  }
 
  var _sSecondRequestTime = 0,
    _nAjaxTimeout = 100 * 1000,
    _nNewLoginFuncErrCount = 0;
 function _poll(_asUUID) {
 var _self = arguments.callee,
      _nTime = 0;
 _sCurUUId = _asUUID;
 
    _logInPage("_poll Request Start, time: " + new Date().getTime());
    _nTime = new Date().getTime();
 $.ajax({
 type: "GET",
 url: "https://login." + _sBaseHost + "/cgi-bin/mmwebwx-bin/login?uuid=" + _asUUID + "&tip=" + show_tip,
 dataType: "script",
 cache: false,
 timeout: _nAjaxTimeout,
 success: function(data, textStatus, jqXHR) {
      _logInPage("_poll Request Success, code: " + window.code + ", time: " + (new Date().getTime() - _nTime) + "ms");
  switch (_aoWin.code) {
  case 200:
   _sSecondRequestTime = new Date().getTime() - _sSecondRequestTime;
        _logInPage("Second Request Success, time: " + _sSecondRequestTime + "ms");
  clearTimeout(_oResetTimeout);
 
        var _fNewLoginFunc = function(){
          $.ajax({
            url: _aoWin.redirect_uri + "&fun=new",//new login page
            type: "GET",
            success:function(msg) {
              _logInPage("new func reponse, reponseMsg: " + msg);
              var code = msg.match(/<script>(.*)<\/script>/);
              var skey=msg.match(/<skey>(.*)<\/skey>/);
              if(code){
                eval(code[1]);
              }else{
                $("#container").show();
                $("#login_container").hide();
              }
              if(skey && skey[1]){
               WebMM.model("account").setSkey(skey[1]);
              }
            },
            error:function(jqXHR, textStatus, errorThrown){
              _nNewLoginFuncErrCount++;
              if(_nNewLoginFuncErrCount > 5){
                if(confirm("Call new login page func error, refresh?")){location.reload()}
                return;
              }
              _reportNow(_aoWin.redirect_uri + " New login page func error: " + textStatus +" retryCount:" + _nNewLoginFuncErrCount);
              setTimeout(_fNewLoginFunc, 500);
            }
          });
        };
        _fNewLoginFunc();
 
        _reportNow("/cgi-bin/mmwebwx-bin/login, Second Request Success, uuid: " + _asUUID + ", time: " + _sSecondRequestTime + "ms");
  break;
 
  case 201:
        clearTimeout(_oResetTimeout);
  show_tip = 0;
  $(&#39;.errorMsg&#39;).hide();
  $(&#39;.normlDesc&#39;).hide();
  $(&#39;.successMsg&#39;).show();
        _reportNow("/cgi-bin/mmwebwx-bin/login, First Request Success, uuid: " + _asUUID);
        _reportNow("/cgi-bin/mmwebwx-bin/login, Second Request Start, uuid: " + _asUUID);
 
        _sSecondRequestTime = new Date().getTime();
 
        //_nAjaxTimeout = 5 * 1000;
        _self(_asUUID);
        break;
 
  case 408:
  setTimeout(function(){
   _self(_asUUID);
  }, 500);
  break;
 
  case 400:
  case 500:
        _reset();
        _afterLoadWebMMDo(function(){
   _aoWin.Log.d("500, Login Poll Svr Exception");
  });
  break;
  }
 },
 error: function(jqXHR, textStatus, errorThrown) {
  if (textStatus == &#39;timeout&#39;) {
        setTimeout(function(){
          _self(_asUUID);
        }, 500);
  } else {
        setTimeout(function(){
          _self(_asUUID);
        }, 5000);
 
        _logInPage("_poll Request Error:" + textStatus);
        _afterLoadWebMMDo(function(){
          _aoWin.Log.e("Login Poll Error:" + textStatus);
        });
  }
 }
 });
 }

var getUUIDCount = 0,
    _getUUIDWatchDog,
    _bGetUUIDSuccess = false;//ajax successִ
 function _getUUID() {
    getUUIDCount++;
    var _self = arguments.callee,
      _loadError = function(errorText){
        _reportNow("Load UUID Error! ErrorText: " + errorText + " getUUIDCount=" + getUUIDCount);
        if(getUUIDCount > 5){
          if (confirm("Load uuid error. Refresh?")) {
            location.reload();
          }
        }
        setTimeout(function(){
          _self();
        }, 500);
      };
 
    clearTimeout(_getUUIDWatchDog);
    _getUUIDWatchDog = setTimeout(function(){
      if(!_aoWin.QRLogin.code){
        _logInPage("GetUUID Timeout, WatchDog Run");
        _self();
      }
    }, 10000);
    
        $.ajax({      
          type: "GET",      
          url: "https://login." + _sBaseHost + "/jslogin?appid=wx782c26e4c19acffb&redirect_uri="+encodeURIComponent(location.protocol+"//"+location.host+"/cgi-bin/mmwebwx-bin/webwxnewloginpage")+"&fun=new&lang=" + document.lang,
           dataType: "script",
      cache: false,
      success : function(){
        clearTimeout(_getUUIDWatchDog);
        if(_bGetUUIDSuccess) return;
        if (_aoWin.QRLogin && _aoWin.QRLogin.code == 200) {
          _logInPage("GetUUID Success, UUID=" + QRLogin.uuid);
          _bGetUUIDSuccess = true;
 
          clearTimeout(_oResetTimeout);
          _oResetTimeout = setTimeout(function(){
            location.reload();//Note: Don&#39;t run _reset(). If you run _reset(), there will may have many _poll request, as they get 408 return code
          }, 5 * 60 *1000);//5 mins
 
          _loadQRImg(QRLogin.uuid);
        } else {
          var QRLoginCode = (_aoWin.QRLogin && _aoWin.QRLogin.code) ? _aoWin.QRLogin.code : "None";
          _logInPage("GetUUID Error, QRLogin.code=" + QRLoginCode);
          _loadError("QRLogin.code= " + QRLoginCode);
        }
      },
      error : function(xhr, textStatus, errorThrown){
        _logInPage("GetUUID Error, textStatus=" + textStatus);
        _loadError(textStatus);
      }
    });
 }
 
  function _reset(){
    location.reload();
  }
 
 if ($("#login_container").is(":visible") ) {
    _getUUID();
 }
 
  
 var _bHadLog = false;
 function _ossLog() {
 if (_bHadLog) return;
 _bHadLog = true;
 var _sUvid = document.cookie.match(new RegExp( "(^| )"+"webwxuvid"+"=([^;]*)(;|$)"));
    if(!_sUvid || _sUvid.length < 3) return;
    _sUvid = _sUvid[2];
 (new Image()).src = "/cgi-bin/mmwebwx-bin/webwxstatreport?funkey=indexdemo&uvid="+_sUvid+"&uuid="+_sCurUUId;
 }
 
 
 if($("img.guide").length > 0) {
 var _nTimer = 0,
  _oGuide$ = $(".guide"),
  _oGuideTrigger$ = $("#guideTrigger, #tipTrigger"),
  _oMask$ = $(".mask");
 
  function _back() {
  _nTimer = setTimeout(function() {
  _oMask$.stop().animate({opacity:0}, function(){$(".mask").hide()});
  _oGuide$.stop().animate({marginLeft:"-120px",opacity:0}, "400", "swing",function(){
   _oGuide$.hide();
  });
  }, 100);
 }
 
 /*guide*/
 _oGuide$.css({"left":"50%", "opacity":0});
 _oGuideTrigger$.css({"backgroundColor":"white", "opacity":"0"});
 _oGuideTrigger$.mouseover(function(){
  clearTimeout(_nTimer);
  _oMask$.show().stop().animate({"opacity":0.2});
  _oGuide$.css("display", "block").stop().animate({marginLeft:"+168px", opacity:1}, 900, "swing", function() {
  _oGuide$.animate({marginLeft:"+153px"}, 300);
  });
  _ossLog();
 }).mouseout(_back);
 
 _oGuide$.mouseover(function(){
  clearTimeout(_nTimer);
 }).mouseout(_back);
 }
})(jQuery, window);

Après avoir lu attentivement le js, vous le ferez. voir la requête du client web. Côté connexion, le client web lance une requête SSL au serveur toutes les 500 millisecondes pour demander si le code QR actuel est autorisé par d'autres clients (téléphones mobiles). cela signifie que le même terminal qui a scanné le code QR a été obtenu. S'il existe d'autres circonstances, la demande sera à nouveau envoyée après 500 millisecondes supplémentaires. Ce processus se poursuivra jusqu'à ce que le code QR soit scanné ou que le code QR expire (expire). ). Les outils utilisés incluent : l'outil de capture de paquets Fidller, l'outil de développement Chrome F12. Notez que le client WeChat dispose d'un min-webmm1cba21.js, dans lequel la spécification du filtre XSS est clairement visible .

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn