Web开发与运维安全浅见

4,274 views
4,192 views

Published on

Web开发,运维,安全,SQL注入

Published in: Technology
0 Comments
10 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,274
On SlideShare
0
From Embeds
0
Number of Embeds
1,011
Actions
Shares
0
Downloads
0
Comments
0
Likes
10
Embeds 0
No embeds

No notes for slide

Web开发与运维安全浅见

  1. 1. web开发与运维安全浅见<br />
  2. 2. 目录<br /><ul><li>前置知识
  3. 3. SQL注入
  4. 4. 文件上传
  5. 5. XSS与SCRF
  6. 6. 远程文件包含
  7. 7. URL跳转
  8. 8. 权限认证
  9. 9. 数据存储与暴力破解
  10. 10. 文件解析
  11. 11. 其他</li></li></ul><li>前置知识<br /><ul><li>Web的发展历程
  12. 12. http://www.test.com/eg.html
  13. 13. 浏览器如何与服务端通信
  14. 14. 浏览器、传输协议、服务端
  15. 15. 浏览器(Netscape、IE、Firefox、….)
  16. 16. 传输协议 (http 1.0)
  17. 17. 服务端(iis、apache)
  18. 18. 与用户交互,新事物出现
  19. 19. http://test.com/cgi-bin/aa.pl/bb/cc
  20. 20. http://test.com/cgi-bin/dd.py/ee/ff?a=1
  21. 21. 服务端如何与脚本语言通信
  22. 22. CGI 、STDINSTDOUT、环境变量
  23. 23. 保存用户提交的信息,新事物出现
  24. 24. 脚本语言如何与数据库通信
  25. 25. 更… …多的需求
  26. 26. 更多的用户访问,更多的应用,更多的数据----越来越复杂,功能越来越多
  27. 27. squid、nginx、php、redis、mysql、memcache、lucene、lvs、keepalived</li></li></ul><li>SQL注入<br /><ul><li>当web还是静态的时候
  28. 28. 用户无法与服务器交互,也没有DB,就不谈SQL注入了。
  29. 29. 那时我还年轻,会发生什么安全问题我不知道。
  30. 30. 当web是动态 ,后面有DB</li></ul>浏览器与服务器通过提交查询交互,最直观的以GET方式出现在URL的?后面的中的字符串参数,这些字符为DB语句的特殊字符,比如引号为SQL语句的闭合符号等。<br /><ul><li>什么是SQL注入,如何注入</li></ul>例子: http://test.com/info.php?id=1<br /><ul><li> 此URL返回数据库中,某表的第1条信息中的数据。程序中可能这么写的。</li></ul>$arrResult = mysql_query('SELECT * FROM table WHERE id = '.$_GET['id']);<br /><ul><li> 如上的URL,那么查询语句将是</li></ul>SELECT * FROM table WHERE id = 1<br /><ul><li> 如果URL是这样id=1 AND 1,那么查询语句将是</li></ul>SELECT * FROM table WHERE id =1 AND 1<br />
  31. 31. SQL注入<br />URL变成如下这个 Info.php?id=1 AND SELECT LEFT(VERSION(),1) = ‘5’<br />SQL语句将是<br />SELECT * FROM table WHERE id =1 AND SELECT LEFT(VERSION(),1) = ‘5’<br />可查询MYSQL版本的第一个字符是否是5<br /><ul><li>原因是什么</li></ul>对提交的数据未过滤,产生SQL语句的拼接<br /><ul><li>有哪些提交方式</li></ul> GET、POST、COOKIE、其他<br /><ul><li>如何防范
  32. 32. 不让其产生SQL语句拼接:SQL参数化查询(PDO)
  33. 33. 整型参数:强制转化为整型(phpintval、(int))
  34. 34. 字符串型参数:mysql_real_escape_string</li></li></ul><li>SQL注入<br /><ul><li>可能已有的防护</li></ul>依赖php.ini的magic_quotes_gpc,对提交的参数进行过滤,php会对单双引号、反斜杠、null等字符进行转移,我们不能依赖它,SQL注入的产生是SQL语句的拼接,安全问题是在SQL语句的执行,应该对进入SQL语句部分的参数进行SQL语句的转义,而不是PHP对字符串的转义,虽然转义字符看起来长得一样。同时,此参数的开启,对于需要用户原始输入的信息还需要做下反转义,比如用户密码(虽然不要保存原始的)<br /><ul><li>其他间接的SQL注入</li></ul> ECSHOP的URL参数部分是经过BASE64加密的,之后程序在base64解密完之后,直接使用解密的结果,不做过滤了。过分相信这些提交的参数,大部分情况,这些URL都是程序生成的。<br />http://www.ecshop.cn/search.php?encode=YTo5OntzOjg6ImtleXdvcmRzIjtzOjE6IjEiO3M6ODoiY2F0ZWdvcnkiO3M6MToiMCI7czo1OiJicmFuZCI7czoxOiIwIjtzOjk6Im1pbl9wcmljZSI7czowOiIiO3M6OToibWF4X3ByaWNlIjtzOjA6IiI7czoxMDoiZ29vZHNfdHlwZSI7czoxOiIwIjtzOjY6ImFjdGlvbiI7czo0OiJmb3JtIjtzOjY6IlN1Ym1pdCI7czoxMjoi56uL5Y2z5pCc57SiIjtzOjE4OiJzZWFyY2hfZW5jb2RlX3RpbWUiO2k6MTMxNjIyODE3MDt9<br />
  35. 35. SQL注入<br /><ul><li>其他间接注入</li></ul> 一些网页游戏,前端FLASH与后端脚本通讯时,选择使用AMF之类协议,也是有前端(flash)将提交查询的SQL语句加密之后,发送给后端程序,后端程序解密,再做相关查询。这个流程中,也是漏掉对解密的参数继续做过滤判断。<br />
  36. 36. SQL注入<br />
  37. 37. SQL注入<br />
  38. 38. 文件上传<br />网站为了提供更多的功能,吸引用户,推出上传文件功能已经是必备的手段了。尤其是上传头像。<br />为了确保用户上传的文件合法,一般会使用JS去判断文件的拓展名是否合法,确认合法之后,再通过,允许提交到服务端。当表单提交时,浏览器会向服务端发出这么一个HTTP 数据包<br />
  39. 39. 文件上传<br />浏览器会读取这个文件的文件名、文件类型(content-type)、文件的二进制内容,一并发送到服务端。后端程序一般会用POST过来的content-type来验证是否是合法的图片资源等。<br />保存的时候,一般会使用POST过来的文件名的拓展名,或者整个文件名。<br />这些信息都来自浏览器,严格点说,来自客户端,但不能确定构造这个HTTP包的是浏览器,或许是坏人修改了这个包。<br />程序使用客户端提交的信息作为判断依据<br /><ul><li>content-type:text/plain也改成了image/pjpeg,
  40. 40. filename :1234.php[0].jpg,其中0为十六进制的00</li></ul>当保存的时候,文件名的null字符之后的字符串将被舍弃,只保留前面的字符。那么,这个文件会被保存成一个php的文件。<br />
  41. 41. 文件上传<br /><ul><li>重新读取件信息判断(文件头标识)
  42. 42. PNG(8 bytes):89 50 4E 47 0D 0A 1A 0A
  43. 43. GIF(6 bytes):47 49 46 38 39 61 (GIF89a)
  44. 44. Getimagesize函数的问题:</li></li></ul><li>文件上传<br /><ul><li>非法文件上传之后,有何危害</li></ul>具体危害,稍后在文件解析章节详聊<br /><ul><li>如何避免
  45. 45. PHP GD库重绘图片
  46. 46. Getimagesize获取的mime来给予文件拓展名
  47. 47. 文件名不使用原文件名,随机生成
  48. 48. 保存目录不允许脚本解析执行</li></ul>几种策略联合使用,避免安全问题发生。<br />
  49. 49. XSS与CSRF<br /><ul><li>什么是XSS</li></ul>Cross Site Scrip 跨站脚本攻击<br /><ul><li>主要分两类
  50. 50. 来自“站内”
  51. 51. 来自外部提交</li></ul>比如URL是这个 <br />1.php?keyword=<script>alert(document.cookie)</script><br />脚本中代码这么写<br />echo '<tr><td>',$_GET['keyword'],'</td></tr>';<br /><ul><li>有何危害</li></ul> 执行任意JS代码。最常见的做法是获取COOKIE认证信息;其他的就是跳转至恶意网址等,或者配合CSRF漏洞,进行创建form表单,进行提交,强制使当前用户操作,比如发帖,删帖,甚至转账等。<br />
  52. 52. XSS与CSRF<br /><ul><li>什么是CSRF</li></ul>Cross-site request forgery跨站请求伪造<br /><ul><li>如何产生的</li></ul>CSRF利用的前提是XSS,但可以是其他网站的,需要确定用户都在同一浏览器访问了他们。<br /><ul><li>如何防护
  53. 53. XSS的防护:对于GET参数的输出,转化为html实体,再输出;对于保存到数据库的信息,很多人犹豫在入库前过滤,还是出库后,输出前过滤。我倾向后者,尽量保留用户输入的原始数据。
  54. 54. ormhash:如果产生CSRF漏洞的页面也有XSS漏洞,那么formhash的防护将失去作用。XSS可以获取到当前标签页内各个dom节点内容,也包括formhash的内容。
  55. 55. 验证码:用户体验差
  56. 56. 两者联合的危害</li></li></ul><li>权限认证<br /><ul><li>认证信息的保存方式
  57. 57. session:保存在服务端,有一定的生效时间,由后端脚本实现回收。保存方式一般是文件,对php来说,可以保存到redis、memcache之类内存nosql数据库中。脚本与浏览器传输session id的方式分为cookie传输,以及URL中传输。
  58. 58. cookie:保存在客户端,可设定生效时间,由浏览器负责回收。保存方式为文件。
  59. 59. Cookie、session区别与联系
  60. 60. 区别:保存方式、回收者不一样。
  61. 61. 联系:当sessionid存放cookie中时,依赖cookie,cookie被删除,服务端的session或许仍在,因为服务端的session由后端脚本回收,除非你还记得session id是多少,可以修改新的cookie,继续使用。</li></li></ul><li>权限认证<br /><ul><li>Cookie如何欺骗的,为什么</li></ul>程序以cookie中存放信息作为验证依据,而这些信息验证不严格,从而通过验证。<br />例子:<br />user=admin;password=c4ca4238a0b923820dcc509a6f75849b;<br />当攻击者根据SQL注入获得这些用户帐号,以及MD5 hash之后的密码的话,可以直接修改cookie,从而通过验证。<br />当攻击者通过XSS获取到用户的COOKIE,直接修改自己浏览器在网站上的cookie为XSS获取到他人的COOKIE,仍通过验证。<br />对于问题1,cookie中不该存放用户密码,哪怕是加密之后的字符。问题2,程序在设置cookie的时候,只选用当前登录用户的相关信息,加密存到cookie中,未考虑到COOKIE被“拿”到其他浏览器上使用的情况。<br />
  62. 62. 权限认证<br /><ul><li>Session如何被劫持的,为什么攻击者先访问网站,获得一个SESSION ID,如果此网站的session传递用的是URL方式,那么将此URL发送给对方,比如</li></ul>http://test.com/index.php?PHPSESSID=sadas2asds2a。<br />如果此网站使用的是cookie存储session id,可以利用XSS漏洞,让JS设置对方的COOKIE中PHPSESSID为攻击者的PHPSESSID。当对方登录之后,认证通过,程序将用户信息写入到session id为URL参数的PHPSESSID的值的文件中。攻击者也使用这个session id继续访问的时候,由于这个session id中也是被攻击用户的认证信息,则认为这个攻击者也是被攻击用户。产生劫持。<br /><ul><li>原因你或许会说,为什么程序认为他是同一个用户呢,他们并不是同一个用户,他们不一样。没错,他们是不一样,正是程序没有验证他们不一样的地方,所以才出现这种情况。不一样的地方比如浏览器的user-agent,IP或者他。</li></li></ul><li>权限认证<br /><ul><li>如何防范COOKIE欺骗与SESSION劫持
  63. 63. 尽量绑定客户端,为了提高用户体验,可不绑定IP;认证信息中不保存用户密码等相关用户的敏感信息,项目密钥与的当前用户名、浏览器agent等字符串通过加密算法(字符串移位、异或等简单处理)生成的字符串(这些字符串可能有不可见字符,不方便传递,可再BASE64转化一下),设置为认证信息。尽管session劫持的问题可以通过session_regenerate_id函数重新分配一个新的session id,但仍建议哪怕是保存在session 中的认证信息也要加密存放,尽量不要明文(序列化之后的数组)存放。对于cookie存储,认证部分可设置httponly,禁止客户端语言(JS/flash)读取。
  64. 64. 为了减少cookie的发送域,可限定其生效域,以及生效路径。来提高COOKIE存放的安全性,防止可读取认证COOKIE的站点太多,而站点越多,越容易出现各种安全问题。</li></li></ul><li>权限认证<br /><ul><li>到底哪个更安全
  65. 65. 都可以被XSS漏洞获取(非httponly,session id以cookie方式保存到客户端)
  66. 66. session以URL方式传递:危险性更大些,当用户通过本站访问其他站点时,会将url中的session泄漏出去(出现在http-referfer中)
  67. 67. 他们保存的认证信息的安全最重要。
  68. 68. 如何选择
  69. 69. session以文件方式保存,当访问量过大,session文件会很多,每次session_start时,一定机率的sessionGC,大量的扫描session文件是否过期,也是不小的IO。当后端脚本服务器增加,session文件的同步,也是需要注意的问题。若session文件不同步,用户被前端反向代理分发到一台未同步session文件的脚本服务器上,会发生session丢失的问题。
  70. 70. session以redis、memcache等nosql保存时,每次session_start都要与nosql建立TCP连接,获取session,再释放连接。当nosql与脚本服务器不在同一服务器上,网络延迟也是一个需要考虑的问题。同时,这些nosql一般默认不设置密码认证,以为这任何能连接到nosql服务器上的人都可以直接访问。对于一些程序员认为session保存在服务端,足够安全,不加密。那么这些session无疑是明文显示,恶意攻击者可任意修改,控制所有用户的会话认证。</li></ul>a:4:{s:8:"username";s:5:"cfc4n";s:8:"is_admin";b:1;s:5:"money";s:4:"9000";s:6:"is_vip";b:1;}<br />
  71. 71. 权限认证<br /><ul><li>cookie的认证保存时间以及认证内容保存用户认证信息一般比session时间要长的多。这样当用户在多个PC登录,之后其中一个设备丢失,用户在系统上更改密码,但丢失设备的认证仍然有效,不过此问题可以忽略不计。cookie过多的生效域,也增加了被盗取的风险。绑定浏览器信息也是比较常见的做法,在双核浏览器中,会发生因为切换内核,更改user-agent,带来认证失败的事情。
  72. 72. cookie生效域为了SSO单点登录,多数程序会设置cookie为主域名下的所有二级域名,这样所有二级域名均可以读取到cookie,极为方便。当二级域名站点存在安全问题时,cookie很容易被窃取。而且cookie加密算法也被泄漏。尽量减少cookie的发送域,同时,尽量采用生成cookie的站点采用公钥加密、使用cookie的站点用私钥解密,来减少风险,使其只能伪造此站点的cookie,而不影响其他二级域名。
  73. 73. 静态资源站点使用不同主域名一来减少cookie发送域,而来也节省带宽,不必向这些静态资源域名发送cookie(YSLOQ法则之一)。比如:sina微博的图片站点域名sinajs.cn、sinaimg.cn;腾讯微博的图片站点域名qpic.cn。</li></li></ul><li>URL跳转<br /><ul><li>什么是URL跳转程序中常会重定向页面,在登录系统中长会根据URL中的参数进行重定向,便于用户登录之后,调转到之前的页面。比如: http://passport.csdn.net/account/login?from=http://download.csdn.net对于跳转页是否是当前站点的页面,或者是否是允许的页面地址没有做判断,当恶意攻击者将地址改为http://passport.csdn.net/account/login?from=http://www.qq.com/ 那么用户登录后会跳转到www.qq.com,如果是恶意网址,那么用户就成为受害者了。
  74. 74. 配合session在URL中传递的危害跳转到的页面中很容易从HTTP-REFERER中获取到url中session id的值,对于session中验证信息不绑定用户客户端信息的情况,攻击者可直接使用,成为之前用户的身份。</li></li></ul><li>暴力破解与数据传输<br /><ul><li>暴力猜解在站点登录页,不断尝试不同的用户名,密码组合,尝试登录,直到登录成功。
  75. 75. 数据库被窃取,还原用户密码一些网站会明文保存用户密码,对于这种,攻击者无需还原。多数网站会加密存储用户密码,即使数据库泄漏,恶意攻击者也需要一定的时间,精力去组合密码,加密之后与用户密码对比,确定是否正确。</li></li></ul><li>暴力破解与数据传输<br /><ul><li>用户密码保存用户密码从最初的明文保存到后来的MD5 加密一次,到二次加密,以及discuz的 salt做法比较常见,对于彩虹表来说,这些或许都可以直接从彩虹表内查出原来的明文密码。建议取当前用户不变的信息进行变换,移位等方式加密。比如md5(user+md5(pass)+salt+系统密钥),甚至类似身份证算法,根据用户名以及salt的字符组合,计算生成一个字符,之后到密钥里取出一个字符串,放入计算的密码中,生成密码MD5 hash字符串。这样密码的安全需要用户名、用户密码、密钥字符串、系统分配的SALT、权字符算法等五个因素生成。增加了攻击者获取原始密码的难度等等。</li></ul>$sQ = getQuan($user,md5($pass),$sSalt);<br />$sT = getT($sQ,$sKey);<br />$sMd5pass = md5($user,md5($pass),$sSalt,$sT,$sKey);<br />
  76. 76. 暴力破解与数据传输<br /><ul><li>如何防范暴力登录不妨看下腾讯的做法。当用户输入QQ号之后,浏览器发送一个AJAX请求至服务器,服务器会判断当前QQ号此时登录的IP段(或者地理位置)是否是他经常登录的IP段,如果是,则返回此次验证码的字符串,之后JS会取返回的验证码字符串作为form表单的一个参数提交过去。如果当前QQ号此次登录不是常在的IP段,则不直接返回验证码。JS再将验证码图片显示出来。用户体验较好,安全性也较好。
  77. 77. 没有用户常登录IP库少量的用户登录IP库,若采用腾讯的做法,势必会使用户体验更差,计算错误,经常弹出验证码。建议初次登录不提示验证码,密码错误1次之后,再提示验证码。连续错误一定次数之后,锁定帐号一段时间,来提高用户帐号安全性。</li></li></ul><li>暴力破解与数据传输<br /><ul><li>密码在浏览器到服务器安全传输HTTP协议的数据都是明文传输的,保证用户密码在传输过程中不被嗅探,窃听抓到,程序中可以做改进。腾讯虽然没有使用HTTPS登录,但将密码在浏览器段用JS加密,之后传输的是加密之后的字符串,提高对抗难度。
  78. 78. COOKIE在浏览器到服务器的安全传输各个SSO登录站点采用HTTPS协议,来用户密码不是被明文传输被嗅探。其他自站点不会有用户密码的传输,只有通过验证之后COOKIE中保存的认证信息,认证信息不会保存用户密码,多数为根据某算法加密钥生成的字符串,可不用HTTPS。</li></li></ul><li>文件包含与远程代码执行<br /><ul><li>什么是远程文件执行</li></ul>看例子:<?phpinclude($_GET['file']);?>若URL为?file=/etc/passwd,则程序直接读取这个文件。<br /><ul><li>如何防范</li></ul>过滤参数。改成强制加扩展名,并且,不允许提交的参数里有目录符号。<br /><ul><li>腾讯QQ 群网站的文件包含漏洞</li></li></ul><li>文件包含与远程代码执行<br />猜测漏洞原因<br /><ul><li>URLhttp://qun.qq.com/air/?w=n&c=/../../../../../../../../../etc/passwd%00.html&a=dismiss&g
  79. 79. 特殊字符从URL可看出,QUERY_STRING中的C参数为非法数据,夸目录的路径,而且后也%00URL编码的字符串。%00在传送到后端脚本中时,会被转成0。此特殊字符串在QUERY_STRING中,CGI规范(RFC3875)允许这个字符作为查询参数,提交到后端CGI脚本中,这个问题并不是个别网友认为的ngxin解析漏洞。跟他一毛钱关系都没。只是截断符号一样。</li></li></ul><li>文件包含与远程代码执行<br />猜测漏洞原因<br /><ul><li>程序引入</li></ul>c参数原本为json,猜测是程序这么写include('$_GET['c']'.".php");,代码中未处理这个问题,PHP把字符串当作文件名到硬盘查找此文件时,认为0为字符串的中止,所有字符0后面的字符被舍弃,导致这个问题。c参数“json”估计是让程序引入json相关类,对输出结果处理,输出为json格式。估计可能还有xml等其他格式的类。<br />
  80. 80. 服务器权限控制<br /><ul><li>DB权限只对固定web开放对于公用库,多个站点、应用都要访问的情况,建议只开放对主应用开放,其他应用走web api+密钥方式访问。以减小风险,防止部分应用安全性较差,造成DB用户密码泄漏。同时,减小耦合度,防止因DB服务器迁移等变更,漏掉某分应用配置信息变更带来的问题。统一接口,统一控制,更好的控制各个应用规范不一,造成数据格式较为混乱的情况。</li></li></ul><li>拒绝服务<br /><ul><li>什么是拒绝服务攻击通过向服务器发送大量垃圾信息或干扰信息的方式,导致服务器无法向正常用户提供服务的现象。
  81. 81. 配置引起的拒绝服务一次http通讯,通常要建立一个tcp连接,请求较多,会觉得很多的时间都浪费在建立tcp通讯上。这时,keepalive就派上用场当一个客户端向服务器发送http请求时,两者之间会建立一个tcp连接,然后服务器发回响应信息同时关闭连接。如果请求的的页面中含有别的资源连接,比如图片、flsah等,就会再次创建连接。KeepAlive的作用就是在第一次创建连接时,服务器会把这个tcp连接保持一段时间(服务器端会有一个keepaliveTime的最大时间,超过时间就断开连接)。这样就不会频繁的去建立tcp连接,同一次请求中的信息传递都可以使用同一个tcp连接。</li></li></ul><li>拒绝服务<br />keepalive引起的拒绝服务keepalive在web server里设置是否启用,以及超时时间,如果超时时间过长,恶意攻击者持续建立TCP连接,开启keepalive,不关闭,单台PC就有可能占满服务器的所有TCP连接。<br />这不可能?单台PC可用端口6W多单台PC+虚拟IP 10个,则建立60W个http 长连接服务器能同时支持60W以上个长连接?<br />
  82. 82. 拒绝服务<br /><ul><li>keepalive适用场景短时间内大量htt请求。对于一些文字性新闻站点,或者文字性论坛等站点,后端脚本服务器无需开启keepalive,因为用户几乎不太可能两个访问超过2-5秒,若这些服务器开启keepalive,意味着5秒(keepalive超时时间)之内只有一个http请求,在这之间,将占用这个TCP连接。如果用户很多的话,那其他用户将无法成功的与服务器建立通讯。TCP阻塞。相反,在图片、js等静态资源服务器比较适合 开启这个选项。微博、论坛、新闻等页面会有多个静态资源,当用户访问微博、论坛等页面时,浏览器发现返回的html中有较多静态组件,会瞬间建立多个http请求,下载这些资源,这时keepalive的优点就体现了。同时对于静态资源可设定一定的浏览器缓存时间,避免下次访问仍向服务器发送请求。</li></li></ul><li>拒绝服务<br /><ul><li>keepalive超时时间设定以腾讯微博为例,登录后首页建立了60个http请求,图片+js大约是40多请求,图片+js大约200k不到。200K对一般用户2M的ADSL来说,大约1s左右可加载完成。那么可设定超时时间为1s。也有可能很多用户在1s之内不能加载完成,具体的时间参数,可以根据运维获取的各地网友的网络情况来决定。当然200k的资源只是首页,其他页面或许不一样,这需要运维去监控决定。</li></li></ul><li>文件解析<br /><ul><li>什么是文件解析漏洞文件解析漏洞是指攻击者构造特殊URI,利用配置或者web server自身对URL中SCRIPT_NAME判断不当导致把非法文件当作脚本解析引起的问题。
  83. 83. nginx与php配置不当的问题去年,80sec团队公布了nginx与php配置不当引起其他非法资源被当成php解析的问题。http://test.com/a.jpg/1.php会把1.jpg当作php文件解析。
  84. 84. 为什么?不妨先看下CGI接口规范</li></li></ul><li>文件解析<br />[HTTP_HOST]<br />[HTTP_CONNECTION]<br />[HTTP_USER_AGENT]<br />[HTTP_ACCEPT]<br />[PATH]<br />[SERVER_SIGNATURE]<br />[SERVER_SOFTWARE]<br />[SERVER_NAME]<br />[SERVER_ADDR]<br />[SERVER_PORT]<br />[REMOTE_ADDR]<br />[DOCUMENT_ROOT]<br />[SERVER_ADMIN]<br />[REMOTE_PORT]<br />[GATEWAY_INTERFACE]<br />[SERVER_PROTOCOL]<br />[REQUEST_METHOD]<br />[QUERY_STRING]<br />[REQUEST_URI]<br />[SCRIPT_NAME]<br />[SCRIPT_FILENAME]<br />[PATH_INFO]<br />[PATH_TRANSLATED]<br />[PHP_SELF]<br />浏览器<br />phpcgi<br />nginx<br />http 协议<br />CGI 协议<br />
  85. 85. 文件解析<br /><ul><li>nginx与phpcgi通信采用CGI协议,发送服务器环境变量,当前域名、端口,客户端IP、端口、提交HTTP数据包的代理软件信息,HTTP包内容等;还包括当前请求的URI,QUERY_STRING、SCRIPT_FILENAME、SCRIPT_NAME、 PATH_INFO等信息通过CGI协议,STDIN交给后端PHP CGI,PHP CGI根据nginx提交来的信息,再进行解析操作。这里,PHP CGI是绝对相信NGINX提供的信息的,不管NGINX提交来的是什么,PHP CGI都会去当作php脚本来解析。
  86. 86. 再看ngxin+php的漏洞</li></li></ul><li>文件解析<br /><ul><li>nginx根据配置获取变量
  87. 87. SCRIPT_NAME=>fake.jpg/foo.php
  88. 88. SCRIPT_FILENAME=>webroot/fake.jpg/foo.php
  89. 89. PATH_INFO=> //空,根据正则,没匹配到
  90. 90. PATH_TRANSLATED=> //空[注意]
  91. 91. PHP.INI的cgi.fix_pathinfo的修复</li></ul>若cgi.fix_pathinfo的值为1<br /><ul><li>php-cgi会再次将SCRIPT_FILENAME的值进行查找PATH_INFO
  92. 92. phpcgi按照CGI规范获取的结果是SCRIT_FILENAME=>wwwroot/fake.jpg
  93. 93. foo.php将变成PATH_INFO,便按照PHP解析。</li></li></ul><li>文件解析<br /><ul><li>问题处在哪里?</li></ul>NGINX是按照配置文件进行匹配URI,获得SCRIPT_NAME以及PATH_INFO;PHP也是按照NGINX通过CGI协议传递的环境变量进行解析的。web server跟cgi脚本都没错,错是错在nginx配置文件内匹配的URI的正则表达式,以及php.ini内的cgi.fix_pathinfo再次的解析了SCRIPT_FILENAME。<br /><ul><li>解决办法</li></ul>关闭php.ini的cgi.fix_pathinfo配置项,或者if ( $fastcgi_script_name ~ ..*/.*php ) {<br />return 403;<br />}<br />此方法虽然可以屏蔽这个漏洞的发生,但一定程度上影响了正常的业务需求,比如这个URI “1.php/test/a.php?a=1”是合法的URI,却被阻止了。比如CodeIgniter、ThinkPHP等框架,这个方法将不适合。<br />
  94. 94. 文件解析<br /><ul><li>NGINX+php的新问题</li></ul>如下URL也会产生文件解析问题http://example.com/file.ext%00.php<br /><ul><li>此次问题跟80sec发现的是同一个漏洞吗</li></ul>假如在上一个漏洞修复的情况下,显然file.ext%00.php字符串中间没有目录的斜杠表示,不会触发PATH_INFO的问题。问题是file.ext%00.php通过nginx的配置中的正则匹配,之后nginx在将URI中的SCRIPT_NAME取出时,认为file.ext0.php(urldecode之后)中,存在null字符,便舍弃null字符之后的字符串.php,将SCRIPT_NAME设置为file.ext,不论php.ini中的cgi.fix_pathinfo是否启用,这个SCRIPT_FILENAME都是合法的字符,也是存在的,便发生解析错误的漏洞。所以,这两个问题不是同一个漏洞。只是在URI部分有点相像而已。而且,这才是NGINX漏洞,之前的并不是。<br /><ul><li>问题出在哪里</li></ul>null字符出现URI中,NGINX没有在匹配为PHP CGI解析之前判断SCRIPT_NAME中是否含有null空字符。而是先判断认为符合PHP-CGI解析的文件名,再判断文件名是否合法。<br />
  95. 95. 文件解析<br /><ul><li>解析漏洞发生的条件
  96. 96. 与CGI脚本在同一服务器上存在恶意代码的非脚本文件
  97. 97. 存在错误解析的漏洞
  98. 98. 如何防范
  99. 99. 不合法的文件不该被上传在服务器上,起码不该存在同一台服务器上
  100. 100. 不合法的URI不该通过匹配包含.phpURI的正则
  101. 101. 匹配URI中SCRIPT_NAME的正则如何写?
  102. 102. 按照程序开发习惯,目录命名中基本没有.这个字符;出现在URI中的文件名的中基本不会出现两个.这个字符。所以我给出的解决办法就是认为URI中出现的第一个.后面的拓展名是php的时候,才会交与php-cgi解析(当然,要先取出SCRIPT_NAME、PATH_INFO)。</li></li></ul><li>其他<br />弱口令、空口令redis、memcache等之类nosql默认不验证或者没验证,依赖操作系统进行访问控制。对于使用session保存会话,且将session保存至这些nosql中的话,无意是致命的,务必要有访问控制。<br />掩耳盗铃<br />if (!(is_admin($arrAuth))) {<br /> echo '<script>document.location.href="./"</script>';<br />}<br />if (!(is_admin($arrAuth))) {<br /> header("Location:http://test.com/login.php");<br />}<br />// 验证通过。。<br />
  103. 103. QA<br />知其然<br />知其所以然<br />梁启超《论小说与群治之关系》<br />

×