0x00 前言


写下本文的直接原因是拜读了庆尘大佬的文章(对SQL注入漏洞原理的思考 (qq.com),这也是本文的参考文章。推荐大家读读大佬的文章,感受大佬浅显易懂的文笔下的深邃思想。

0x01 信任输入

信任问题

安全问题的本质就是信任问题

例如对一个网站的开发来说

  • 信任普通用户的输入——前台漏洞
  • 信任管理员用户的输入——后台漏洞
  • 信任离线升级/在线升级/自动化升级/升级包——供应链攻击
  • 不信任任何输入——信任代码逻辑——逻辑漏洞

有时候信任是可以被提升的——越权。

防御核心

对应的安全方案有很多,但都可以简化为

输入——检测是否存在风险——输出

黑客往往是从输入入手。所以我们重点关心的问题也就是如何处理信任与输入的关系

0x02 控制流和数据流

可以将程序员的代码分割为两个部分

  • 一部分是控制代码走向的控制流代码
  • 另一部分是用来展示,存储,流转的数据流(包括输入的数据和程序员设定的数据)

,是被动,说明了数据流的数据不应该具有主动性。说实在一点,外来的数据不能影响内部的控制程序。一旦数据流可以入侵到控制流,那么漏洞也随之而生。

0x03 以SQL注入为例

薄弱的程序

先看一段简单的代码:

1
2
3
4
5
<?php
$db = init_db();
$username = $_GET['username'];
$db->query("select * from users where username = '$username'");
?>

这是一个最简单的SQL注入代码,再看看payload:

1
2
3
username=admin' and 1=1 #

username=' or 1=1 #

让我们理理逻辑:

1
输入——php字符变量——SQL语句——数据库

很好,这就搭建起了输入和后端的关系。

背后的原理

程序员希望我们输入的是正常的数据,也就是程序员期望得到一个不能影响控制流的输入流。

但是我们的payload通过绕过闭合,成功使数据流入侵了控制流。

正如上文所说:

​ 一旦数据流可以入侵到控制流,那么漏洞也随之而生。

  • 这里就引出了代码审计的两个核心
  • 能否让数据流逃逸到控制流
  • 业务逻辑可能产生的点在哪

0x04 预编译

以PHP的预编译为例:

1
2
3
4
5
6
7
8
9
// 创建连接 
$conn = new mysqli($servername, $username, $password, $dbname);
// 获取用户输入
$user_input = $_GET['user_input'];
// 使用预编译语句和参数绑定来防止 SQL 注入
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ?");
$stmt->bind_param("s", $user_input);
$stmt->execute();
$result = $stmt->get_result();

预编译为什么能防止SQL注入

预编译语句通过将SQL查询语句参数分开,使用占位符来代表参数,然后将用户输入的数据绑定到占位符上,确保了输入数据被正确地解释为字符串而不是SQL代码。因此,无论用户输入什么数据,都不会影响原始查询的结构和意图,从而有效地防止了SQL注入攻击。

让我们再理理思路:

  • 为什么需要使用预编译——因为要防止SQL注入
  • 为什么要防止SQL注入——防止数据流入侵到控制流
  • 怎样防止数据流入侵到控制流——将用户的输入限制到输入流

归根结底,还是要限制用户的输入,也就是回到了信任的问题上

0x05 结语

我写的这篇文章抄袭居多,思路生硬,但是仍然写出来,是因为学习安全需要对问题本质上的思考,哲学上的思考。不写,不得深思。

另外,我也很希望读到能上升到思想与哲学的文章,再次感谢庆尘大佬。