PHP的相关内容分享
如果要管理多个数据库,方便切换,可以在phpMyadmin里直接配置多个数据库
选择即可跳转到相应的数据库
要注意,这是明文保存密码在配置文件里的,所以需要注意安全

复制一份 config.sample.inc.php 为 config.inc.php

/**
* First server
*/
$i++;
/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'cookie';
/* Server parameters */
$cfg['Servers'][$i]['host'] = 'localhost';
$cfg['Servers'][$i]['compress'] = false;
$cfg['Servers'][$i]['AllowNoPassword'] = false;


可以看到这个是基于cookie来验证登录的
我们可以改为config方式,并且加上用户名和密码

/**
* First server
*/
$i++;
/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'config';
/* Server parameters */
$cfg['Servers'][$i]['host'] = 'localhost';
$cfg['Servers'][$i]['user'] = 'user';
$cfg['Servers'][$i]['password'] = 'password';
$cfg['Servers'][$i]['compress'] = false;
$cfg['Servers'][$i]['AllowNoPassword'] = false;


把user和password配置好即可
复制多个即可增加多个server,同时访问phpMyadmin会出现下拉选择框,选择即可跳转到另外的数据库
在github上发现了个不错的项目
https://github.com/chaegumi/cxpcms

我一直还说着要做一个管理框架来着,有人做了就拿下看看
结果在本地配置好之后,一直都登录提示验证码错误,这个倒是开始怀疑人生了

1 验证码错误?

反复确认了Captcha.php里生成的和我输入的是一致的
然后确认对比流程,发现提交的是对的,但本地读取的是空值
另外查看session目录的文件,每次访问都产生新的session文件
说明session会话根本没有跟踪到,每次访问都是当做新用户看待,所以比对失败

2 那为什么每次都是新的session呢?

CI根据cookie里的ci_session值作为session_id
做了个简单的页面,打印cookie和session,每次这两个值都在变
另外做了个原生页面的,这个值是不会变的

3 那肯定是CI的问题

直接查看文件
system/libraries/Session/Session.php
检查session的处理流程:

    print_r($_COOKIE);
    echo $this->_config['cookie_name'].'//'.$this->_sid_regexp.'//';
    if (isset($_COOKIE[$this->_config['cookie_name']])
      && (
        ! is_string($_COOKIE[$this->_config['cookie_name']])
        OR ! preg_match('#\A'.$this->_sid_regexp.'\z#', $_COOKIE[$this->_config['cookie_name']])
      )
    )
    {
      echo 'del//';
      unset($_COOKIE[$this->_config['cookie_name']]);
    }


调试起来发现,总是进入del的流程,cookie被删掉了
导致后面会重新设置cookie
很明显是这个导致的
preg_match('#\A'.$this->_sid_regexp.'\z#', $_COOKIE[$this->_config['cookie_name']]


4 表达式在做什么

    if (PHP_VERSION_ID < 70100)
    {
      if ((int) ini_get('session.hash_function') === 0)
      {
        ini_set('session.hash_function', 1);
        ini_set('session.hash_bits_per_character', $bits_per_character = 4);
      }
      else
      {
        $bits_per_character = (int) ini_get('session.hash_bits_per_character');
      }
    }
    elseif ((int) ini_get('session.sid_length') < 40 && ($bits_per_character = (int) ini_get('session.sid_bits_per_character')) === 4)
    {
      ini_set('session.sid_length', 40);
    }

    switch ($bits_per_character)
    {
      case 4:
        $this->_sid_regexp = '[0-9a-f]{40,}';
        break;
      case 5:
        $this->_sid_regexp = '[0-9a-v]{40,}';
        break;
      case 6:
        $this->_sid_regexp = '[0-9a-zA-Z,-]{40,}';
        break;
    }


我们看到表达式是 [0-9a-f]{40,} 而cookie长度是26个字符,所以总是不能符合要求
打印出来配置,发现也一直是26,ini_set也不起作用

5 如何修复

我们看到新版本的CI已经修复了这个问题
    // Yes, 4,5,6 are the only known possible values as of 2016-10-27
    switch ($bits_per_character)
    {
      case 4:
        $this->_sid_regexp = '[0-9a-f]';
        break;
      case 5:
        $this->_sid_regexp = '[0-9a-v]';
        break;
      case 6:
        $this->_sid_regexp = '[0-9a-zA-Z,-]';
        break;
    }


简单升级替换system文件夹即可解决

项目更新在 https://github.com/hqlulu/cxpcms
在旧工程里有很多文件是使用了短标签标记php片段
但默认安装的php环境,现在都把短标签关闭
php.ini 里
short_open_tag = OFF


文件里如果有短标签的代码,会不解析的
所以可以做一次批量替换
<\?(?!php|=) 替换成 “注意留个空格,防止 这样的语句
sublime下可以直接替换,命令行sed貌似不支持 ?!修饰符
有一个之前的旧项目需要在新环境运行,发现提示mysql函数没有定义
引用
Fatal error: Uncaught Error: Call to undefined function mysql_connect()


新环境是 PHP Version 7.1.11,之前的php项目都是5.2的,所以代码算是旧家伙了,官方自php5.3开始一直推荐mysqli 和 pdo 。
打印phpinfo看,的确没有mysql的函数,取而代之是mysqli、mysqlnd和pdo

mysqli,mysqlnd,pdo到底是什么:
引用
MYSQL:This extension is deprecated as of PHP 5.5.0, and has been removed as of PHP 7.0.0.
MYSQLI: MySQL Improved Extension
MySQLND: MySQL Native Drive
PDO:The PHP Data Objects。extension defines a lightweight, consistent interface for accessing databases in PHP。


以上摘自 PHP官方手册: http://php.net/manual/en/book.mysqli.php

MYSQL 也叫 Original MySQL,PHP4版本的MYSQL扩展,从PHP5起已经被废弃,并从PHP7开始已经被移除。
MYSQLI 叫做 “MySQL增强扩展”。
MYSQLND MYSQL NATIVE DIRVER 叫做MYSQL “官方驱动”或者更加直接点的叫做“原生驱动”
PDO PHP Data Objects PHP数据对象,是PHP应用中的一个数据库抽象层规范。

项目要跑起来,可以适当修改就正常运行

1 数据库链接


//mysql
$link = mysql_connect('127.0.0.1', 'user', 'password');
if (!$link) {
    echo 'Could not connect: ' . mysql_error();
}else{
  mysql_query("set names 'utf8'");
  mysql_select_db("data");
}

//mysqli
$link = mysqli_connect('127.0.0.1', 'user', 'password');
if (mysqli_connect_errno()) {
    echo 'Could not connect: ' . mysqli_connect_errno();
}else{
  $link->query("set names 'utf8'");
  $link->select_db("data");
}


2 读取数据


//mysql
$sql = "select * from users order by ctime desc";
$qr = mysql_query($sql);
$users = array();
while( $task = mysql_fetch_assoc($qr) ){
  $users[] = $task;
}

//mysqli
$sql = "select * from users order by ctime desc";
$qr = $link->query($sql);
$users = $qr->fetch_all(MYSQLI_ASSOC); //直接获取所有数据


discuz获取真实ip的方法是这个:
source/class/discuz/discuz_application.php

private function _get_client_ip() {
  $ip = $_SERVER['REMOTE_ADDR'];
  if (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
    $ip = $_SERVER['HTTP_CLIENT_IP'];
  } elseif(isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
    foreach ($matches[0] AS $xip) {
      if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) {
        $ip = $xip;
        break;
      }
    }
  }
  return $ip;
}


也就是说默认用REMOTE_ADDR,如果有HTTP_CLIENT_IP或HTTP_X_FORWARDED_FOR,则用相应的指定的IP地址。
这个对于用ip来限制重试密码的方式来说,很危险,伪造一个CLIENT_IP或者X_FORWARDED_FOR就可以让discuz认为的独立的ip,从而脱离限制。
discuz也没有白名单机制去限制这两个参数的使用,所以是个很危险的漏洞。

防御方式:对使用CLIENT_IP或者X_FORWARDED_FOR限制

如果明确不使用代理方式部署服务器,那可以考虑禁用这两个参数。
如果用代理的方式部署,可以实施白名单机制。
PHP修改代码即可,判别REMOTE_ADDR白名单再启用这两个参数。

Nginx也可以有白名单的方式,编译需要添加参数:
--with-http_realip_module
使用说明:http://nginx.org/en/docs/h...

可以对比一下几个方式搭配:
1 不使用realip_module
2 使用realip_module

客户端模式:
A 伪造client-ip直接访问目标服务器
B 伪造client-ip访问代理服务器
C 代理服务器不在realip_module白名单
代理服务器设置
proxy_set_header        CLIENT-IP       $remote_addr;


为此,我们需要先修改PHP代码,以便获知PHP获得的参数:

private function _get_client_ip() {
  $ip = $_SERVER['REMOTE_ADDR'];
  if (isset($_GET['debug_ip'])) {
    exit('REMOTE_ADDR:'.$ip.' / CLIENT_IP:'.$_SERVER['HTTP_CLIENT_IP'].' / X_FORWARDED_FOR:'.$_SERVER['HTTP_X_FORWARDED_FOR']."\n");
  }
  $white_lists = array(
    '60.191.x.y',
    '123.157.x.y',
    '222.187.x.y',
    '121.40.x.y',
    );
  if (!in_array( $ip, $white_lists)) {
    return $ip;
  }
  if (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
    $ip = $_SERVER['HTTP_CLIENT_IP'];
  } elseif(isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
    foreach ($matches[0] AS $xip) {
      if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) {
        $ip = $xip;
        break;
      }
    }
  }
  return $ip;
}


测试组合结果:
域名和ip因为隐私做了替换
引用
1A

curl -H "host:www.aslibra.com" -H "CLIENT-IP:2.3.4.5" "dyw3.aslibra.com/?debug_ip=1"
REMOTE_ADDR:114.243.204.152 / CLIENT_IP:2.3.4.5 / X_FORWARDED_FOR:

1B

curl -H "host:www.aslibra.com" -H "CLIENT-IP:2.3.4.5" "dyw4.aslibra.com/?debug_ip=1"
REMOTE_ADDR:222.187.x.y / CLIENT_IP:114.243.204.152 / X_FORWARDED_FOR:

2A

curl -H "host:www.aslibra.com" -H "CLIENT-IP:2.3.4.5" "dyw3.aslibra.com/?debug_ip=1"
REMOTE_ADDR:114.243.204.152 / CLIENT_IP:2.3.4.5 / X_FORWARDED_FOR:

2B

curl -H "host:www.aslibra.com" -H "CLIENT-IP:2.3.4.5" "dyw4.aslibra.com/?debug_ip=1"
REMOTE_ADDR:114.243.204.152 / CLIENT_IP:114.243.204.152 / X_FORWARDED_FOR:

2C 222.187.x.y 不在nginx的白名单的情况

curl -H "host:www.aslibra.com" -H "CLIENT-IP:2.3.4.5" "dyw4.aslibra.com/?debug_ip=1"
REMOTE_ADDR:222.187.x.y / CLIENT_IP:114.243.204.152 / X_FORWARDED_FOR:


测试结果说明什么问题?
1A 客户端ip 和设定的ip都收到
1B 代理ip和客户端ip
2A 客户端ip和设定的ip
2B 客户端ip和客户端ip
2C 代理ip和客户端ip

说明,realip_module传递给PHP后端REMOTE_ADDR就是合法的CLIENT_IP,而CLIENT_IP却没有清空
那问题来了,它没法解决discuz检查CLIENT_IP的漏洞,如果检查就没戏
所以,PHP加一份白名单很有必要哦!
分页: 1/20 第一页 1 2 3 4 5 6 7 8 9 10 下页 最后页 [ 显示模式: 摘要 | 列表 ]

阅读推荐

服务器相关推荐

开发相关推荐

应用软件推荐