注入攻击-SQL注入和代码注入
《注入攻击-SQL注入和代码注入》要点: 注入攻击OWASP将注入攻击和跨站脚本攻击(XSS)列入网络应用程序十大常见安全风险.实际上,它们会一起出现,因为 XSS 攻击依赖于注入攻击的成功.虽然这是最明显的组合关系,但是注入攻击带来的不仅仅是 XSS. 注入攻击代指一类攻击,它们通过注入数据到一个网络应用程序以期获得执行,亦或是通过非预期的一个方式来执行恶意数据.这种类别的攻击包括跨站脚本攻击(XSS)、SQL 注入攻击、头部注入攻击、日志注入攻击和全路径暴露.当然限于篇幅,这里只是一个简单的介绍. 这类攻击是每个程序员的梦魇.它们数量庞大、攻击范围广,并且有时候防御措施很复杂,因此是最常见、成功率最高的网络攻击.所有的应用程序都需要从某个地方获取数据来运行.跨站脚本攻击和界面伪装漏洞最为常见,并且它们本身就已经非常重要,通常与注入攻击分开归类.接下来的一章我将单独介绍它们. OWASP 对注入攻击的定义如下: 类似SQL、OS、LDAP注入攻击等注入攻击会在不可信数据作为命令或请求的一部分被发送到解释程序时发生.攻击者的恶意数据会迷惑解释程序去执行非计划的命令,或访问非授权的数据. SQL 注入攻击目前最常见的注入攻击形式是臭名昭著的 SQL 注入攻击.SQL 注入攻击不仅常见,而且致命.我要特别强调,了解这种攻击、实现攻击的条件以及防御攻击需要采取的措施极为重要. SQL 注入攻击通过将数据注入网络应用程序,然后被用于 SQL 请求来操作.数据通常来自类似网页表单的不可信来源.不过,数据也可能来自包括数据库本身在内的其他来源.程序员通常会信任来自自己数据库的数据,以为它们是非常安全的,却没有意识到,在一种用法中安全,不代表它在所有其他用法中都是安全的.来自数据库在经过证明(比如说,通过验证流程)之前,应该被视为不可信. 如果攻击成功,SQL 注入攻击能够操纵受攻击的 SQL 请求,从而进行非程序员意愿的数据库操作. 看一下这条请求: git·$db = new mysqli(‘localhost’,‘username’,‘password’,‘storedb’); $result = $db->query( ‘SELECT * FROM transactions WHERE user_id = ‘ . $_POST[‘user_id’] ); ·git 上面的请求中存在多处问题.首先,我们还没有验证 POST 数据来确保这是个有效的 userid.其次,我们允许一个不可信来源告诉我们要使用哪个 userid——攻击者可以任意设置一个有效 userid.也许 userid 包含在一个隐藏的表单字段,因为网络表单不允许编辑,我们就以为安全了(却不知道攻击者可以提交任何信息).第三,我们并没有 escape 该 user_id,或将其作为一个绑定参数传给请求,由于我们一开始没有验证 SQL 请求,这就让攻击者有机会注入任意字符串来操纵该请求. 上述三点问题在网络应用程序中极其常见. 至于信任来自数据库的数据,想象一下我们使用 user_name 字段来搜索交易.用户名的范围相当广阔,可能还包含引用.可以想见,攻击者可以在一个用户名内储存一个 SQL 注入字符串.如果我们将数据库视为可信的数据来源,没能合理地 escape 或约束它,当我们在后续请求中再次使用该字符串时,它就可以操纵请求字符串. 另一个需要注意的 SQL 注入攻击因素是永久存储不需要总是在服务器上进行.HTML5 支持使用客户端数据库,可以借助 Javascript 使用 SQL 来查询.有两个支持这项操作的接口:WebSQL 和 IndexedDB.WebSQL 于2010年被 W3C 弃用,受到后台使用 SQLite 的 WebKit 浏览器支持.虽然这个接口不被推荐使用,但是 WebKit 处于后台兼容考虑,很有可能会继续支持它.正如它的名字所示,它接收 SQL 请求,因此容易遭受 SQL 注入攻击.IndexedDB 是一个新的备选,不过它是一种 NOSQL 数据库(不需要使用 SQL 查询). SQL 注入攻击范例尝试操纵 SQL 命令的目标包含以下几种:
信息泄露披露存储数据操纵存储数据避开权限管理防御 SQL 注入攻击防御 SQL 注入攻击可采用深度防御原则.在将数据用于 SQL 命令之前,应该进行验证,以确保它是我们期望的正确格式,并且在将数据包含在请求或绑定参数前,应该将其 escape. 验证第二章讲述输入验证,而且正如我在其中提到的,我们应该假设不是由当前请求的 PHP 源代码直接生成的所有数据都不可信.对其严格验证,并且拒绝所有未通过验证的数据.不要尝试“修复”数据,除非只是简单修正数据格式. 常见的验证错误包括只验证数据当下用途(例如,展示或计算),却不考虑数据最终存储位置的数据库表字段的验证需求. Escaping通过使用mysqli 扩展,你可以利用 mysqlirealescapestring() 函数来 escape包含在 SQL 查询中的所有数据.PostgresSQL 的 pgsql 扩展提供 pgescapebytea()、 pgescapeidentifier()、 pgescapeliteral() 和 pgescape_string() 函数.Mssql(微软 SQL 服务器)不提供 escaping 功能,而经常被推荐的 addslashes() 方法并不够用——你实际上需要一个定制功能http://stackoverflow.com/questions/574805/how-to-escape-strings-in-mssql-using-php. 再告诉你一件头疼的事,你绝对绝对不能在 escape 进入 SQL 查询数据上出错.一旦失手,可能就会引发 SQL 注入攻击. 基于以上原因,并不推荐使用 escaping.它可以用来救急,如果你用来抽象的数据库程序库不强制参数绑定就能进行 SQL 查询,可能就需要使用它.否则你应该避免使用 escape.它很混乱,容易出错,而且因数据库扩展不同而存在差异. 参数化查询(预处理语句)参数化或参数绑定是构建 SQL 查询的推荐方法,而且所有优秀的数据库程序库都默认使用这种方法.以下是使用 PHP 的 PDO 扩展的一个实例. if(ctype_digit($_POST['id']) && is_int($_POST['id'])) { $validatedId = $_POST['id']; $pdo = new PDO('mysql:store.db'); $stmt = $pdo->prepare('SELECT * FROM transactions WHERE user_id = :id'); $stmt->bindParam(':id',$validatedId,PDO::PARAM_INT); $stmt->execute(); } else { // reject id value and report error to user } (编辑:ASP站长网) |