PHP实例:避免重复提交和检查数据来路(2)_PHP技巧_黑客防线网安服务器维护基地--Powered by WWW.RONGSEN.COM.CN

PHP实例:避免重复提交和检查数据来路(2)

作者:黑客防线网安PHP教程基地 来源:黑客防线网安PHP教程基地 浏览次数:0

本篇关键词:检查数据提交重复
黑客防线网安网讯:  请大家看代码,感觉哪里有不合理的地方,还请赐教!谢谢.    加密我是找的网上的一个方法,稍作了一下修改.    GEncrypt.inc.php:    <?php    classGEncryptextendsGSuper...
  请大家看代码,感觉哪里有不合理的地方,还请赐教!谢谢.
  
  加密我是找的网上的一个方法,稍作了一下修改.
  
  GEncrypt.inc.php:
  
  <?php
  
  classGEncryptextendsGSuperclass{
  
  protectedstaticfunctionkeyED($txt,$encrypt_key){
  
  $encrypt_key=md5($encrypt_key);
  
  $ctr=0;
  
  $tmp="";
  
  for($i=0;$i<strlen($txt);$i++){
  
  if($ctr==strlen($encrypt_key))$ctr=0;
  
  $tmp.=substr($txt,$i,1)^substr($encrypt_key,$ctr,1);
  
  $ctr++;
  
  }
  
  return$tmp;
  
  }
  
  publicstaticfunctionencrypt($txt,$key){
  
  //$encrypt_key=md5(rand(0,32000));
  
  $encrypt_key=md5(((float)date("YmdHis")+rand(10000000000000000,99999999999999999)).rand(100000,999999));
  
  $ctr=0;
  
  $tmp="";
  
  for($i=0;$i<strlen($txt);$i++){
  
  if($ctr==strlen($encrypt_key))$ctr=0;
  
  $tmp.=substr($encrypt_key,$ctr,1).(substr($txt,$i,1)^substr($encrypt_key,$ctr,1));
  
  $ctr++;
  
  }
  
  returnbase64_encode(self::keyED($tmp,$key));
  
  }
  
  publicstaticfunctiondecrypt($txt,$key){
  
  $txt=self::keyED(base64_decode($txt),$key);
  
  $tmp="";
  
  for($i=0;$i<strlen($txt);$i++){
  
  $md5=substr($txt,$i,1);
  
  $i++;
  
  $tmp.=(substr($txt,$i,1)^$md5);
  
  }
  
  return$tmp;
  
  }
  
  }
  
  ?>
  
  GToken.inc.php
  
  方法:
  
  a,granteToken参数:formName,即动作名称,key是加密/解密密钥.
  
  返回一个字符串,形式是:加密(formName:session_id)
  
  b,isToken参数:token即granteToken产生的结果,formName,动作名称,fromCheck是否检查来路,如果为真,还要判断token里的session_id是否和当前的session_id一至.
  
  c,dropToken,当成功执行一个动作后,调用这个函数,把这个token记入session里,
  
  <?php
  
  /**
  
  *原理:请求分配token的时候想办法分配一个唯一的token,base64(time+rand+action)
  
  *如果提交将这个token记录,说明这个token以经使用,可以跟据它来避免重复提交
  
  *
  
  */
  
  classGToken{
  
  /**
  
  *得到当前所有的token
  
  *
  
  *@returnarray
  
  */
  
  publicstaticfunctiongetTokens(){
  
  $tokens=$_SESSION[GConfig::SESSION_KEY_TOKEN];
  
  if(empty($tokens)&&!is_array($tokens)){
  
  $tokens=array();
  
  }
  
  return$tokens;
  
  }
  
  /**
  
  *产生一个新的Token
  
  *
  
  *@paramstring$formName
  
  *@param加密密钥$key
  
  *@returnstring
  
  */
  
  publicstaticfunctiongranteToken($formName,$key=GConfig::ENCRYPT_KEY){
  
  $token=GEncrypt::encrypt($formName.":".session_id(),$key);
  
  return$token;
  
  }
  
  /**
  
  *删除token,实际是向session的一个数组里加入一个元素,说明这个token以经使用过,以避免数据重复提交
  
  *
  
  *@paramstring$token
  
  */
  
  publicstaticfunctiondropToken($token){
  
  $tokens=self::getTokens();
  
  $tokens[]=$token;
  
  GSession::set(GConfig::SESSION_KEY_TOKEN,$tokens);
  
  }
  
  /**
  
  *检查是否为指定的Token
  
  *
  
  *@paramstring$token要检查的token值
  
  *@paramstring$formName
  
  *@paramboolean$fromCheck是否检查来路,如果为true,会判断token中附加的session_id是否和当前session_id一至.
  
  *@paramstring$key加密密钥
  
  *@returnboolean
  
  */
  
  publicstaticfunctionisToken($token,$formName,$fromCheck=false,$key=GConfig::ENCRYPT_KEY){
  
  $tokens=self::getTokens();
  
  if(in_array($token,$tokens))//如果存在,说明是以使用过的token
  
  returnfalse;
  
  $source=split(":",GEncrypt::decrypt($token,$key));
  
  if($fromCheck)
  
  return$source[1]==session_id()&&$source[0]==$formName;
  
  else
  
  return$source[0]==$formName;
  
  }
  
  }
  
  ?>
  
  示例:
  
  首先从$_POST里取出token,用isToken判断.
  
  <?php
  
  include("../common.inc.php");
  
  $token=$_POST["token"];
  
  if(GToken::isToken($token,"adminLogin",true)){
  
  $vCode=$_POST["vCode"];
  
  if(strtoupper($vCode)!=strtoupper($_SESSION[GConfig::SESSION_KEY_VALIDATE_CODE])){
  
  thrownewException("验证码不正确!");
  
  }
  
  $vo=newVO_Admin();
  
  $vo->setNickName($_POST["name"]);
  
  $vo->setPwd($_POST["pwd"]);
  
  $mo=newMO_Admin();
  
  $mo->setVO($vo);
  
  $f=$mo->login();
  
  if(!$f){
  
  thrownewException("用户名或密码不正确!");
  
  }else{
  
  GToken::dropToken($token);
  
  //header("location:".GDir::getRelativePath("/admin/index.php"));
  
  echo"here";//如果是外部提交的,这句就不会打印出来!
  
  }
  
  }
  
  $sFile=GDir::getAbsPath(GConfig::DIR_SERIALIZE,"admin/login");
  
  $tpl=GSerialize::load($sFile);
  
  if($tpl===false){
  
  $tpl=newGTpl(GConfig::DIR_SKIN,GConfig::DEBUG_TPL_FILE);
  
  $tpl->load(array(
  
  "header"=>"admin/header.html",
  
  "footer"=>"admin/footer.html",
  
  "admLogin"=>"admin/login.html",
  
  "admLoginJs"=>"admin/loginJs.html"
  
  ));
  
  GSerialize::save($tpl,$sFile);
  
  }
  
  $tpl->assign("title","管理员登陆");
  
  $tpl->assign("path",GDir::getRelativePath(SITE_DIR));
  
  $tpl->assign("vImg",GDir::getRelativePath("/vImg.php"));
  
  if(MO_Admin::isLogined()){
  
  $tpl->parseBlock("blk_logined");
  
  }else{
  
  $tpl->assign("token",GToken::granteToken("adminLogin"));
  
  $tpl->parseBlock("blk_loadScripts","cond_notLogin");
  
  $tpl->parseBlock("blk_notLogin");
  
  }
  
  echo$tpl->parse("header");
  
  echo$tpl->parse("admLogin");
  
  echo$tpl->parse("footer");
  
  echo$tpl->parse("admLoginJs");
  
  ?>
  
  这一切看着似乎是没有问题了.
  
  如果想判断是否是执行的匹配动作,可以把isToken里的formName改一下,运行,很好,没有匹配上.证明这个成功.
  
  是否能避免重复提交,我没有验证,太简单的逻辑了.
  
  余下的就是判断来路检查是否正常工作了.
  
  把上面的示例产生的htmlcopy到本地的一个网页内(以达到不同的域的目的),运行,检查来路不明,没有执行动作(需要把isToken的第三个参数设为true).
  
  把isToken的第三个参数设置为false,提交,指定的动作执行了!
  
  好了,到此为止,不知道哪个地方是否还存在BUG,这就要在长期运用中慢慢调试修改了!
  
  
    黑客防线网安服务器维护方案本篇连接:http://www.rongsen.com.cn/show-17391-1.html
网站维护教程更新时间:2012-09-21 05:18:03  【打印此页】  【关闭
我要申请本站N点 | 黑客防线官网 |  
专业服务器维护及网站维护手工安全搭建环境,网站安全加固服务。黑客防线网安服务器维护基地招商进行中!QQ:29769479

footer  footer  footer  footer