☰
SqliLabs搭建避坑指南:PHP与MySQL版本匹配及报错排查
2026/10/1 12:24:52 网站建设 项目流程

搭建 SqliLabs 这件事,说简单是真简单——源码往 Web 根目录一扔,改一行数据库账号密码,浏览器打开就能跑;说麻烦也是真麻烦,我见过太多人卡在一句Fatal error: Call to undefined function mysql_connect()或者一片纯白页面上,从下午折腾到半夜,最后开始怀疑是压缩包下载坏了。这篇就把我在 Windows 和 Linux 两边反复搭 SqliLabs 时踩过的坑摊开讲一遍,从环境选型的思路、版本匹配的底层逻辑,到数据库初始化、连接文件配置、报错逐条排查,尽量写成一份能直接照着抄的排查手册。

内容主要面向刚接触 Web 安全、准备自己搭个本地练习环境的朋友,也适合已经搭起来但卡在某一关跑不通的人。所有操作都建议只在自己本机或者有明确授权的实验环境里做,别拿这些手法去碰任何不属于你的系统,这个前提先摆在前面。下面按"想清楚再动手"的顺序来说。

1. 搭建前的整体思路与选型:为什么SqliLabs总在环境上翻车

1.1 先搞清楚SqliLabs到底依赖什么

很多人搭不起来,根源在于把 SqliLabs 当成一个普通的静态网站。它不是。它是一堆 PHP 脚本 + 一个 MySQL 数据库的组合,里面每一关都是一个独立的 PHP 页面,页面里写死了 SQL 查询语句,靠 URL 参数拼接进查询里,从而制造出可控的注入点。所以它同时强依赖三样东西:一个能解析 PHP 的 Web 服务器、一个能连上的 MySQL 服务、以及 PHP 与 MySQL 之间的那层扩展。

这三样东西里,任何一环版本对不上,页面就是打不开。最典型的就是那一整套mysql_*开头的老函数——mysql_connect()、mysql_query()、mysql_error()。这批函数在 PHP 5.5 就被标记为废弃,PHP 7.0 直接被移除。而 SqliLabs 的原始版本恰恰大量使用它们,于是当你在 PHP 7 或 PHP 8 环境下打开 Less-1,页面直接抛致命错误,白屏或者报Call to undefined function。这不是你操作错了,是版本天生不兼容。

搞明白这个依赖关系,后面的所有决策就都好理解了:你选的 PHP 版本,决定了你需要哪个分支的 SqliLabs;你选的 MySQL 版本,决定了认证方式会不会拦你;你选的集成环境,决定了改配置的入口在哪。

1.2 集成环境还是手工编译,两条路怎么选

我个人建议新手一律走集成环境这条路,比如 Windows 下的 phpStudy、XAMPP、WampServer,Linux 下用 apt 装 lamp 那一套。理由很实在:SqliLabs 本身的价值在于练注入思路,不在于练环境配置。集成环境自带 Apache + PHP + MySQL,还带一个图形化的版本切换面板,能让你在 PHP 5.6 和 PHP 7.4 之间一键切换,这对 SqliLabs 来说简直是刚需。

手工编译适合什么人?适合你已经能熟练处理httpd.conf、php.ini、my.cnf这三个文件,并且清楚LoadModule、extension_dir、default_authentication_plugin这些配置项各自管什么。如果你目前还分不清php.ini和httpd.conf的职责边界,那就别折磨自己,先用集成环境把靶场跑起来,把注入练明白,回头再去啃源码编译。

还有一种更省事的路子是用容器。现成的 Web 环境镜像拉下来,把 SqliLabs 目录挂进去,几分钟就能跑起来,环境隔离也干净,玩坏了直接删容器重来。代价是你得先对容器有一点基本概念,知道端口映射和目录挂载是怎么回事。

1.3 版本匹配是搭建成败的分水岭

我把这几年的经验压缩成一句话:PHP 版本决定你能不能跑起来,MySQL 版本决定你能不能连上,Web 服务器端口决定你能不能访问到。

具体到组合上,可以参照下面这张表来选,能避开绝大多数坑:

方案PHP 版本MySQL 版本适合人群备注
原版 SqliLabs + PHP 5.65.65.5 / 5.7想跑通全部 65 关最省心,老函数全在
兼容分支 + PHP 7.x7.0–7.45.7不想装老 PHP需下载 PHP7 兼容版本
兼容分支 + PHP 8.x8.0+8.0追求新环境部分关卡仍需微调
容器方案镜像自带镜像自带熟悉容器的人隔离好,删了不心疼

选 PHP 5.6 的理由很直接:它保留了完整的mysql_*函数族,你下载官方原版压缩包,解压即用,不需要改任何一行 PHP 源码。选 PHP 7 的理由是现在的集成环境默认就是 7.x,但你必须去找那个把mysql_*改成mysqli_*的兼容分支,并且确认兼容分支覆盖了你想要练的关卡范围。

注意:不要在同一台机器上同时装两个集成环境去抢 80 端口,端口冲突是新手最常遇到的"玄学问题"之一,后面会专门讲怎么排查。

2. 环境准备与关键配置的底层逻辑

2.1 PHP版本与mysql扩展的生死关系

先把这件事讲透,因为它是 90% 白屏问题的源头。PHP 连接 MySQL 有三代扩展:

  • mysql_*:第一代,过程式,PHP 5.5 废弃,PHP 7.0 移除。
  • mysqli_*:第二代,支持面向对象和过程式,至今可用。
  • PDO_MySQL:第三代,跨数据库统一接口,至今可用。

SqliLabs 原版几乎清一色用第一代。所以当你在 PHP 7 环境打开页面,PHP 引擎会告诉你找不到mysql_connect这个函数——不是没连上数据库,是连函数本身都不存在了。这时候你有两条路:

第一条,把 PHP 降到 5.6。集成环境面板里一般都有"PHP 版本"下拉框,选 5.6,点应用,重启 Apache。但要注意,切换版本的时候 Apache 需要重新加载对应的模块,改完不重启是无效的。

第二条,换兼容分支。社区里有人把源码里的mysql_*全部替换成了mysqli_*,并处理了参数顺序差异。这条路的前提是你能找到靠谱的分支,并且它的关卡目录完整。

不管走哪条路,都要确认php.ini里对应的扩展是打开的。检查方法是在 Web 根目录放一个phpinfo.php,内容就一行:

<?php phpinfo(); ?>

浏览器访问它,搜索mysql关键字。如果你看到mysqli的配置块,说明第二代扩展已启用;如果连mysql相关的块都搜不到,那就去php.ini里找extension=mysqli,把前面的分号去掉,保存后重启 Apache。

提示:phpinfo.php用完就删掉,留在公网可访问的目录里等于把服务器家底摊给所有人看。

2.2 MySQL版本与认证插件的兼容陷阱

这一条很多人第一次遇到会懵。MySQL 8.0 把默认的认证插件从mysql_native_password换成了caching_sha2_password。老的 PHP 客户端库不认识这个新插件,于是在连接阶段直接报错,典型信息是The server requested authentication method unknown to the client或者Authentication plugin 'caching_sha2_password' cannot be loaded。

现象是:数据库服务明明启动了,用命令行客户端能登上,Navicat 也能连,但网页就是连不上。这时候你会误以为是db-creds.inc里的密码写错了,反复改密码,改到怀疑人生。其实跟密码没关系。

解决办法是把对应用户的认证插件改回老的:

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码'; FLUSH PRIVILEGES;

或者更彻底一点,在 MySQL 配置文件my.ini(Windows)或my.cnf(Linux)的[mysqld]段里加上:

[mysqld] default_authentication_plugin=mysql_native_password

改完重启 MySQL 服务。我个人更推荐第二种,一次性解决,后续新建用户也不会再踩这个坑。

还有一种情况是字符集。MySQL 8 默认utf8mb4,MySQL 5.7 默认可能是latin1。如果导入 SQL 文件时编码对不上,数据库里存的中文会变成问号,虽然不影响注入练习,但看着膈应。导入前统一把连接字符集设成utf8,或者导入命令里显式指定:

mysql -u root -p --default-character-set=utf8 < security.sql

2.3 php.ini里几个必须动的开关

SqliLabs 是练习靶场,你的目标是"看到错误信息",所以有几个配置跟生产环境的常规建议是反着来的。

第一个是display_errors。默认在生产环境是关的,页面出错只给你一个空白或者 500。练注入的时候必须打开,否则报错注入那一类关卡根本没法做,因为页面上不显示任何数据库报错。

display_errors = On error_reporting = E_ALL

第二个是short_open_tag。部分老版本 PHP 代码里用的是<?短标签而不是<?php,如果short_open_tag = Off,这些文件里的 PHP 代码不会被解析,直接当纯文本吐到页面上。现象是你看到页面上一堆 PHP 源码原封不动显示出来,这基本就是这个开关的问题。

short_open_tag = On

第三个是时区。date.timezone没设置的话,PHP 会抛一个警告,虽然不影响功能,但会污染页面输出,干扰你看真正的报错信息。

date.timezone = Asia/Shanghai

这三个改完,老规矩,重启 Apache。顺带说一句,改php.ini之后不生效,八成是你改的不是当前生效的那一份。一台机器上装多个 PHP 版本时,每个版本目录下都有一份自己的php.ini,phpinfo()页面里有一行Loaded Configuration File,那才是真正生效的路径,照着这个路径去改。

2.4 目录权限与杀毒软件的隐形干扰

Windows 上还有一类特别隐蔽的问题:杀毒软件。SqliLabs 的源码里包含大量明显的注入 payload、webshell 片段、以及各种测试用的恶意字符串。实时防护一扫,直接把这些文件隔离或者删掉,结果就是你解压完发现有 65 个关卡目录,其中几个莫名其妙是空的,或者sql-connections目录里的文件少了一个,页面加载到一半报require_once(): Failed opening required。

处理办法很土但很有效:把整个 SqliLabs 目录加进杀软的信任区/排除列表,然后再重新解压一遍。别嫌麻烦,这一步不做,后面排查到天亮都找不到原因。

Linux 下则是权限问题。Apache 默认以www-data(Debian 系)或apache(RedHat 系)用户运行,如果目录属主是 root 且其他用户没有读权限,访问就是 403 Forbidden。

sudo chown -R www-data:www-data /var/www/html/sqli-labs sudo chmod -R 755 /var/www/html/sqli-labs

755 意味着所有人可读可执行、只有属主可写,对靶场来说足够。别图省事给 777,那只是在制造新的习惯性恶习。

3. 完整搭建流程:从零到跑通第一关

3.1 站点根目录的位置选择与放置

集成环境都有自己的 Web 根目录,phpStudy 一般是phpstudy_pro/WWW,XAMPP 是xampp/htdocs,Linux 上是/var/www/html。把解压出来的sqli-labs整个文件夹丢进去,最终结构应该长这样:

WWW/ └── sqli-labs/ ├── index.html ├── sql-connections/ │ ├── db-creds.inc │ ├── setup-db.php │ └── ... ├── Less-1/ ├── Less-2/ └── ... Less-65/

这里有个小细节:解压的时候经常会出现双层嵌套目录,变成sqli-labs/sqli-labs/Less-1。访问的时候路径就要多写一层,很多人以为是 404 是配置问题,其实只是目录套了两层。解压后先进去看一眼层级,该拍平的拍平。

访问地址是http://localhost/sqli-labs/或者http://127.0.0.1/sqli-labs/。用localhost和127.0.0.1在某些环境下行为不完全一致——前者可能走 IPv6 的::1,而 MySQL 或者 Apache 的监听配置只绑了 IPv4。如果localhost打不开而127.0.0.1能打开,就是这个原因。统一用127.0.0.1可以少一类麻烦。

提示:不要直接双击Less-1/index.php用文件方式打开,那是file://协议,PHP 代码不会被解析,你只会看到源码原文。

3.2 数据库初始化:setup-db到底做了什么

SqliLabs 目录里有个sql-connections/setup-db.php,这是整个靶场的数据库初始化脚本。它做的事情大致是:连接 MySQL,创建名为security的数据库(有些版本还会创建challenges库),然后建表、插入初始数据。建出来的核心表包括users、emails、uagents、referers这几张,分别对应不同的注入关卡场景——比如uagents表是给 User-Agent 注入用的,referers表是给 Referer 注入用的。

运行方式是浏览器访问:

http://127.0.0.1/sqli-labs/sql-connections/setup-db.php

如果脚本执行成功,你会在页面上看到类似"成功创建数据库和表"的提示,具体措辞各版本略有差异。执行失败的话,页面通常会直接抛出数据库连接错误,这时候问题就回到db-creds.inc上去了。

有些版本没有这个自动脚本,或者脚本只建表不插数据,那就需要手动导入 SQL 文件:

mysql -u root -p -e "CREATE DATABASE security DEFAULT CHARACTER SET utf8;" mysql -u root -p security < security.sql

导入完用一条命令验证:

USE security; SHOW TABLES; SELECT COUNT(*) FROM users;

users表里应该有十几条记录,如果COUNT(*)返回 0,说明数据没进去,注入练习时联合查询查不出东西,你会误以为是自己的 payload 写错了。

3.3 db-creds.inc:那一行配置改对了吗

这个文件是 SqliLabs 的数据库凭据配置,路径在sql-connections/db-creds.inc。内容大致是这样:

<?php $host = "localhost"; $dbuser = "root"; $dbpass = "root"; $dbname = "security"; ?>

四个变量逐一确认:$host建议写127.0.0.1而不是localhost,理由同上;$dbuser和$dbpass必须和你 MySQL 里的实际账号密码一致,集成环境常见的是 root/root 或者 root/空;$dbname一般保持security不动,除非你手动导库时改了名字。

这里失败的经典表现是:访问关卡页面,页面顶部弹出一行Connection failed: Access denied for user 'root'@'localhost'。看到这个就是在告诉你,账号或者密码不对,或者这个用户没有从localhost连接的权限。注意'root'@'localhost'和'root'@'127.0.0.1'在 MySQL 里是两个不同的账号条目,权限是分开授予的。如果确认密码没错但还是被拒,可以在 MySQL 里查一下:

SELECT user, host, plugin FROM mysql.user WHERE user = 'root';

看看有没有127.0.0.1这个 host 的记录,没有就补一条授权。

3.4 判断搭建是否真正成功

别急着从 Less-1 开始打。先做三步验证。

第一步,访问http://127.0.0.1/sqli-labs/,应该能看到一个带关卡列表的首页,这是最基本的 Web 服务通了。

第二步,访问 Less-1:

http://127.0.0.1/sqli-labs/Less-1/?id=1

页面应该正常显示一个用户名和密码。如果这一步就白屏,回头去看 2.1 节的 PHP 版本问题。

第三步,故意制造一个语法错误:

http://127.0.0.1/sqli-labs/Less-1/?id=1'

如果在id=1后面加一个单引号,页面回报一个You have an error in your SQL syntax的数据库错误,恭喜,环境完全正常,而且报错回显也是打开的,报错注入类关卡可以正常练。

这三步都过了,后面 65 关的环境基础就打好了。哪一步卡住,就照着对应章节排查。

4. 高频问题排查实录:那些让人抓狂的报错

4.1 常见报错速查表

先上一张表,遇到问题先对号入座,再看后面的详细分析。

报错信息 / 现象根本原因解决方向
Call to undefined function mysql_connect()PHP 7+ 移除了老扩展降到 PHP 5.6 或换兼容分支
页面纯白,什么都没有display_errors关闭,错误被吞打开错误显示,或查 Apache 错误日志
Access denied for user账号密码错或 host 权限不足核对db-creds.inc,补 host 授权
Authentication plugin 'caching_sha2_password'MySQL 8 新认证插件改回mysql_native_password
页面上直接显示 PHP 源码短标签未开启short_open_tag = On
403 Forbidden目录权限或索引未开chown+Options Indexes
404 Not Found路径错误或目录嵌套检查目录层级和大小写
No database selected数据库未创建或名称不符跑setup-db.php或手动建库
查询结果为空users表没数据手动导入数据 SQL
中文变问号字符集不匹配用 utf8 重新导入

4.2 白屏、403、404、500分别怎么查

白屏是最难查的,因为它什么都不告诉你。第一反应应该是去翻日志,而不是对着空白页发呆。Apache 的错误日志位置:Linux 下是/var/log/apache2/error.log或/var/log/httpd/error_log;Windows 集成环境一般在Apache/logs/error.log。日志里通常会明确写着是哪一行代码抛了什么错,比页面上猜半天高效得多。

如果日志里也没有,那基本可以确定是 PHP 的错误显示被关掉了。把display_errors打开,重新访问,错误就出来了。

403 Forbidden有两种。一种是权限问题,前面已经讲过用chown和chmod处理。另一种是目录索引没开——你访问的是目录而不是具体文件,Apache 没有index.php就拒绝列出目录内容。检查httpd.conf或者站点配置里的Options,需要有Indexes或者指向正确的默认首页文件。SqliLabs 每个关卡目录里都有index.php,正常不该出现这种情况,所以 403 更大概率是权限。

404 Not Found基本只有两个原因:路径写错,或者目录嵌套。再就是大小写问题,Linux 下文件系统区分大小写,less-1和Less-1是两个东西,URL 里必须跟目录名完全一致。

500 Internal Server Error最典型的原因是.htaccess配置里引用了服务器没加载的模块。SqliLabs 某些版本目录里带.htaccess,如果里面的指令 Apache 不认识,整个目录就 500。可以临时把.htaccess重命名成.htaccess.bak试试,能访问了就是它的问题。

4.3 端口冲突:80被占了怎么办

这个问题值得单拎出来讲,因为它的表现形式特别有迷惑性——所有服务看起来都启动了,数据库连得上,但浏览器就是打不开页面,或者打开的是另一个完全不相干的页面。

原因是你机器上还有别的东西在监听 80 端口。常见的抢占者包括:另一个 Web 服务器(IIS)、某些后台服务、以及各种做本地网络共享的软件。Windows 上查起来很简单:

netstat -ano | findstr ":80"

输出的最后一列是进程 PID,用任务管理器找到对应 PID 结束掉,或者干脆改 Apache 的监听端口。改端口在httpd.conf里:

Listen 8080

改完 URL 就要带上端口号:http://127.0.0.1:8080/sqli-labs/。改端口的时候记得有个坑:如果你配置了虚拟主机,VirtualHost那一行的端口也要同步改,只改Listen会出现请求打到默认站点上去的情况。

Linux 下换一条命令:

sudo lsof -i :80 # 或者 sudo netstat -tlnp | grep :80

4.4 关卡特有的那些"不是搭错了"的现象

环境跑通之后,练习过程中还会遇到一些看起来像报错、实际是设计如此的情况,提前说清楚能省下不少时间。

第一个是堆叠注入类关卡。Less-38 往后的部分关卡涉及多语句执行,需要 PHP 的mysqli扩展支持multi_query。如果你的 PHP 是老版本用mysql_*实现的,堆叠注入可能执行不了。这不是你 payload 的问题。

第二个是挑战模式。Less-54 之后的关卡是 challenge 模式,表名和列名是随机生成的,而且每次提交答案之后,后台会把数据库重置一遍。所以你会发现在这几关里刷新一下页面,之前查到的表名就变了。这是设计如此,逼你每次重新枚举。

第三个是注入点类型混淆。Less-1 到 Less-10 是 GET 型,Less-11 之后开始有 POST 型,再往后还有 Cookie 注入、User-Agent 注入、Referer 注入。很多人卡在 Less-18 之类的关卡上,反复改 URL 参数没反应,其实是因为注入点在 HTTP 请求头里,得用抓包工具改请求头才行,改 URL 当然没效果。

第四个是转义处理。部分关卡对输入做了转义或者过滤,你按前面关卡的思路直接怼 payload 会失败。这不是环境问题,是关卡本身在考你绕过思路。

提示:遇到某关怎么打都不通,先看这一关的源码。SqliLabs 的每一关源码都摆在那里,index.php里就那几行 SQL 拼接,看两眼就知道注入点在哪、过滤了什么。这比盲试 payload 高效十倍。

5. 让靶场跑得更稳的维护心得

5.1 快照、备份与环境隔离

搭一次不容易,别让它轻易崩。最值得做的一件事是:环境配好、数据库初始化完成之后,立刻给整机打一个快照,或者至少把 SqliLabs 目录和数据库导出文件各备一份。

mysqldump -u root -p --databases security challenges > sqli_backup.sql

为什么要备份?因为你在练习过程中一定会手滑。比如试着用DROP TABLE这类语句做堆叠注入练习,一不小心真把表删了;或者改db-creds.inc的时候改错了没记下来。有了备份,恢复就是两条命令的事:

mysql -u root -p < sqli_backup.sql

另外强烈建议把靶场放在虚拟机或者独立环境里,别跟日常办公、存资料的系统混在一起。靶场里跑的都是注入、文件包含这类测试代码,跟真实数据放在同一台机器上,风险和麻烦都不划算。

5.2 一台机器上多版本的和平共处

如果你同时还要练其他的 Web 靶场,可能会遇到版本需求冲突——有的要 PHP 5.6,有的要 PHP 7.4。集成环境提供了多版本目录,切换是改httpd.conf里的模块引用路径,或者用面板一键切。但切换后必须重启服务,而且切换前先确认原来的站点配置不会互相干扰。

数据库这边,不同靶场用不同的库名是个好习惯,security、dvwa、pikachu各用各的,避免一个靶场的初始化脚本把另一个的数据覆盖了。有些靶场的初始化脚本真的会DROP DATABASE再重建,共用库名就是自找麻烦。

注意:如果你换过端口、改过目录、动过php.ini,记得每次改完都做一次完整的回归验证——首页能不能开、Less-1 能不能出结果、报错能不能回显。只测一步很容易漏掉连带影响。

5.3 从"能跑"到"跑得明白"

环境搭通只是起点。真正让这段时间花得值钱的,是搭完之后回头把每一类的原理弄清楚。比如同样是报错注入,为什么extractvalue()和updatexml()能报出数据、能报出多少位、为什么有时候要配合limit一条条取;同样是布尔盲注,为什么用ascii()和substr()组合就能一位一位地猜出库名。这些理解,靠背 payload 是背不出来的。

我自己的习惯是,每打完一关就去看一眼源码,把这一关的 SQL 语句抄下来,标注出注入点在哪、过滤了什么、我的 payload 是怎么绕过去的。同一个关卡隔一周再做一遍,如果还能顺畅打下来,说明是真的懂了,而不是照着答案抄了一遍。

还有个小技巧:把setup-db.php的访问地址存成书签。练到一半发现数据被自己搞乱了,点一下就能重置到初始状态,比手动导库快得多。但记住重置会把你自己建的表、插的数据一并清掉,重置前想清楚。

环境这东西,搭一次踩一遍坑,第二遍就顺了。真正费时间的从来不是点几下鼠标,而是不知道报错背后是什么在作祟。把上面这些对应关系理清楚,下次再遇到mysql_connect找不到、密码明明对却连不上、页面白得发光,心里就有谱了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询