代码层面漏洞修复:从一个登录框说起

上周帮朋友改他写的登录页面,发现输入用户名 admin' OR '1'='1 后,居然直接跳进后台了。这不是教科书式的 SQL 注入吗?问题不在功能,而在代码写法。

漏洞不是黑客造的,是代码漏的

很多新手觉得“只要功能跑通就行”,但真实世界里,用户输入永远不可信。比如下面这段 PHP 代码:

$username = $_POST['user'];
$password = $_POST['pass'];
$sql = "SELECT * FROM users WHERE name = '$username' AND pass = '$password'";
$result = mysqli_query($conn, $sql);

当用户输进 admin' -- ,SQL 就变成:
SELECT * FROM users WHERE name = 'admin' -- ' AND pass = ''
后面条件被注释掉,绕过密码验证。

修复不是加个判断,是换种写法

真正有效的修复,是让数据和逻辑彻底分开。用预处理语句(Prepared Statement):

$stmt = $pdo->prepare("SELECT * FROM users WHERE name = ? AND pass = ?");
$stmt->execute([$username, $password]);
$user = $stmt->fetch();

问号占位符不拼接字符串,数据库自动把输入当纯数据处理,再狠的单引号也翻不出浪花。

其他常见场景顺手修一修

表单提交后跳转 URL?别直接 echo $_GET['redirect'],容易跳到钓鱼站。改成白名单校验:

$allowed = ['dashboard.php', 'profile.php', 'settings.php'];
$target = $_GET['redirect'] ?? 'dashboard.php';
if (in_array($target, $allowed)) {
  header("Location: " . $target);
}

前端显示用户昵称?别直接 innerHTML 插入:
document.getElementById('name').innerHTML = data.name;
换成 textContent 或做 HTML 转义,防 XSS。

代码层面漏洞修复,本质就是一句话:信任数据,不如信任规则;拼接逻辑,不如隔离输入。