作者GALINE (天真可爱CQD)
看板PHP
标题[讨论] 安全性,injection,过滤与跳脱
时间Sun Dec 3 02:19:36 2017
在 5.6 -> 7.1 的讨论串看到一些安全相关的对话
感觉有些东西值得单独拿出来讨论
我自己的意见是这样:
- 不要一开始就把资料做跳脱,只有到最後要把资料喂出去给其他地方的时候才做
- 例如,做 SQL 的那一行,或写 HTML 那行
- 设计来干什麽的 function,就只拿来干什麽
- htmlentities 只处理 html,不处理 SQL injection
- 不要用 addslashes 跟 magic quote
- 如果可以的话,不要自己组 SQL/HTML/Javascript
- 从根本确保没有 injection 这件事
----------------------------------------------
上面这几个原则,是为了达成这几个目的
- 保留原始资料,就算他里面可能有脏东西
- 不管 code 写到哪里,都可以遵循同样的做法
- 减少可能有问题的地方
- 难搞的事情,让比专业的人来做
首先必须要认知,同样的资料要避免被注入脏东西
在不同的地方处理方法是不一样的。
例如,同样
</script><script>alert('1');// 这个字串
- 放进 html 要 escape 成
</script><script>alert('1');//
- htmlspecialchars / htmlentities
- 放进 javascript 字串,要 escape 成
"<\/script><script>alert('1');\/\/"
- json_encode
- 放进 sql,要 escape 成
</script><script>alert(\'1\');//
- mysql(i)_real_escape_string
可以看到不同的地方需要的 escape 都不一样。
所以你必须需要保留原始的输入资料,然後在不同的地方各自做不同的转换
而每个转换都应该找专门设计来做这件事的 function 来做。
然後,你不该「事先」把资料做 escape。
如果有个 function 是 updateUserNickName($uid, $name)
那麽你应该会预期 $name 是
"It's me, Mario!" 的时候
使用者的昵称会被改成
"It's me, Mario!"
但,如果你事先把 $name escape 过了,那这个 function 得做的事情就变成
输入
"It\'s me, Mario!" 的时候,昵称被改成
"It's me, Mario!"
换句话说,function 行为与业务行为不同步
不管是要写单元测试,或是未来要改写这个 function,写的人诅咒作者的机会很高
再来是,如果建立起不事先跳脱资料的惯例,那麽只要看到
"SELECT * FROM user WHER uid = '{$uid}'"
你不用看前面的 code 也能确定这段 code 一定有问题
不用花时间回去确认「前面到底有没有事先过滤啊」
可以用更短的时间看出问题所在
addslashes 的问题是他看不懂多位元的文字
可以故意塞特定位元,让字串过 addslashes 之後刚好变成 '\ 之类的东西
http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string
magic quote 则是自动帮你套用 addslashes,等於是事先做跳脱
而且结果还不一定能用(记得 js 跟 html 跟 sql 需要的跳脱都不一样吗?)
但比起伤脑筋怎麽做跳脱,最好的方法是一开始就不要做可能被插东西的字串
这也是为什麽这年头普遍建议用 prepared statment
因为你塞进 DB 的 prepared query (例如
SELECT * FROM user WHERE uid = ?)
一定整句是你写的,不会有外面传来的东西,百分之百保证不会被插东西
bind 变数的时候,并不是在「把变数组合成一句 SQL」,而是「告诉DB变数的值是什麽」
所以不管使用者塞什麽脏东西,DB 都不会误会你的意思
同样的理由,当你需要用 javascript 动态产生表单栏位的时候
不要自己做一段 html 然後 document.write
而是应该 createElement,然後对 element 做 setAttribute
最後 append 到需要的 node 上面
或是用 jquery 的写法:
$('<input>')
.attr({id:"myid",name:"myname"})
.val(userInputValue) // 不管使用者写什麽脏东西都不怕
.appendTo($('#form1'));
不自己做 html 字串,就不需要担心 html 端的 injection
(严谨的说,是「几乎」不用担心)
--
莉娜用魔法爆破进入屋内。
劫犯从另一个房间里出现,大叫道︰「你是谁!」
莉娜︰「我是个可疑的女人!」
劫犯无言以对。
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 114.27.61.52
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/PHP/M.1512238781.A.6C9.html
※ 编辑: GALINE (114.27.61.52), 12/03/2017 02:25:24
※ 编辑: GALINE (114.27.61.52), 12/03/2017 09:38:43
1F:推 bakedgrass: 谢谢分享 12/03 10:26
2F:推 miniear: 谢谢大大分享~~ 12/03 16:09
3F:推 xdraculax: 推 12/03 19:43
4F:推 st1009: 推! 12/03 19:48
5F:推 MangoTW: 推正确观念 12/04 01:10
6F:推 Kenqr: 推 12/04 16:34
7F:推 tkdmaf: 最近ios群就有个讨论,後端要求APP端的请求自行加上\,我 12/04 19:58
8F:→ tkdmaf: 很想跟他说请用力往後端的肚子正拳贯下去…… 12/04 19:58
9F:推 JohnRoyer: 推 12/05 11:35
10F:推 ddoomm: GJ 12/05 14:59
11F:推 cryinglove: 好文不推,怎对得起自己 12/14 19:07
12F:推 shvanta: 这边真的赞, 之前工作看到有人把Escape过的资料存进DB, 12/19 10:14
13F:→ shvanta: 真是吐血. 他以为那个内容只有他网页会用吗... 12/19 10:14