"短信轟炸機",是別人通過爬蟲或者其他抓取手段在網路上收集那些公司平台短信業務接口的一個集成程序,可能只需要輸入一個手機號,對方一整天都會收到各大平台的注冊或提醒短信,就是手機在那里響個不停。因為現在手機只能對單方的多條短信進行屏蔽,而這種是多平台同時進行發送,很難攔截。
而被他們收集接口的乙方公司,可能一天短信的消耗量就比過一周的量,造成公司財產損失。其實相比以前我們遇到的被刷“提現”接口可以直接獲取金錢,刷短信接口的行為,開始我很是想不通,就單純為了消耗別人公司的短信費,他也得不到什么好處,為什么要這樣做。當時也沒想對方是出於什么理由,只是先把短信接口重新整改,防止的手法在下面介紹。
這種行為我也是最近才了解,原來網上也存在像周星馳電影"整蠱專家"的人,收取別人的錢開展對自己客戶提供的人進行騷擾等業務,而短信就是其中一種,網上還有通過輸入手機號,對方手機一天全部是陌生人來電的“呼死你”軟件,心理承受力差的可能就抑郁,好點的話至少一天的心情都不好。
我們公司現在短信的用處主要還是注冊/登陸驗證碼,找回密碼,綁銀行卡,修改支付密碼,所以一天的量並不大。但那一天充了錢,不出幾分鍾,直接刷到沒有,還好發現的早,解決的也早。
解決方法,在PC端可以在發短信驗證碼時,加上圖形驗證碼校驗,最好是要能和用戶互動的,比如拖動或算術的,因為如果是靜態的圖形驗證也不是很安全,畢竟現在的圖片識別接口也很多。而在移動端,加圖形驗證體驗不是很好,可以和前端通過約定密鑰實現,而在H5上,就很尷尬了,而且還遇到一個只有必須繞彎路的事情。
一,APP端
1.IP和手機號黑名單(ip的例子)
<?php $Ip = $request->ip(); $Iplist = ['180.137.97.10']; if (in_array($Ip, $Iplist)) { return $this->sendError(1, '業務限流', 200); }
2.限制指定的user_agent
<?php $string = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0"; if ($Agent == $string) { return $this->sendError(1, '業務限流', 200); }
3.限制多久后才能發
(1).獲取指定鍵的一個緩存是否存在,存在則返回 $is_msgtime = cache($mobile.'_msgtimes'); if (!empty($is_mesgtime)) { return $this->sendError(1, '60秒后才能繼續發', 200); } (2).在短信發送成功時,存下該鍵名,並緩存60秒(按需求指定時間) cache($mobile.'_msgtimes', 1, 60);
4.限制單號單日發送的個數限制
(1)獲取緩存指定鍵名的值為多少(number),並與最大限制比較
$Daytimes = intval(cache($mobile.'_daytimes')) ? intval(cache($mobile.'_daytimes')) : 0; if(Daytimes>3) { return ^^^^^^^^^ } (2)短信發送成功記錄並累加該號該日發送量 if ($Daytimes > 0) { $nextday = strtotime("today") + 24 * 60 * 60; $expires = $nextday - time(); Cache::set($mobile.'_daytimes', $Daytimes + 1, $expires); } else { $nextday = strtotime("today") + 24 * 60 * 60; $expires = $nextday - time(); Cache::set($mobile.'_daytimes', 1, $expires); }
以上部分是沒用,因為ip和手機號,user_agent都可以通過特殊手段偽造,並且上面只是對單號碼進行攔截,所以問題就是別人通過很多號碼對接口請求,這樣一樣的可以刷。
5.接口添加復雜性,增加簽名請求等方式
(1).請求接口時,除了手機號參數,還需帶上簽名(一個不可逆加密方式處理的字符串,前后端約定一個key),和時間戳.
(2).后端根據約定的key和手機號也做相應的加密與傳過來的簽名匹配,並和時間戳和當前服務器時間做比較,時間戳最好也作為簽名加密,加密方式多種,不管是DES,RSA還是MD5看個人。
$timestamp = input('get.timestamp') ? input('get.timestamp') : 0; // 時間戳 $sign = input('get.app_sign') ? input('get.app_sign') : ''; // 請求簽名 $terminal = input('get.term') ? input('get.term') : ''; // 終端標識 1.app 2.web $veryify_code = mt_rand(100000, 999999); // 6位數的驗證碼 $priKey = "paobuqianjinzhf..20181029"; // 加密秘鑰 // 判斷終端 if(!empty($terminal) && ($terminal == 'app')) { $signAuth = md5($priKey.$mobile.$timestamp); if($timestamp > time()+10 || $timestamp<time()-60*10) { return $this->sendError(1, '請求已過期', 200); } if($sign != $signAuth) { return $this->sendError(1, '簽名匹配失敗', 200); }
短語短信發送,最好用一張表記錄一下,不管成功與否,以后查起來也方便,到底這接口發了哪些號碼,什么時候發的等等
二,H5端
在h5上,上面的通過key撒鹽的方式傳參就行不通了,因為網頁可以查看代碼,如果把key放在前端傳上來,可以看的很清楚。但是可以在后端生成一個串分配到網頁請求的時候傳上來就可以啊,就想表單令牌一樣。但是我們這個H5是純靜態,沒有后台程序,接口都只是跨域ajax請求。所以分配字符串到頁面行不通,通過接口請求簽名也行不通,因為別人抓到了這些接口,還是一樣的可以通過一樣的方式實現一遍。無奈只能通過圖形驗證碼。
<?php /** * Created by PhpStorm. * User: Administrator * Date: 2018/10/29 0029 * Time: 16:15 */ namespace Admin\Controller; use Think\Controller; use Think\Verify; // 驗證碼類 use Admin\Model; class RegisterController extends Controller // 控制器:用戶登錄 { // 登陸控制器的入口函數 public function index() { $this->redirect('Admin/Register/userRegister'); } // 用戶注冊界面 public function userRegister() { // $parm=I('get.'); $ajax = new AjaxController(); $this->assign('loginurl', $ajax->getAjaxUrl('ajaxuserloginexe')); $token=md5('paobuqianjinzhf..20181029'.time()); $this->assign('token',$token); $this->display('user_register'); } // 生成登陸驗證碼 public function verfyCode() { $config = array( 'fontSize' => 50, // 驗證碼字體大小 'length' => 4, // 驗證碼位數 //'useNoise' => false, // 關閉驗證碼雜點 ); $Verify = new \Think\Verify($config); $Verify->entry(); } // 檢測驗證碼 public function checkVerifyCode() { $code = I('code'); $mobile = I('mobile'); $term = 'app'; $timestamp =time(); $prikey='paobuqianjinzhf..20181029'; $app_sign = md5($prikey.$mobile.$timestamp); if (empty($mobile)){ $result_data['state'] = 0; $result_data['string'] = '手機號必填寫'; returnjsontojs($result_data); } if(!check_verify($code,false)) { $result_data['state'] = 0; $result_data['string'] = '驗證碼不正確'; returnjsontojs($result_data); } $Agent = $_SERVER['HTTP_USER_AGENT']; // $url ="http://www.api.com/v1/ThirdParty/sendMsg?mobile=".$mobile.'&term='.$term.'&app_sign='.$app_sign.'×tamp='.$timestamp; $url ="https://api.runmoneyin.com/v1/ThirdParty/sendMsg?mobile=".$mobile.'&term='.$term.'&app_sign='.$app_sign.'×tamp='.$timestamp; // $url ="https://api.runmoneyin.com/v1/ThirdParty/sendMsg?mobile=".$mobile; $curl = curl_init(); //設置抓取的url curl_setopt($curl, CURLOPT_URL, $url); //設置頭文件的信息作為數據流輸出 curl_setopt($curl, CURLOPT_HEADER, 1); //設置獲取的信息以文件流的形式返回,而不是直接輸出。 // curl_setopt($curl,CURLOPT_USERAGENT,$Agent); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); //執行命令 $data = curl_exec($curl); $body=''; $result_data['state'] = false; if (curl_getinfo($curl, CURLINFO_HTTP_CODE) == '200') { $headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE); $header = substr($data, 0, $headerSize); $body = json_decode(substr($data, $headerSize),true); } //關閉URL請求 curl_close($curl); if ($body['error']==0){ $result_data['state'] = true; } $result_data['string']=$body['message']; returnjsontojs($result_data); } }
![]()
以上我是在另一個系統下放了那個H5頁面,因為靜態頁面也無法做圖形驗證碼,獲取驗證碼時先判斷圖形驗證碼是否正確,正確再通過CURL請求真正的短信接口,跟APP一樣的請求方式傳參。
但是這個進行到后面卻發現,我們那個H5頁面的地址已經做了固定域名二維碼並打印了上萬張,現在把H5的地址換掉的話,也就是域名變了,也就意味着那些打印的二維碼全都沒用了,於是想到一個辦法: 在原來靜態H5的地址,加上一個訪問a.html會默認訪問a.php,然后在a.php做一個跳轉,跳轉到我們修改圖形驗證碼的域名就可以了,這樣還是訪問原來的地址,但是會重定向到新系統的地址。因為我們只是對a.html起效,其他同目錄的b.html不做處理,如果是在服務器上做重定向,整個域名下的都會被重定向,
1.在a.html目錄下新建a.php,並新建一個.htaccess文件
2.對a.html的服務器能支持支持.htaccess
打開apache安裝目錄下的httpd.conf文件,把
AllowOverride None 改為AllowOverride All ,如圖

去掉下面的注釋 #
LoadModule rewrite_module modules/mod_rewrite.so,如圖

3.htaccess文件修改為
<IFMODULE mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule (.*)\a.html$ $1\a.php [QSA,PT,L]
</IFMODULE>
個人公眾號:ZERO開發

