DVWA(Damn Vulnerable Web Application),玩过Web安全测试的人基本都认识它。不管是为了练习SQL注入、XSS,还是熟悉CSRF、文件包含,本地搭一套DVWA都是最省事的路子。但搭建过程中,最劝退的环节往往不是漏洞利用,而是环境本身——十个人有七八个会栽在数据库连接这一步。
我第一次搭DVWA也在这块折腾了整整一个晚上。PHP、Apache装得飞快,MySQL建好库和用户,config/config.inc.php按教程改好,浏览器一刷新,红字弹出来:Could not connect to the database。后来排查得多了才发现,所谓“数据库连接失败”其实是一大类问题的总称,背后可能是服务没启动、驱动缺失、配置写错、权限不足、认证插件不兼容,每一条都能单独把你卡死。下面就把这条排查链路完整梳理一遍,从现象到根因,从命令到配置,按步骤来,基本十分钟内能定位。
1. 先分清报错类型:同样是数据库连不上,原因可能完全不同
第一次撞上这类问题的人,最容易做的事就是不断改密码、改config、重装MySQL,折腾一通还是原来的红字。其实报错本身已经给了足够的线索,只是大多数人只看第一句话,忽略了后半段的错误码。DVWA连接数据库失败,常见的有三种表现,每种对应完全不同的排查方向。
1.1 安装页面红字:直接指向配置与服务状态
DVWA首次访问时,脚本会尝试用config里的账号密码连接MySQL,连不上就显示一段很笼统的提示,大概长这样:
Could not connect to the database Please check the settings in the config file.这句提示本身没什么价值,有价值的是它下面那段详细信息,里面通常带着SQLSTATE错误码。我列一个对照表,方便大家一眼定位:
| 错误码/提示 | 实际含义 | 优先排查方向 |
|---|---|---|
| SQLSTATE[HY000] [1045] Access denied for user ... (using password: YES) | 用户名或密码不对,或者host权限不匹配 | config账号、MySQL用户表 |
| SQLSTATE[HY000] [2002] Connection refused | MySQL没监听这个端口,或者服务没启动 | 服务状态、端口占用 |
| SQLSTATE[HY000] [2002] No such file or directory | 连接的是Unix socket但路径找不到 | PHP与MySQL的socket配置 |
| SQLSTATE[HY000] [2002] Connection timed out | 网络不通或防火墙拦截 | 防火墙、bind-address |
先看SQLSTATE后面属于哪一类,再决定往哪个方向排查。第1045种情况最多,后面几节重点展开;2002和No such file这两类属于环境配置问题,按照第2节处理。
1.2 安装阶段通过,登录时却提示Login Failed
另一种情况更加隐蔽:打开setup.php页面时,数据库连接状态明明是正常的,点“Create / Reset Database”也没报错,但回到首页用默认账号admin/password登录,页面却提示Login Failed。
问题通常不在数据库连接,而在DVWA的初始化数据没有真正写进去。点击Create / Reset Database时,DVWA会建表并插入初始用户数据,如果config里配置的数据库账号只有SELECT权限、没有CREATE和INSERT权限,这个操作可能部分成功、部分失败,表面不报错,实际users表是空的。
遇到这种情况,先用命令行确认dvwa库里有没有users表:
USE dvwa; SHOW TABLES; SELECT * FROM users;没表或没数据,就回头检查数据库账号的权限,GRANT ALL PRIVILEGES ON dvwa.* TO ...,再回到setup.php重新执行一次Reset。另外,浏览器里的旧session也可能导致登录后立刻退出,换无痕窗口试试往往能当场解决。
1.3 白屏或500:先翻日志,再动配置
如果打开DVWA页面直接白屏,或者收到500 Internal Server Error,很多人下意识认为是config没配置好,开始反复改配置。实际上白屏和500通常是PHP层面的错误,比如mysqli扩展缺失、PHP版本与代码不兼容,日志里基本都有明确答案。
Debian/Ubuntu下可以这样看日志:
- Apache:tail -f /var/log/apache2/error.log
- Nginx + PHP-FPM:tail -f /var/log/nginx/error.log,以及/var/log/php*-fpm.log
- Windows + phpStudy:面板上的日志入口
也可以临时把php.ini里的display_errors设为On,让错误直接显示在页面上。我遇到过花半小时改配置没进展,最后发现就是php-mysql扩展没装的案例,日志里一行Call to undefined function mysqli_connect()直接就把问题说明白了。先看日志,往往比猜快十倍。
2. 服务层排查:MySQL到底有没有真正跑起来
不要一上来就改代码和配置。第一步永远是确认MySQL服务端本身是活的、可连接的。这个检查五秒钟的事,但能省掉后面一大堆疑神疑鬼。
2.1 查看服务状态,没有的话手动拉起来
在Linux上用systemd管理服务的环境里,查看状态即可:
sudo systemctl status mysql如果提示Unit mysql.service not found,那可能是因为很多发行版已经把MySQL替换成兼容的MariaDB,服务名是mariadb:
sudo systemctl status mariadb sudo systemctl start mariadb sudo systemctl enable mariadbenable那一步很容易被忽略,但很重要。不然你这次手动启动了,下次重启机器后服务又没起来,数据库又连不上了,你会误以为是配置问题,其实只是没设开机自启。
Windows环境下,在服务管理器里确认MySQL服务名称并启动。如果用的是phpStudy这类集成环境,直接在面板上点启动MySQL即可。注意,集成环境切换PHP版本或者改端口后,有时面板显示“已启动”,实际进程已经退出,重启面板一般能解决。
2.2 用命令行做最小验证,排除一切中间环节
检查服务端最好的办法是用mysql客户端直连:
mysql -u root -p输入密码后能进入交互界面,就说明服务端是好的。接着执行:
SELECT VERSION(); SHOW DATABASES;看看库列表里有没有dvwa库。如果你在命令行用root能登录,但在网页里连不上,说明问题不在服务端,而在PHP驱动或者config配置。如果你在命令行连都连不上,比如Access denied,那是MySQL用户本身有问题,先解决账号再说。
端口层面也值得确认,尤其是环境复杂的时候:
sudo netstat -ntlp | grep 3306看到监听列表里有3306才算正常。如果3306被其他程序占用,MySQL可能启动失败,这时要么改掉冲突程序端口,要么给MySQL指定其他端口并同步修改config文件里的端口配置。另外,有时MySQL进程启动了,但因为端口被占用,实际进程起了一半就退出,看一下端口监听状态比只看进程存在与否更准确。
2.3 监听地址与socket文件,两个容易被忽略的元凶
MySQL默认的bind-address是127.0.0.1,本地搭建没问题。但如果DVWA不是部署在本机,而是跑在容器里或远程服务器上,这个地址就要改成0.0.0.0或者对应的网卡地址,否则外部请求根本进不来。
另一个坑是Unix socket路径。PHP连接MySQL有两种通道:TCP(host为127.0.0.1或IP)和Unix Socket(host为localhost)。有的环境里PHP配置的socket路径和MySQL实际的socket路径不一致,比如PHP默认找/var/run/mysqld/mysqld.sock,而MySQL的实际位置不同,就会报“No such file or directory”这种看起来不太像数据库连接错误的错误。
解决办法是统一路径:要么在config里把db_server写成127.0.0.1强制走TCP,要么在php.ini里修正mysqli.default_socket和pdo_mysql.default_socket这两个配置项。我的经验是直接写127.0.0.1最省心,能少踩一个socket相关的坑。
3. 驱动层:PHP版本变了,连接方式也得跟着变
DVWA是个PHP项目,PHP到底用什么方式连MySQL,取决于PHP的数据库扩展。这一步出问题,代码配置全对照样连不上,而且报错方式五花八门。
3.1 三代数据库接口:兼容性差别很大
PHP连MySQL历史上主要有三类接口:
| 接口 | 活跃时期 | 当前状态 | 与DVWA的关系 |
|---|---|---|---|
| mysql_* 函数 | PHP 3~5.6 | PHP 7.0起已彻底移除 | DVWA 1.9及更早使用,新环境直接报致命错误 |
| mysqli 扩展 | PHP 5.0起 | 广泛使用,官方维护 | DVWA 2.x主要使用 |
| PDO_MySQL | PHP 5.1起 | 推荐使用,跨数据库 | DVWA 2.x也支持 |
这里最大的坑是版本错位。DVWA 1.9及以前的代码用的是mysql_connect这类老接口,在PHP 7.0以上的环境里会直接报Call to undefined function mysql_connect(),这根本不是数据库的问题,而是代码已经被PHP版本淘汰了。网上大量教程的截图还是老界面,新手照着下载了DVWA 1.9,然后在新环境里反复折腾数据库配置,永远无法解决。
遇到这种情况,直接用新版DVWA 2.x即可,代码已经切到mysqli/PDO,兼容PHP 7和8。
3.2 PHP 7/8环境缺少mysqli扩展的症状与修复
就算是新版DVWA,PHP环境缺少mysqli扩展也一样会出问题。症状通常是页面报错,提示未定义函数mysqli_connect,或者PDO driver不存在。
Ubuntu/Debian安装扩展很简单:
sudo apt install php-mysql sudo systemctl restart apache2如果你用的是Nginx + PHP-FPM,把restart apache2换成对应的php8.1-fpm服务名。
Windows下如果用phpStudy或手动安装的PHP,需要在php.ini里去extension=mysqli这一行前面的分号,同时确认extension_dir配置指向了正确的ext目录,改完一定要重启PHP或Web服务,不然不生效。
验证扩展是否生效,最快的方式:
php -m | grep mysqli或者在Web目录放一个phpinfo.php文件,内容写<?php phpinfo();,浏览器打开后搜索mysqli。有输出就说明扩展正常。phpinfo这个工具在排错时非常好用,能一次性看到PHP版本、加载的模块、各种配置路径,比到处翻文档靠谱。
3.3 驱动层的快速自查清单
到这一步,驱动层的排查其实是套固定动作,列个清单:
- 执行php -v确认PHP版本,DVWA 2.x建议PHP 7.0及以上。
- 执行php -m确认mysqli和pdo_mysql都在加载列表里。
- 打开phpinfo检查MySQL相关配置项,比如mysqli.default_socket路径。
- 确认下载的DVWA是2.x新版,不是1.9老版本。
我的经验是,如果在Linux上搭建,直接装系统源里的PHP 7.4或8.0配合php-mysql,基本不用为驱动操心。反而是Windows下手动配PHP容易漏掉extension_dir这个配置,报错千奇百怪,优先用集成环境最省事。
4. 配置层:config文件里的默认账号密码,为什么这么容易踩坑
DVWA的数据库连接配置集中在config/config.inc.php文件里。这个文件默认不存在,需要先复制一份config/config.inc.php.dist为config/config.inc.php,很多新手第一步就漏了,页面直接报找不到配置文件的错误。
4.1 默认配置解读:DVWA用的不是root账号
看一段典型的默认配置:
$_DVWA[ 'db_server' ] = '127.0.0.1'; $_DVWA[ 'db_database' ] = 'dvwa'; $_DVWA[ 'db_user' ] = 'dvwa'; $_DVWA[ 'db_password' ] = 'p@ssw0rd'; $_DVWA[ 'db_port' ] = '3306';这里有个关键点:默认账号是dvwa,密码是p@ssw0rd,数据库是dvwa,而不是root。很多人按老教程改成root和自己的密码,也不是不行,但要注意MySQL里root账号的host匹配规则。MySQL账号是由“用户名@主机”共同决定的,root@localhost和root@127.0.0.1在授权表里是两条独立记录,如果config里host写127.0.0.1,MySQL按TCP连接匹配的可能是'root'@'127.0.0.1'这条,如果你只授权了'root'@'localhost',那就会Access denied。
最简单稳妥的做法是:不用root,按DVWA默认创建一个专用账号,config保持默认不去改,减少出错概率。
4.2 建库建用户的标准SQL,一步到位
下面这段SQL可以把库和账号一次性准备好:
CREATE DATABASE IF NOT EXISTS dvwa CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER IF NOT EXISTS 'dvwa'@'localhost' IDENTIFIED BY 'p@ssw0rd'; GRANT ALL PRIVILEGES ON dvwa.* TO 'dvwa'@'localhost'; FLUSH PRIVILEGES;注意字符集用utf8mb4,对后面练习时存储中文字符内容更友好。创建完账号后,再回到setup.php页面点击Create / Reset Database,DVWA会自动完成建表和初始数据写入。
如果你改了MySQL端口,别忘了同步改config里的db_port,端口不一致的报错是Connection refused,很容易和服务没启动混淆。改完端口后,重启MySQL,并在命令行用-P参数测试新端口连通性。
4.3 改完配置不生效?可能是session和PHP-FPM在捣乱
配置改对了,数据库账号也没问题,但页面仍然报错,这种情况我见过不少,常见原因有三个:
第一,PHP-FPM或Apache没重启。config文件是PHP代码,每次请求都会重新读取,按理说不需要重启,但如果开了opcache扩展,某些环境下会缓存文件内容,重启一下服务最保险。
第二,浏览器残留旧session。DVWA会把数据库连接状态写进session,之前失败的状态会影响后续判断,清cookie或者换无痕窗口重试,可以当场验证是不是这个问题。
第三,文件路径搞错。确认你改的是config/config.inc.php,而不是config.inc.php.dist。有人复制文件后把.dist误删了,导致每次请求都读不到配置,报错信息却指向数据库连接,非常迷惑。
提示:修改config文件前先备份原文件,可以cp config.inc.php config.inc.php.bak。改坏了随时能回退,比重新下载整个项目省事。
5. MySQL 8.x 的认证插件:隐藏最深的一个大坑
这个坑大概是最折磨人的。现象是:命令行里用mysql -u dvwa -p能正常登录,授权看起来也全对,config也没问题,但PHP这边连数据库就是Access denied,错误信息一模一样。为什么会这样?因为MySQL 8.x默认的认证插件变了。
5.1 caching_sha2_password和旧版PHP驱动的不兼容
MySQL 5.7时代默认认证插件是mysql_native_password,PHP的mysqli和PDO驱动对这个插件支持得很成熟。MySQL 8.0起,默认改成了caching_sha2_password,安全性是提升了,但问题来了:较老版本的PHP mysqli扩展和libmysqlclient库对caching_sha2_password支持不完整,连接时会被MySQL拒绝,报Access denied。给人的感觉就像是密码写错了,但其实密码完全正确。
这个坑最麻烦的地方在于,错误信息里完全没有“认证插件不支持”这样的字眼,就是标准的SQLSTATE[HY000] [1045] Access denied。你可能会反复检查密码、检查用户权限、检查host匹配,就是想不到是插件兼容问题。
5.2 一条SQL把认证插件改回兼容模式
解决办法很直接,把目标用户的认证插件手动改回mysql_native_password:
ALTER USER 'dvwa'@'localhost' IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd'; FLUSH PRIVILEGES;如果新建用户,可以直接在创建时指定插件:
CREATE USER 'dvwa'@'localhost' IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd';需要注意的是,在MySQL 8.4及更新版本里,mysql_native_password插件开始被标记为废弃。所以我的建议是:本地搭DVWA如果没必要,直接用MariaDB就行了。MariaDB默认认证插件就是mysql_native_password,跟老PHP兼容性很好,不用折腾。
5.3 host匹配:localhost和127.0.0.1很容易给人下马威
前面提到过MySQL账号是由“用户名@主机”共同决定的,'dvwa'@'localhost'和'dvwa'@'127.0.0.1'是两条完全不同且独立的记录。PHP里config的db_server如果写127.0.0.1,MySQL按TCP连接处理,优先匹配的host可能是127.0.0.1或%,而不是localhost那条记录。如果你只创建了'localhost'的账号,就可能出现“命令行能连、PHP连不上”的怪象。
排查时可以查一下用户表,一目了然:
SELECT user, host, plugin FROM mysql.user WHERE user='dvwa';想省心的话,直接用host为'%'的账号:
CREATE USER 'dvwa'@'%' IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd'; GRANT ALL PRIVILEGES ON dvwa.* TO 'dvwa'@'%'; FLUSH PRIVILEGES;这样不管config里写localhost还是127.0.0.1,基本都能连上。测试环境这样放开没问题,生产环境千万别这么干。
6. 一套可复现的零到一搭建流程:照这个做基本不会翻车
前面几节都在讲排查,这一节给出一套完整、可照抄的流程。新手不熟悉环境,不一定有耐心逐项排查,用这套组合拳,能少踩几个坑。
6.1 推荐的环境组合与选型理由
我试过很多组合,总体感受是:
- Ubuntu 22.04 + PHP 7.4/8.1 + MariaDB 10.x + DVWA 2.x,最省心
- Windows + phpStudy集成面板 + PHP 7.4 + MySQL 5.7/MariaDB,次之
- Docker方式,一条命令能跑起来,但要稍微理解端口映射和容器数据卷
为什么首推MariaDB?因为它兼容MySQL协议,但默认认证插件就是mysql_native_password,省去了MySQL 8.x认证插件不兼容老PHP驱动的折腾。DVWA是学习用途,追求的是快速跑起来,没必要在认证插件上浪费时间。
6.2 Ubuntu下的完整步骤
以Ubuntu 22.04为例,从零开始:
- 安装Web环境:
sudo apt update sudo apt install -y apache2 php php-mysql php-mbstring mariadb-server unzip- 确认MariaDB服务:
sudo systemctl enable --now mariadb sudo systemctl status mariadb- 下载部署DVWA:
cd /var/www/html sudo wget https://github.com/digininja/DVWA/archive/refs/heads/master.zip sudo unzip master.zip sudo mv DVWA-master dvwa sudo chown -R www-data:www-data dvwa如果网络环境下载这个包比较吃力,可以从其他镜像或者国内软件源找DVWA 2.x的包,只要是新版就行。
- 配置config文件:
cd /var/www/html/dvwa/config sudo cp config.inc.php.dist config.inc.php sudo nano config.inc.php确认db_server、db_database、db_user、db_password四个值符合预期,一般默认就是dvwa / p@ssw0rd。
- 创建数据库和账号:
sudo mysql -u rootCREATE DATABASE IF NOT EXISTS dvwa CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER IF NOT EXISTS 'dvwa'@'localhost' IDENTIFIED BY 'p@ssw0rd'; CREATE USER IF NOT EXISTS 'dvwa'@'127.0.0.1' IDENTIFIED BY 'p@ssw0rd'; GRANT ALL PRIVILEGES ON dvwa.* TO 'dvwa'@'localhost'; GRANT ALL PRIVILEGES ON dvwa.* TO 'dvwa'@'127.0.0.1'; FLUSH PRIVILEGES;这里同时创建两个host的账号,就是为了直接绕开第5.3节说的host匹配问题。
- 打开安装页面:
浏览器访问http://你的服务器IP/dvwa/setup.php,点击“Create / Reset Database”。页面显示数据库连接正常,基本就成功了。
- 登录系统:
回到首页,用admin/password登录。登录后可以在DVWA Security选项卡把难度调成Low或Medium,开始正常练习。
6.3 建完库之后顺手做的状态核验
登录成功后,建议进数据库看一眼:
SHOW TABLES FROM dvwa;应该能看到guestbook和users等表。users表里应有admin、gordonb、1337等默认测试账号。确认这些表和数据存在,后续做题时登录和注入功能才不会出现莫名的异常。
同时检查防火墙:如果是在云主机或虚拟机上搭,别人要访问的话,80端口需要在防火墙或安全组里放行。如果是本机自测,这一步可以跳过。
6.4 后续使用中会碰到的几个小问题
- 页面提示没有初始化,重新访问setup.php并再点一次Reset Database即可。
- 某几个题目模块报错但页面整体能用,大多是数据库用户权限不足,确认GRANT ALL已经执行。
- 文件包含模块可能需要修改php.ini里的allow_url_include配置,等玩到那一节课再调就行。
- 登录成功后想切换难度级别时,如果提示session异常,清一下浏览器cookie再登录。
把这条链路走通之后,DVWA基本不会再因为数据库连不上而耽误时间了。
最后再分享一个实际经验:我后来搭DVWA基本固定用MariaDB,很少再碰认证插件不兼容的坑。如果实在要用MySQL 8.x,记住一个排查顺序——先看服务在不在跑,再确认扩展装没装,然后核对config和账号权限,最后检查用户认证插件。按这个顺序走,十分钟内基本能定位。排错还有一个心得:永远先看完整错误行,而不是只看第一句,SQLSTATE后面的错误码才是真正的路由。