无限星辰工作室-客户无限互联网动力之源

标题: Discuz!基础的代码安全和代码规范 [打印本页]

作者: crx349    时间: 2019-6-4 15:18
标题: Discuz!基础的代码安全和代码规范

变量
所有漏洞都来源于变量,因此变量首先要做的就是定义初始化。用任何一个变量前一定要先定义,初始化它
虽然现在Discuz!X来说,GPC不会被全局覆盖了,但是大家写插件的过程中也不要忽视了
因为在服务器php.ini的配置中 global on 时
所有的GET POST 都会变成变量
  1. $_GET['xxx']
复制代码
如果存在
就会变成 $xxx 而产生在程序里
因此,你自己要用的变量,一定要初始化

第一点,变量的初始化
无论你要怎么利用变量,一定要初始化
不管是Discuz!还是Discuz!X
由于PHP的历史原因
你不能相信任何一个服务器
只因为php有个global on 的参数
他会让GPC变量直接变成全局变量
因此,你自己的变量一定要初始化

第二点,认清变量的类型
整刚才说到,变量一定要初始化,那么初始化成什么类型
如果你要用于数组

初始化
  1. $a = array();
复制代码

字串
  1. $a ='';
复制代码

数字
  1. $a = 0
复制代码


这样子,这里说说数组,这里又存在一个php历史问题,这历史延续至今。

  1. $s = '123456';
  2. echo $s[2];
复制代码

等于什么?

[]大家都知,这是数组的用法,但php太自由了 $s[3] 的数组用法,竟然可以用在字串里,这个在大家认为很自然。
但是,很多漏洞会从此诞生,这就是认清自己的变量类型的道理所在。
$s[1] 是数组的用法,可以用在字串中,但是我不推荐大家用,黑客会这么用在GET中更改你的变量类型。

举例
  1. echo $s[2];
复制代码

简单这一句,你认为这是输出数组的一个项,还是字串?
大多数人会认为这明显是输出数组的一个项目,但是刚才也看到了,它输出字串的一个字节也可以。
那,我们反过来思考,如果程序的某逻辑需要输出字串的某字节,但是,如果你没明确告知变量类型。那么有可能会让这一个字节变成一个字串 xxx.php?s[2]=hello

初始化+认清自己的变量类型
特别是数组和字串,如果你要取字串的某一位,安全的方法,可能还是 substr($s, 2, 1)
切忌[]的用法,一定要$a = array() 不要让他和字串类型的变量产生互用理中

第三点、不要相信任何一个即将入库的变量
进很多SQL注入都是从变量开始,要仔细看每一个SQL语句中可能出现的变量,如,整数一定要intval;字串一定要addslashes处理,说到addslashes,说说Discuz!的特点,国外某些论坛是,所有变量都无需addslashes,addslashes只在SQL数据库类中统一处理,但Discuz!不是,Discuz!会统一给GPC变量自动addslashes。

注意,是只给GPC变量加addslashes,其他的都没加。所以,你要注意两件事:
1. GPC变量你想用于显示?
那么别忘记stripslashes 后在显示,否则万一遇到有带有 ' 的,那就会多一个\,I'm 变成 I\'m
htmlspecial只处理<>这些,和单引号无关

2. 再次,刚才说过DZ只处理GPC。因此,GPC之外的所有变量一定要自己addslashes,特别是有些时候时,把A库的东西读出来后,直接复制到B库的情况。有人说A库的东西都入进去了,直接入B库还不安全吗?这可不一定,I'm 被A读取出来后 直接入B库,肯定是sql error,必须addslashes。如果要 serialize ,那么 serialize前无需addslashes,serialize后要,从数据库中去出来的肯定是I'm,不是I'\m,serialize是好东西,但不要把addslashes后的也给serialize进去。

那么,我再继续深一步,刚才说到了数据库。
我们保证了入库前的所有变量必须是addslashes,但是,如果你不做下面的一件事。那么你再addslashes也是白搭
哪件事呢?
  1. select * from table where id=$id
  2. select * from table where id=I\'m
复制代码

看,依然sql错误,而且还被注入

我举例子
没错,单引号封闭,无论你是什么类型的字段
在Discuz!的规范里,必须都加单引号
  1. select * from table where id='$id'
复制代码

WHERE后面的所有条件
变量必须加单引号,这是规范。也许你少加一个,并不会产生漏洞,也只是也许。

但,有些隐形的漏洞就是在七拐八拐中产生的。你少写一个,那些黑客就会用七拐八拐的方式去分析,看看可否利用行中。
intval是必须的,规则也是必须遵守的,然后是html的问题,不要漏掉任何一个字串类型。
所有字串类型,如果你不希望他们显示html,入库前一定要htmlspecialchars后再入库,或者strip_tags下

数字类型
大家都知道intval,字串是htmlspecialchars,当然,后台无所谓!后台比较安全,但是,最好也有,一个习惯,仅作参考。

  1. $a = '12345';
  2. $a_en = htmlspecialchars($a)
  3. $a_ad = addslashes($a);
复制代码


这样,入库的时候sql查询语句里应该都是_ad结尾的
html模版中的应该都是_en结尾的
我说不出很多黑客的那些漏洞属于
但是刚才说的那些如果都做到了,代码安全不成问题

然后说说Discuz!内置的一些变量

Discuz!X中,理论上你要用 $_G ($_G['gp_*'] 除外) 里的变量,都要考虑htmlspecialchars和addslashes
$_G['gp_*'] 是DX里的GPC
GP
GET POST 都经过了 addslashes后存放到了$_G['gp_*]中
但_G中的其他,均没addslashes
GPC都addslashes过
dhtmlspecialchars 支持数组
其他同理
如果你有一个良好的代码规范,也会让代码安全性提高
很多规范大家可以给自己定,像刚才的$a_en $a_ad

第四点,下面简单说说代码规范
大家阅读代码的时候也许都看到了
$a = 1;
赋值语句前后空格
if(.........
if后面没空格,这些细节涉及不到安全,但有一点,这些也有安全影响?

SQL
良好的代码规范可增加自己的可读性
  1. DB::query("UPDATE ".DB::table('common_member_count')." set $giftunit = $remaining where uid = $_G[uid]");
复制代码


Discuz!规定sql语句中的SQL关键词必须大写
  1. DB::query("UPDATE ".DB::table('common_member_count')." SET $giftunit='$remaining' WHERE uid='$_G[uid]'");
复制代码

修正过的

  1. $giftunit = $remaining
复制代码

没引号,而且大小写不明,阅读起来很累,规范的不规范的写在一起
虽然站长,不会看代码。但是,一个漂亮代码文档,就像一篇好作文。

有一个SQL上的细节
  1. notifications=notifications+1
复制代码

这种SQL语句,理论上我们不推荐,虽然这么写本身是正确的
如果a字段是unsigned类型,那么会产生数暴增
产生溢出

  1. a=a+'-1'
复制代码

就不会

mysql好奇怪的
这点大家通过pma试试就知道了

插件如有减分操作的时候
当a=0的时候
  1. 1、a=a-1
  2. 2、a=a+'-1'
  3. 3、a=a+(-1)
复制代码

三种方法,你看哪个ok

下面说最后一点
涉及安全的,代码的流程,你的程序,如果只在你的流程下运作
允许100、1000次也许都不会出错。但是,在别人那里,不一定

举例
  1. foreach($array as $k => $v)
复制代码

嗯,$array是数组,并且存在的时候。。。

没错,是,你自己调试的时候,这数组肯定有
但是在用户那里,有可能就没了
这时候,这语句有错

如果$array不是数组的情况下,这句就错了
  1. 你可以if(is_array($array))
  2. 也可以(array)$array
复制代码


类似影响流程的不仅仅是foreach
如rawurlencode
  1. echo rawurlencode('sss');
复制代码

谁都知没问题
但!!回到刚才我曾说过的,认清变量类型
  1. echo rawurlencode(array('11'));
复制代码


肯定出错,大家可以测试下
因此 rawurlencode($s) 的时候
一定要确保$s是字串还是数组




欢迎光临 无限星辰工作室-客户无限互联网动力之源 (https://xmspace.net/) Powered by Discuz! X3.4