我的日常

登录/注册
您现在的位置:论坛 盖世程序员(我猜到了开头 却没有猜到结局) 盖世程序员 > discuz的cookie加密法
总共48086条微博

动态微博

查看: 1435|回复: 0

discuz的cookie加密法

[复制链接]

326

主题

72

听众

999

金钱

实习版主

该用户从未签到

优秀版主

跳转到指定楼层
楼主
发表于 2014-12-24 14:53:24 |只看该作者 |倒序浏览
一:discuz!登陆验证Cookie机制分析
5 V+ F- Z0 x/ s6 B+ n9 A- ?) g 在构建登录验证的过程中,发现管理员管理的便捷与系统安全隐患之间的矛盾.全站采用cookie验证,比如wordpress的验证就是基于cookie的,由于cookie的明文传输,在局域网内极易被截获,或者这个vita在我不发骚的情况下存在了XSS漏洞的话,cookie被人截获,在这种情况下,等于站点被人xxoo了;另一种情况就是利用session来进行管理员身份的认证,但是由于php天生对于session的处理机制的问题,不能长时间保存,利用数据库构建的session系统开销太大,在这种情况下,我就只好先研究先下大家是怎么做的,于是分析了Discuz!的登陆验证机制.每个Discuz!论坛都有一个特定的authkey也就是Discuz!程序中的$_DCACHE[’settings’][’authkey’]并且与用户的浏览器特征值HTTP_USER_AGENT一起组成了discuz_auth_key这个变量如下代码:
# O* O. }4 s7 f+ u' wcommone.inc.php文件大概130行左右; c, r" Z  I' h  C5 N
PHP代码+ v& [9 ]( y4 }
  • $discuz_auth_key = md5($_DCACHE['settings']['authkey'].$_SERVER['HTTP_USER_AGENT']);  
    9 D2 p7 P/ O8 Y. ?) M& ?, I
7 R: \9 K! H$ o$ v* `! `

在Discuz!论坛用户登陆以后会有一个cookie,名称为cdb_auth(cdb_是你站点的名称,可以设置不能在config.inc.php文件中设置),Discuz!论坛就靠这个来判断一个用户是否是登陆状态,在分析这个值的内容之前,我们看下他是如何生成的

PHP代码5 j+ j6 s" U, j; L6 ?' \
  • list($discuz_pw, $discuz_secques, $discuz_uid) = empty($_DCOOKIE['auth']) ? array('', '', 0) : daddslashes(explode("\t", authcode($_DCOOKIE['auth'], 'DECODE')), 1);
    - D  K7 o) @  z( `% y6 q  N
" {) C2 z) m  v0 q* k, i( F- u

解释一下,获得的客户端的cookie经过Discuz!的函数authcode解密以后会得到用户输入的用户名,密码,在authcode函数中会用到刚刚提到的$discuz_auth_key这个值,在不知道$discuz_auth_key的情况下,基本上靠cookie里的值反解出用户名密码的几率为0,同样的,在生成cdb_auth就是相逆的一个流程,先获得用户输入的用户名,密码,在验证正确之后,用authcode加密,写入cookie,很简单吧., w9 V3 @' S/ z1 s
以上就是Discuz!普通用户的登陆验证过程,写的不是很详细,大概能看明白就行.

二:DISCUZ COOKIE
6 p) O% J2 }% @) B1 x* B4 C6 S# _5 K: x  D3 s& j8 L% ~
很多人都在用discuz 并会因为种种的需要结合discuz做各种系统.
2 V) v% o6 f, [* p* e对此,discuz提供了通行证 可有时候使用通行证不一定适用 就比如说那一段很长很长的url吧 看着就让人心烦
4 k7 P7 L0 Y6 i: D有什么解决方法捏?为了社区朋友们以后方便开发 这几天呕心沥血 肝肠寸断 孜孜不倦 终于让偶给想出了一个比较天才的想法
' q. [5 H4 C) z:hoho 那就是生成一个discuz 验证cookie 9 `7 U) _1 l+ x- ^
废话说完了 开始正题: 7 S5 w3 K1 p: s9 u3 J3 y
开始之前 咱先了解一下discuz的登陆机制  
6 I- L0 [5 \: g9 `" |先来一个简单的form

XML/HTML代码9 u7 K) F$ X" }$ D/ B. o
  • <form action='i_login.php'>   
  •   
  • user:<input  name='username' type='text'>   
  •   
  • password:<input name='password' type='password'>   
  •   
  • <input type='submit' value='login'>   
  •   
  • </form>   
    % z: S$ B9 ?; h+ n

. w8 P  A# A- H, T0 P2 ?' y0 o

OK,一个很实用的登录框已经完成。。。
2 U# G7 u  j+ d2 _& s下面 说下php方面的 我们假设改文件和discuz同一目录里
5 \0 D" F8 {+ o" G& m看代码 6 H/ [2 I0 K9 e. Q* d% c" H
i_login.php

PHP代码; N( o5 }( M. W3 V4 R* n
  • <?php   
  • /**  
  •   * 加载discuz的入口文件 当然你也可以不加 不过你得提出几个必要的函数  
  • */   
  •   
  •   require_once './include/comon.inc.php';   
  •   
  •   $formUsername = trim($username); // 接受POST传来的$username
  •   $formPassword = trim($password); // 接受POST传来的$password
  •   
  • /**
  •   *  说下secques
  •   *  secques是论坛里的安全回答经过编码后提取的一段字符 虽然我们登陆的时候不会用到它
  •   *  但是生成COOKIE呢 它还是不可或缺滴
  • */
  •   $query = $db->query("SELECT uid,password,secques FROM cdb_members WHERE username='$formUsername'");   
  •   $member = $db->fetch_array($query);   
  •   
  •   // 验证用户密码是否匹配
  •   
  •   if($member['password'] == md5($formPassword))
  •   {
  •   // 已经验证用户密码都是匹配的 下面比较关键的就是生成cookie了 可要仔细看好了    
  •   /*
  •    先说下dsetcookie函数  这是dz的一个设置cookie的函数 可以在include/global.func.php里查看
  •    通常只需要三个参数即可 第一个为cookie键 第二个为键值 第三个为cookie有效时间 这里我就随便设置一个
  •    再说 authcode 此为加密函数,俺一直用这个函数,很强大,很难破解,有兴趣的朋友也可在include/global.func.php里
  •    找到该函数,研究一下
  •   */
  •   dsetcookie('sid','',-2423234234); // 注销掉sid
  •   dsetcookie('auth', authcode("$formPassword\t$member['secques']\t$member['uid']", 'ENCODE'), '1234243');   
  •   // OK 关键步骤 我们都已经完成了 下面就由你写一个header跳转到论坛首页看是否登陆了 我本地测试可以 你有问题的话那可就是    
  •   // RPWT了(人品问题)~~
  •   header("location:/index.php");
  •   }
  •   else
  •   {
  •   // 我们这里返回一个错误信息 告诉那个用户密码错误
  •   }
  • ?> : v7 D' b- _& V3 s1 U3 i" u

3 E  ~, w4 d/ z" ^. ~6 r

好 一个简单的登陆验证就完成了  
- A6 i: c3 `, Q- r+ K6 `( f7 ?+ E如果你不想加载common.inc.php文件的话 你需要提取 , M" z) j2 ~3 M$ h. t( r) j7 N
authcode 和dsetcookie函数 都比较简单哈  
" R$ H" |' Z; c( E2 u& l2 gOK 我们继续说下discuz验证部分 没兴趣的可以跳过去 ( m! F+ e4 d% J1 ~
验证部分 在common.inc.php 大约119行 开始

PHP代码
  M; V/ N, E7 }* ~, [/ p" c
  • // 拆解COOKIE auth   
  •   
  • list($discuz_pw, $discuz_secques, $discuz_uid) = isset($_DCOOKIE['auth']) ? explode("\t", authcode($_DCOOKIE['auth'], 'DECODE')) : array('', '', 0);   
  •   
  • $discuz_pw = addslashes($discuz_pw);   
  •   
  • $discuz_secques = addslashes($discuz_secques);   
  •   
  • $discuz_uid = intval($discuz_uid);   
  •   
  • // 不存在$_DCOOKIE['auth']的话 就直接清楚COOKIE    
  •   
  • if(isset($_DCOOKIE['auth']) && !$discuz_uid) {   
  •   
  • clearcookies();   
  •   
  • }   
  •   
  • $newpm = $newpmexists = $sessionexists = $seccode = $bloguid = 0;   
  •   
  • if($sid) {   
  •   
  •       //存在$discuz_uid的话 根据uid取出用户信息 否则根据sid    
  •   
  • if($discuz_uid) {   
  •   
  •   // 取用户信息    
  •   
  • } else {   
  •   
  •   // 用sessions表中取用户信息    
  •   
  • }   
  •   
  • // 下面就是验证了 我不写了 (sid是用户的一个sessionid 用户登陆后会在sessions表内生成一条用户记录 用户推出后该记录删除  7 ^5 T1 |) p! `

! L+ r( a$ G2 \" Q3 k+ j: Q
三:Discuz 用户信息加密算法-authcode加密/解密函数详解
/ Q# G( L8 V- B6 T; H5 k+ S. M# v/ d+ T' u$ W; y
Discuz论坛是国内广泛使用的开源论坛,论坛的安全体系构筑严谨,尤其是对用户信息加密的部分。) W& q) q+ ?/ r0 o9 r% {  o( B2 U9 `4 K
    用户信息包括用户名、密码、所属组别等,这些信息经过加密并保存在Cookie里面 ,服务器端读取Cookie信息,并解迷。% h9 u$ F$ l4 E6 h. k
    作为对比,国内另一个基于Perl的论坛-----雷傲BBS,早期版本中,用户名以明文形式保存在Cookie里,密码经过一次md5加密后保存在Cookie里。这样,万一论坛存在跨站漏洞,或其他方式导致管理员密码信息泄露,会对论坛构成威胁。4 k* y9 ~- j; Y4 W* o( Q1 B' p# q
    用户信息的加密解密都是在一个函数中实现的,函数定义为:
PHP代码
# a& u% I8 K% P" ~) l# s+ U  ?
  • /**  
  • *用户信息加密解密函数  
  • *  
  • *待加密内容用\t分割  
  • *@return String 加密或解密字符串  
  • *@param String $string 待加密或解密字符串  
  • *@param String $operation 操作类型定义 DECODE=解密 ENDODE=加密  
  • *@param String $key 加密算子  
  • */  
  •   
  • function authcode($string, $operation, $key = '') {   
  •   
  • /**
  • *获取密码算子,如未指定,采取系统默认算子  
  • *默认算子是论坛授权码和用户浏览器信息的md5散列值  
  • *$GLOBALS['discuz_auth_key']----全局变量  
  • *取值为:md5($_DCACHE['settings']['authkey'].$_SERVER['HTTP_USER_AGENT'])  
  • *$_DCACHE['settings']['authkey']是论坛安装时生成的15位随机字符串  
  • */  
  •   
  •     $key = md5($key ? $key : $GLOBALS['discuz_auth_key']);   
  •   
  •     $key_length = strlen($key);   
  •   
  • /**
  • *如果解密,先对密文解码  
  • *如果加密,将密码算子和待加密字符串进行md5运算后取前8位  
  • *并将这8位字符串和待加密字符串连接成新的待加密字符串  
  • */  
  •   
  •     $string = $operation == 'DECODE' ? base64_decode($string) : substr(md5($string.$key), 0, 8).$string;   
  •   
  •     $string_length = strlen($string);   
  •   
  •     $rndkey = $box = array();   
  •   
  •     $result = '';   
  •   
  •   
  •   
  • /**
  • *初始化加密变量,$rndkey和$box  
  • */  
  •   
  •     for($i = 0; $i <= 255; $i++) {   
  •   
  •         $rndkey[$i] = ord($key[$i % $key_length]);   
  •   
  •         $box[$i] = $i;   
  •   
  •     }   
  •   
  •   
  •   
  • /**
  • *$box数组打散供加密用  
  • */  
  •   
  •     for($j = $i = 0; $i < 256; $i++) {   
  •   
  •         $j = ($j + $box[$i] + $rndkey[$i]) % 256;   
  •   
  •         $tmp = $box[$i];   
  •   
  •         $box[$i] = $box[$j];   
  •   
  •         $box[$j] = $tmp;   
  •   
  •     }   
  •   
  •   
  • /**
  • *$box继续打散,并用异或运算实现加密或解密  
  • */  
  •   
  •     for($a = $j = $i = 0; $i < $string_length; $i++) {   
  •   
  •         $a = ($a + 1) % 256;   
  •   
  •         $j = ($j + $box[$a]) % 256;   
  •   
  •         $tmp = $box[$a];   
  •   
  •         $box[$a] = $box[$j];   
  •   
  •         $box[$j] = $tmp;   
  •   
  •         $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));   
  •   
  •     }   
  •   
  •     if($operation == 'DECODE') {   
  •   
  •         if(substr($result, 0, 8) == substr(md5(substr($result, 8).$key), 0, 8)) {   
  •   
  •             return substr($result, 8);   
  •   
  •         } else {   
  •   
  •             return '';   
  •   
  •         }   
  •   
  •     } else {   
  •   
  •         return str_replace('=', '', base64_encode($result));   
  •   
  •     }   
  •   
  • }  & w2 E+ k. m7 |# M( @+ x* X

' a* D3 Q( R" s* F& I- j

科帮网 1、本主题所有言论和图片纯属会员个人意见,与本社区立场无关
2、本站所有主题由该帖子作者发表,该帖子作者与科帮网享有帖子相关版权
3、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和科帮网的同意
4、帖子作者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任
5、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
6、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除并致以最深的歉意
7、科帮网管理员和版主有权不事先通知发贴者而删除本文


JAVA爱好者①群:JAVA爱好者① JAVA爱好者②群:JAVA爱好者② JAVA爱好者③ : JAVA爱好者③

快速回复
您需要登录后才可以回帖 登录 | 立即注册

   

关闭

站长推荐上一条 /1 下一条

发布主题 快速回复 返回列表 联系我们 官方QQ群 科帮网手机客户端
快速回复 返回顶部 返回列表