SRCMS·轻响应V1.6正式版

修复外部报告的多个严重安全缺陷
This commit is contained in:
Martin Zhou
2016-01-26 14:09:59 +08:00
parent e650f04553
commit f46a67c7ec
31 changed files with 924 additions and 114 deletions

View File

@@ -1,11 +1,170 @@
<?php
//<2F><><EFBFBD>ı<EFBFBD>XSS<53><53><EFBFBD><EFBFBD>
function waf($arr)
{
$ra=Array('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/','/<script/i','/javascript:/i','/vbscript:/i','/expression/i','/applet/','/meta/','/xml/','/blink/','/<link/i','/<embed/i','/<object/i','/frame/i','/iframe/i','/layer/','/title/','/bgsound/','/base/','/onload=/i','/onunload=/i','/onchange=/i','/onsubmit=/i','/onreset=/','/onselect=/i','/onblur=/i','/onfocus=/i','/onabort=/i','/onkeydown=/i','/onkeypress=/i','/onkeyup=/i','/onclick=/i','/ondblclick=/i','/onmousedown=/','/onmousemove=/i','/onmouseout=/i','/onmouseover=/i','/onmouseup=/i','/onunload=/i','/alert/i','/<input/i');
$value = preg_replace($ra,'',$arr);
echo $value;
/**
* PHP <20><><EFBFBD>ı<EFBFBD>XSS<53><53><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*
* @package XssHtml
* @version 1.0.0
* @link http://phith0n.github.io/XssHtml
* @since 20140621
* @copyright (c) Phithon All Rights Reserved
*
*/
class XssHtml {
private $m_dom;
private $m_xss;
private $m_ok;
private $m_AllowAttr = array('title', 'src', 'href', 'id', 'class', 'style', 'width', 'height', 'alt', 'target', 'align');
private $m_AllowTag = array('a', 'img', 'br', 'strong', 'b', 'code', 'pre', 'p', 'div', 'em', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'table', 'ul', 'ol', 'tr', 'th', 'td', 'hr', 'li', 'u');
/**
* <20><><EFBFBD><EFBFBD><ECBAAF>
*
* @param string $html <20><><EFBFBD><EFBFBD><EFBFBD>˵<EFBFBD><CBB5>ı<EFBFBD>
* @param string $charset <20>ı<EFBFBD><C4B1><EFBFBD><EFBFBD>룬Ĭ<EBA3AC><C4AC>utf-8
* @param array $AllowTag <20><><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD>ǩ<EFBFBD><C7A9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EBB1A3>Ĭ<EFBFBD>ϣ<EFBFBD>Ĭ<EFBFBD><C4AC><EFBFBD>Ѻ<EFBFBD><D1BA>Ǵ󲿷ֹ<F3B2BFB7><D6B9>ܣ<EFBFBD><DCA3><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>Σ<EFBFBD>ձ<EFBFBD>ǩ
*/
public function __construct($html, $charset = 'utf-8', $AllowTag = array()){
$this->m_AllowTag = empty($AllowTag) ? $this->m_AllowTag : $AllowTag;
$this->m_xss = strip_tags($html, '<' . implode('><', $this->m_AllowTag) . '>');
if (empty($this->m_xss)) {
$this->m_ok = FALSE;
return ;
}
$this->m_xss = "<meta http-equiv=\"Content-Type\" content=\"text/html;charset={$charset}\"><nouse>" . $this->m_xss . "</nouse>";
$this->m_dom = new DOMDocument();
$this->m_dom->strictErrorChecking = FALSE;
$this->m_ok = @$this->m_dom->loadHTML($this->m_xss);
}
/**
* <20><><EFBFBD>ù<EFBFBD><C3B9>˺<EFBFBD><CBBA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
public function getHtml()
{
if (!$this->m_ok) {
return '';
}
$nodeList = $this->m_dom->getElementsByTagName('*');
for ($i = 0; $i < $nodeList->length; $i++){
$node = $nodeList->item($i);
if (in_array($node->nodeName, $this->m_AllowTag)) {
if (method_exists($this, "__node_{$node->nodeName}")) {
call_user_func(array($this, "__node_{$node->nodeName}"), $node);
}else{
call_user_func(array($this, '__node_default'), $node);
}
}
}
$html = strip_tags($this->m_dom->saveHTML(), '<' . implode('><', $this->m_AllowTag) . '>');
$html = preg_replace('/^\n(.*)\n$/s', '$1', $html);
return $html;
}
private function __true_url($url){
if (preg_match('#^https?://.+#is', $url)) {
return $url;
}else{
return 'http://' . $url;
}
}
private function __get_style($node){
if ($node->attributes->getNamedItem('style')) {
$style = $node->attributes->getNamedItem('style')->nodeValue;
$style = str_replace('\\', ' ', $style);
$style = str_replace(array('&#', '/*', '*/'), ' ', $style);
$style = preg_replace('#e.*x.*p.*r.*e.*s.*s.*i.*o.*n#Uis', ' ', $style);
return $style;
}else{
return '';
}
}
private function __get_link($node, $att){
$link = $node->attributes->getNamedItem($att);
if ($link) {
return $this->__true_url($link->nodeValue);
}else{
return '';
}
}
private function __setAttr($dom, $attr, $val){
if (!empty($val)) {
$dom->setAttribute($attr, $val);
}
}
private function __set_default_attr($node, $attr, $default = '')
{
$o = $node->attributes->getNamedItem($attr);
if ($o) {
$this->__setAttr($node, $attr, $o->nodeValue);
}else{
$this->__setAttr($node, $attr, $default);
}
}
private function __common_attr($node)
{
$list = array();
foreach ($node->attributes as $attr) {
if (!in_array($attr->nodeName,
$this->m_AllowAttr)) {
$list[] = $attr->nodeName;
}
}
foreach ($list as $attr) {
$node->removeAttribute($attr);
}
$style = $this->__get_style($node);
$this->__setAttr($node, 'style', $style);
$this->__set_default_attr($node, 'title');
$this->__set_default_attr($node, 'id');
$this->__set_default_attr($node, 'class');
}
private function __node_img($node){
$this->__common_attr($node);
$this->__set_default_attr($node, 'src');
$this->__set_default_attr($node, 'width');
$this->__set_default_attr($node, 'height');
$this->__set_default_attr($node, 'alt');
$this->__set_default_attr($node, 'align');
}
private function __node_a($node){
$this->__common_attr($node);
$href = $this->__get_link($node, 'href');
$this->__setAttr($node, 'href', $href);
$this->__set_default_attr($node, 'target', '_blank');
}
private function __node_embed($node){
$this->__common_attr($node);
$link = $this->__get_link($node, 'src');
$this->__setAttr($node, 'src', $link);
$this->__setAttr($node, 'allowscriptaccess', 'never');
$this->__set_default_attr($node, 'width');
$this->__set_default_attr($node, 'height');
}
private function __node_default($node){
$this->__common_attr($node);
}
}
function waf($data)
{
$xss = new XssHtml($data);
$html = $xss->getHtml();
echo $html;
}
?>

View File

@@ -17,7 +17,7 @@ class LoginController extends Controller {
//登陆验证
public function login(){
if(!IS_POST)$this->error("非法请求");
$member = M('member');
$member = M('manager');
$username =I('username');
$password =I('password','','md5');
$code = I('verify','','strtolower');
@@ -32,12 +32,12 @@ class LoginController extends Controller {
$this->error('账号或密码错误 :(') ;
}
//验证账户是否被禁用
if($user['status'] == 0){
$this->error('账号被禁用,请联系超级管理员 :(') ;
}
if($user['type'] == 1){
$this->error('您没权限登陆后台 :(') ;
}
//if($user['status'] == 0){
//$this->error('账号被禁用,请联系超级管理员 :(') ;
//}
//if($user['type'] == 1){
//$this->error('您没权限登陆后台 :(') ;
//}
//验证是否为管理员
//更新登陆信息
$data =array(
@@ -55,7 +55,7 @@ class LoginController extends Controller {
$ip = get_client_ip();
$time = date("Y-m-d h:i:sa");
$con='您好,您的后台管理账户 '.$username.' 于 '.$time.' 被登录登录IP地址为 '.$ip.' 如果该操作非您本人操作,可能帐号信息已经被泄露,请您及时修改密码。 ';
SendMail('1009465756@qq.com','应急响应中心后台登录提示',$con,'应急响应中心'); //使用时注意将1009465756@qq.com修改为您的邮箱帐号
SendMail($user['email'],'应急响应中心后台登录提示',$con,'应急响应中心');
$this->success("登陆成功",U('Index/index'));
}
//定向之后台主页
@@ -64,10 +64,10 @@ class LoginController extends Controller {
}
//验证码
public function verify(){
ob_clean();
ob_clean();
$Verify = new \Think\Verify();
$Verify->codeSet = '0123456789';
$Verify->fontSize = 13;
$Verify->codeSet = 'AECDEFGHIGJ123456';
$Verify->fontSize = 16;
$Verify->length = 4;
$Verify->entry();
}
@@ -81,4 +81,4 @@ class LoginController extends Controller {
session('username',null);
redirect(U('Login/index'));
}
}
}

View File

@@ -0,0 +1,125 @@
<?php
namespace Admin\Controller;
use Admin\Controller;
/**
* @author Zhou Yuyang <1009465756@qq.com> 12:28 2016/1/26
* @copyright 2105-2018 SRCMS
* @homepage http://www.src.pw
* @version 1.6
*/
/**
* 后台用户管理
*/
class ManagerController extends BaseController
{
/**
* 用户列表
* @return [type] [description]
*/
public function index($key="")
{
if($key == ""){
$model = M('manager');
}else{
$where['username'] = array('like',"%$key%");
$where['email'] = array('like',"%$key%");
$where['_logic'] = 'or';
$model = M('member')->where($where);
}
$count = $model->where($where)->count();// 查询满足要求的总记录数
$Page = new \Extend\Page($count,15);// 实例化分页类 传入总记录数和每页显示的记录数(25)
$show = $Page->show();// 分页显示输出
$member = $model->limit($Page->firstRow.','.$Page->listRows)->where($where)->order('id DESC')->select();
$this->assign('member', $member);
$this->assign('page',$show);
$this->display();
}
/**
* 添加用户
*/
public function add()
{
//默认显示添加表单
if (!IS_POST) {
$this->display();
}
if (IS_POST) {
//如果用户提交数据
$model = D("Manager");
if (!$model->field('username,email,password,repassword')->create()) {
// 如果创建失败 表示验证没有通过 输出错误提示信息
$this->error($model->getError());
exit();
} else {
if ($model->add()) {
$this->success("后台用户添加成功", U('manager/index'));
} else {
$this->error("后台用户添加失败");
}
}
}
}
/**
* 更新后台用户信息
* @param [type] $id [管理员ID]
* @return [type] [description]
*/
public function update()
{
//默认显示添加表单
if (!IS_POST) {
$model = M('manager')->find(I('id',0,'intval'));
$this->assign('model',$model);
$this->display();
}
if (IS_POST) {
$model = D("manager");
if (!$model->field('username,email,password')->create()) {
$this->error($model->getError());
}else{
//验证密码是否为空
$data = I();
unset($data['password']);
if(I('password') != ""){
$data['password'] = md5(I('password'));
}
//更新
if ($model->save($data)) {
$this->success("用户信息更新成功", U('manager/index'));
} else {
$this->error("未做任何修改,用户信息更新失败");
}
}
}
}
/**
* 删除后台用户
* @param [type] $id [description]
* @return [type] [description]
*/
public function delete()
{
$id = I('get.id',0,'intval');
if(C('SUPER_ADMIN_ID') == $id) $this->error("超级管理员不可禁用!");
$model = M('manager');
//查询status字段值
$result = $model->find($id);
//更新字段
$data['id']=$id;
if($result['status'] == 1){
$data['status']=0;
}
if($result['status'] == 0){
$data['status']=1;
}
if($model->save($data)){
$this->success("状态更新成功", U('manager/index'));
}else{
$this->error("状态更新失败");
}
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Admin\Model;
use Think\Model;
class ManagerModel extends Model{
protected $_validate = array(
array('username','require','请填写用户名!'), //默认情况下用正则进行验证
array('email','require','请填写邮箱!'), //默认情况下用正则进行验证
array('email','email','邮箱格式错误!'), //默认情况下用正则进行验证
array('password','require','请填写密码!','','',self::MODEL_INSERT), //默认情况下用正则进行验证
array('repassword','password','确认密码不正确',0,'confirm'), // 验证确认密码是否和密码一致
array('staus',array(0,1),'请勿恶意修改字段',3,'in'), // 当值不为空的时候判断是否在一个范围内
array('type',array(1,2),'请勿恶意修改字段',3,'in'), // 当值不为空的时候判断是否在一个范围内
);
protected $_auto = array(
array('password','md5',1,'function') , //添加时用md5函数处理
array('update_at','time',2,'function'), //更新时
array('create_at','time',1,'function'), //新增时
array('login_ip','get_client_ip',3,'function'), //新增时
);
}

View File

@@ -19,7 +19,6 @@ class MemberModel extends Model{
array('update_at','time',2,'function'), //更新时
array('create_at','time',1,'function'), //新增时
array('login_ip','get_client_ip',3,'function'), //新增时
// array('password','',2,'ignore') //怎么不能用?
);

View File

@@ -0,0 +1,28 @@
<include file="Public/header" title="添加用户" />
<div id="page-wrapper">
<form action="{:U('manager/add')}" method="post">
<div class="form-group">
<label>用户名</label>
<input class="form-control" type="text" name="username" placeholder="后台用户名">
</div>
<div class="form-group">
<label>邮箱</label>
<input class="form-control" type="text" name="email" placeholder="邮箱">
</div>
<div class="form-group">
<label>密码</label>
<input class="form-control" type="password" name="password" placeholder="密码">
</div>
<div class="form-group">
<label>确认密码</label>
<input class="form-control" type="password" name="repassword" placeholder="重复密码">
</div>
<div class="form-group">
<button class="btn btn-success" type="submit" >添加</button>
</div>
</form>
</div>
<include file="Public/footer" />

View File

@@ -0,0 +1,48 @@
<include file="Public/header" title="前台用户管理" />
<div id="page-wrapper">
<div class="row">
<div class="col-md-6">
<a href="{:U('manager/add')}" class="btn btn-success">添加用户</a>
</div>
<div class="col-md-6">
<form action="{:U('manager/index')}" method="post">
<div class="form-group input-group">
<input type="text" class="form-control" name="key" placeholder="输入用户名或者邮箱关键词搜索">
<span class="input-group-btn">
<button class="btn btn-default" type="button"><i class="fa fa-search"></i></button>
</span>
</div>
</form>
</div>
</div>
<table class="table table-hover table-striped">
<thead>
<tr>
<td>编号</td>
<td>用户名</td>
<td>邮箱</td>
<td>创建时间</td>
<td>上次登陆</td>
<td>登陆IP</td>
<td>操作</td>
</tr>
</thead>
<tbody>
<foreach name="member" item="v">
<tr>
<td>{$v.id}</td>
<td>{$v.username}</td>
<td>{$v.email}</td>
<td>{$v.create_at|date="Y/m/d H:i:s",###}</td>
<td>{$v.update_at|date="Y/m/d H:i:s",###}</td>
<td>{$v.login_ip}</td>
<td><a href="{:U('manager/update?id=')}{$v.id}">编辑</a></td>
</tr>
</foreach>
</tbody>
</table>
</div>
<include file="Public/footer" />

View File

@@ -0,0 +1,25 @@
<include file="Public/header" title="更新用户" />
<div id="page-wrapper">
<form action="{:U('manager/update')}" method="post">
<div class="form-group">
<label>用户名</label>
<input class="form-control" type="text" name="username" value="{$model.username}">
</div>
<div class="form-group">
<label>邮箱</label>
<input class="form-control" type="text" name="email" value="{$model.email}">
</div>
<div class="form-group">
<label>新密码</label>
<input class="form-control" type="password" name="password" placeholder="不填写则不更改">
</div>
<div class="form-group">
<input type="hidden" name="id" value="{$model.id}">
<button class="btn btn-success" type="submit" >更新</button>
</div>
</form>
</div>
<include file="Public/footer" />

View File

@@ -18,12 +18,18 @@
<input class="form-control" type="password" name="repassword" placeholder="repassword">
</div>
<div class="form-group">
<label>用户类型</label>
<label>用户等级</label>
<label class="radio-inline">
<input type="radio" name="type" id="type" value="1" checked="checked">前台用户
<input type="radio" name="type" id="type" value="1" <if condition="$model.type eq 1">checked="checked"</if>>路人
</label>
<label class="radio-inline">
<input type="radio" name="type" id="type" value="2">管理员
<input type="radio" name="type" id="type" value="2" <if condition="$model.type eq 2">checked="checked"</if>>实习白帽子
</label>
<label class="radio-inline">
<input type="radio" name="type" id="type" value="3" <if condition="$model.type eq 3">checked="checked"</if>>普通白帽子
</label>
<label class="radio-inline">
<input type="radio" name="type" id="type" value="4" <if condition="$model.type eq 4">checked="checked"</if>>核心白帽子
</label>
</div>
<div class="form-group">

View File

@@ -1,4 +1,4 @@
<include file="Public/header" title="用户列表" />
<include file="Public/header" title="前台用户管理" />
<div id="page-wrapper">
<div class="row">
<div class="col-md-6">
@@ -41,8 +41,10 @@
<td>{$v.update_at|date="Y/m/d H:i:s",###}</td>
<td>{$v.login_ip}</td>
<td>
<if condition="$v.type eq 1"> <span class="label label-success">会员</span>
<elseif condition="$v.type eq 2"/><span class="label label-danger">管理员</span>
<if condition="$v.type eq 1"> <span class="label label-default">路人</span>
<elseif condition="$v.type eq 2"/><span class="label label-info">实习白帽子</span>
<elseif condition="$v.type eq 3"/><span class="label label-success">普通白帽子</span>
<elseif condition="$v.type eq 4"/><span class="label label-danger">核心白帽子</span>
</if>
</td>
<td><if condition="$v.status eq 1">正常<else/><span style="color:red">禁用</span></if></td>

View File

@@ -14,12 +14,18 @@
<input class="form-control" type="password" name="password" placeholder="不填写则不更改">
</div>
<div class="form-group">
<label>用户类型</label>
<label>用户等级</label>
<label class="radio-inline">
<input type="radio" name="type" id="type" value="1" <if condition="$model.type eq 1">checked="checked"</if>>前台用户
<input type="radio" name="type" id="type" value="1" <if condition="$model.type eq 1">checked="checked"</if>>路人
</label>
<label class="radio-inline">
<input type="radio" name="type" id="type" value="2" <if condition="$model.type eq 2">checked="checked"</if>>管理员
<input type="radio" name="type" id="type" value="2" <if condition="$model.type eq 2">checked="checked"</if>>实习白帽子
</label>
<label class="radio-inline">
<input type="radio" name="type" id="type" value="3" <if condition="$model.type eq 3">checked="checked"</if>>普通白帽子
</label>
<label class="radio-inline">
<input type="radio" name="type" id="type" value="4" <if condition="$model.type eq 4">checked="checked"</if>>核心白帽子
</label>
</div>
<div class="form-group">

View File

@@ -27,7 +27,7 @@
</div>
<div class="form-group">
<label for="post-content">修复建议</label>
<input type="text" name="title" class="form-control" value="{$post.advise}" id="post-title" placeholder="输入修复建议">
<input type="text" name="advise" class="form-control" value="{$post.advise}" id="post-title" placeholder="输入修复建议">
</div>
<div class="form-group">
<label>修补限期</label>

View File

@@ -12,9 +12,13 @@
<li class="dropdown">
<a href="{:U('blog/index')}"><i class="fa fa-th-list"></i> 博客管理</a>
</li>
<li class="dropdown">
<a href="{:U('member/index')}"><i class="fa fa-users"></i> 用户管理</a>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><i class="fa fa-users"></i>用户管理<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{:U('member/index')}"><i class="fa fa-tag"></i> 前台用户</a> </li>
<li><a href="{:U('manager/index')}"><i class="fa fa-tag"></i> 后台用户</a></li>
</ul>
</li>
<li class="dropdown">
<a href="{:U('hall/index')}"><i class="fa fa-star"></i> 贡献榜管理</a>
</li>