先端の暗号化は、Firefoxを使用して復号化されます
テキストを使用して(CC-BY-NC-ND)は非商用で再現することができ、この記事では、変更することはできません
保険では、2.0の実装は、暗号化された送信処理が必要になるなど、APPや携帯電話のブラウザの多くは、徐々に、次のようなパケットとしてこの問題を解決するためのいくつかの暗号化対策を、暗号化
何を読んおろかデータを変更されていないものをちんぷんかんぷんの束、。。それが行うことになっていますか?私たちは、次のは、Firefoxに基づいて説明することで、私は個人的にFirefoxのを好む、Firefoxの、クロムなどを使用することができます。
1、トリガーボタン
デバッガCTRL + F12を開いた後、デバッガにした後、ページがメインのログインページ機能モジュールがトリガされたように見える、カスタムによると、一般的なlogin.jsをすべてのjsをロードします更新します。
私たちは、ボタンをトリガするページに戻ります。これは、すべてのフロントエンドの操作は、結合事象に基づいています。JSは、イベント駆動型の言語である、あなたが悪いのブラウザメモリー++を書くと、当然のことながら、これは余談で、閉鎖の多くがあるでしょう。それはイベント駆動型であるため、そのような検出の動作にいくつかのロジックを定義する(「クリック」コールバック(){})は、多くのfunction.onが存在するであろう。
私たちは、まず、このような選択し、「保存」と「送信」ボタンまたは同様、彼の右をクリックすると、そのボタンの上に開始する必要があります「の表示要素を。」Firefoxは急速にもあるため問題の位置付けに層状のリードをCSSが、これは重要ではありません、いくつかの使用が急速に重要な要素を見つける方法を知っている、我々はまた、HTMLの説明ではまだ、もちろん、この要素の近くでHTML構造にナビゲートします私は、JSの一部を説明するために開始されませんでした。
そして、イベントをクリックして、我々はすぐに、次のチャートとして、ボタンをクリックした後、コードのイベント・ロジック・ブロックに移動します
あなたがクリック上記と同じ時間に、つまり、バブリングイベントイベントされ、次の二つをバインドするには、このボタンのクリックイベントを見ることができ、ここでのクリックがトリガされます。これはおそらく、コードがあるべきであるトリガー
$(「#のbuttion_id」)。(クリック機能を(){...}赤い部分は、我々は、コードボックスにクリックイベントを開くべきであるということです)、私はすべてのコードのステッカーを置きます。
以下代码是基于jquery的,要看懂的话需要一些基础,我讲的尽可能简单,让大家都可以快速明白。
1 function() { 2 if (!$(this).prop('disabled')) { 3 var mobilenum = /^(13[0-9]|15[0-9]|16[0-9]|17[013678]|18[0-9]|19[0-9]|14[57])[0-9]{8}$/; 4 var mob = $('.row input').eq(3).val().replace(/\s/g, '') 5 if (!mobilenum.test(mob)) { 6 $('#modal-error').modal('show').children('.error-content').children('.modal-body').html('请输入有效的手机号'); 7 return; 8 } 9 if (needImg) { 10 $('#modal-input').modal('show'); 11 $('#modal-input .msg-code-img').eq(0).click(); 12 var $_input = $('#modal-input input')[0]; 13 setTimeout(function() { 14 $_input.focus(); 15 }, 500); 16 } else { 17 var params = { 18 'MOBILE': $('.row input').eq(3).val().replace(/\s/g, '') 19 }; 20 getPhoneCode(params); 21 } 22 } 23 }
最主要我们看17-20行的代码,构造了一个对象传入到getPhoneCode函数中,params的参数就是手机的参数 并且处理一定逻辑。
2、调试JS,下断点
接来下我们去搜索getPhoneCode(params)函数。
我们通过全局查找快速定位到这个函数的位置。
1 function getPhoneCode(params) { 2 if (!$('#msg-btn').prop("disabled")) { 3 $('#msg-btn').prop("disabled", true); 4 params['ajaxUrl'] = "/user2/sendSmsCode"; 5 params['ajaxCallBack'] = function (data) { 6 if (data.MSG_CODE == 0) { 7 if (data.MESSAGE_CODE) { 8 $('.msg-code-input').val(data.MESSAGE_CODE); 9 checkNull(); 10 } 11 /*if (show_input) { 12 $('.tel-code-row').show(); 13 }*/ 14 $(".msg-code-img:not('#modal-input .msg-code-img'):last").click(); 15 time($('#msg-btn')); 16 return; 17 } else if (data.MSG_CODE == '102') { 18 if ($('.tel-code-row').css('display') == 'none') { 19 alerterror('您的失败次数过多<br/>请输入图片验证码'); 20 $('.tel-code-row').show(); 21 } else { 22 alerterror('图片验证码输入错误'); 23 } 24 if (typeof show_input != 'undefined' && !show_input) { 25 show_input = true; 26 } 27 } else { 28 alertfail(); 29 } 30 $('#msg-btn').prop("disabled", false); 31 } 32 submitAjax(params); 33 } 34 }
32行之前都是一些逻辑和判断的代码 和我们想要调试的没关系,4-5行是把一些信息包装进了params参数中,最终通过32行的submitAjax函数来执行,我们继续跟踪这个函数 ,方法和上面一样,全局搜索这个方法
submitAjax函数的定义如下:
1 //提交数据 2 var submitAjax = function (dataObject) { 3 var ajaxUrl = UC_URL + dataObject.ajaxUrl 4 delete dataObject.ajaxUrl 5 var ajaxCallBack = dataObject.ajaxCallBack; 6 delete dataObject.ajaxCallBack; 7 dataObject.CHNLID = dataStore.getItem("CHNLID"); 8 dataObject.BACKURL = unescape(Base64.decode(dataStore.getItem("backUrl"))); 9 dataObject.VERSION = "1.32"; 10 if (null != dataObject.BACKURL) { 11 dataObject.BACKURL = getDomain(dataObject.BACKURL); 12 } 13 if (null == dataObject.CHNLID && null == dataObject.BACKURL) { 14 dataObject.CHNLID = 'SF'; 15 dataObject.BACKURL = location.host; 16 } 17 var JsonParams = JSON.stringify(dataObject); 18 var rsaCommit = function (JsonParams) { 19 var RSAParams = RSAUtils.encryptedString(rsaKey, JsonParams); 20 $.ajax({ 21 type: "POST", 22 cache: false, 23 dataType: "json", 24 url: ajaxUrl, 25 contentType: 'text/plain', 26 data: RSAParams, 27 ...82 }
去掉了一些不重要的代码,我们主要来看dataObject参数。我们先对这个地方下个断点
然后我们回到页面,填写好手机号,点击“获取验证码”,让代码跑起来。
我们可以看到dataObject参数就2个属性,然后继续往下跟,在Json.stringfy之前下断点,因为最后加密的函数是第19行,RSAUtils.encryptedString(rsaKey, JsonParams);
其实有经验的同学可以直接在这里下断点查看,这里的rasKey是没有定义的,只有这个JsonParams,而 JsonParams就是刚才的dataObject对象的json序列化。
我们可以看到,在变成json格式之前,程序加入了一些其他的参数,这个不重要。接下来我们下断点到 RSAUtils.encryptedString函数。然后来看rsaKey参数是什么,鼠标移上去显示是undefined..
因为代码只var rsaKey,并没赋值任何。。。不知道程序员在想什么,这个类的加密string方法显然是需要一个加密的key的,也就是私钥,其实这个程序有一个密钥,不过不是这个函数里的
所以其实前端加密来阻止参数修改没意义的。。
3、构造参数
最后我们需要理解上面的流程和逻辑
- 获取需要的参数比如mobile,版本等信息
- json序列化
- 加密
- 发送至服务端
最后的代码是
1 var my = {MOBILE:"15*******",CHNLID:"SF",BACKURL:"*****.com.cn",VERSION:"1.32"}; 2 var data = JSON.stringify(my); 3 var rsaKey; 4 RSAUtils.encryptedString(rsaKey, data);
最后得出的值是
我们再和直接用burpsuite抓到的值对比下
其他的一些思考
基本上就结束了,接来下我们可以构造任何我们想要的值来替换掉传输,因为至此我们可以构造任何想要的参数来篡改。
其实换个思路,我们可以编写一些插件(其实已经有类似的插件) ,例如早起的Tamper Data 插件之类的,或者自己写脚本引入,在一些关键代码之前反射出对象的全部属性.
从程序员角度来看,我们可以看到他有好几个加密方法,有的传了密钥,有的没有。而且代码都是部分混淆,部分没有,其实提高一下门槛的话,应该把login.js之类的 也混淆了。虽然这种混淆对我这样的安全工程师没什么用,但是waf不也是这样的思路吗?
把全部的js混淆了不仅可以压缩代码的字符数,减少服务器压力和带宽,还可以提高安全的门槛,增加破解难度,在交互中多次传输一些长度很高的token,迷惑安全人员,再使用一些js和浏览器的hack技术,使得门槛可以非常高。 比如这些js的奇怪特性。