返回列表 发帖
查看: 8444|回复: 4

Discuz!基础的代码安全和代码规范

83

主题

-6

回帖

329

积分

炉火纯青

贡献
2 点
金币
241 个
发表于 2019-6-3 13:24:08 | 显示全部楼层 |阅读模式

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

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

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

初始化$a = array();
字串 $a ='';
数字 $a = 0

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

$s = '123456';
echo $s[2];
等于什么?

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

举例
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也是白搭
哪件事呢?
select * from table where id=$id
select * from table where id=I\'m
看,依然sql错误,而且还被注入

我举例子
没错,单引号封闭,无论你是什么类型的字段
在Discuz!的规范里,必须都加单引号
select * from table where id='$id'
WHERE后面的所有条件
变量必须加单引号,这是规范。也许你少加一个,并不会产生漏洞,也只是也许。

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

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

$a = '12345';
$a_en = htmlspecialchars($a)
$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
良好的代码规范可增加自己的可读性
DB::query("UPDATE ".DB::table('common_member_count')." set $giftunit = $remaining where uid = $_G[uid]");

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

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

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

a=a+'-1'
就不会

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

插件如有减分操作的时候
当a=0的时候
1、a=a-1
2、a=a+'-1'
3、a=a+(-1)
三种方法,你看哪个ok

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

举例
foreach($array as $k => $v)
嗯,$array是数组,并且存在的时候。。。

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

如果$array不是数组的情况下,这句就错了
你可以if(is_array($array))
也可以(array)$array

类似影响流程的不仅仅是foreach
如rawurlencode
echo rawurlencode('sss');
谁都知没问题
但!!回到刚才我曾说过的,认清变量类型
echo rawurlencode(array('11'));

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

用php的每一个函数的时候都要看清接受参数的类型
如果是字串,切记刚才说的
php很傻,有时候字串、数组不分
这是最后一点,爆路径,爆路径后能干啥,黑客最清楚
回复

使用道具 举报

14

主题

1791

回帖

2058

积分

应用开发者

discuz 老兵

贡献
8 点
金币
188 个
QQ
发表于 2019-6-7 23:01:14 | 显示全部楼层
收藏了~~  下次开发插件前注重以下
回复 支持 反对

使用道具 举报

3

主题

118

回帖

184

积分

应用开发者

贡献
0 点
金币
58 个
发表于 2019-6-9 08:38:28 | 显示全部楼层
感谢分享,
回复

使用道具 举报

0

主题

4

回帖

8

积分

初学乍练

贡献
0 点
金币
4 个
发表于 2019-8-9 10:38:27 | 显示全部楼层
本帖最后由 ssbaoer89 于 2019-8-9 10:40 编辑

机会是留给
回复 支持 反对

使用道具 举报

12

主题

87

回帖

220

积分

应用开发者

贡献
1 点
金币
71 个
发表于 2019-8-9 11:56:12 | 显示全部楼层
还有很多历史原因遗留的严重BUG,
php的正则匹配中小数点.即使你后面没有加/s也是包括\r这个换行符的(网络上所有的教程说法都是错误误导的),

还有PHP_EOL这个常量千万不能用,因为它在windows下等同于\r\n,linux下等同于\n, 比如现在是windows写入和读取后分割都是用\r\n确实没有问题, 但如果你以后服务器换到了linux的话分割用PHP_EOL \n那么以前在windows时写入的数据分割后后面全部会平白无故多一个\r出来,长度完全就不对了
回复 支持 1 反对 0

使用道具 举报

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

本版积分规则

  • 关注公众号
  • 有偿服务微信
  • 有偿服务QQ

手机版|小黑屋|Discuz! 官方交流社区 ( 皖ICP备16010102号 |皖公网安备34010302002376号 )|网站地图|star

GMT+8, 2024-4-27 07:27 , Processed in 0.052396 second(s), 17 queries , Redis On.

Powered by Discuz! W1.0 Licensed

Cpoyright © 2001-2024 Discuz! Team.

关灯 在本版发帖
有偿服务QQ
有偿服务微信
返回顶部
快速回复 返回顶部 返回列表