一、先建立整体画面:网站像一家餐厅
假设你在网站上点“登录”。
可以把整个过程想象成去餐厅吃饭:
所以一次登录大概是这样:
你输入账号密码
↓
浏览器发送 HTTP 请求
↓
Web 服务器接收请求
↓
PHP 检查输入是否合法
↓
PHP 去 MySQL 查询用户
↓
MySQL 返回查询结果
↓
PHP 判断密码是否正确
↓
浏览器显示“登录成功”或“登录失败”这篇文章的所有内容,基本都是围绕这条链路展开。
二、全文结构拆分
文章可以分成四大块:
第一部分:网站整体怎么组织
关键词:
B/S 架构
前后端分离
MVC
RESTful API
这一部分回答的是:
一个 Web 应用由哪些角色组成?它们怎么分工?
第二部分:PHP 怎么接收数据、操作数据库
关键词:
$_GET$_POST输入验证
PDO
预编译语句
文件上传
密码哈希
这一部分回答的是:
用户提交的数据到了服务器后,PHP 应该怎么安全地处理?
第三部分:做一个真正的留言板
关键词:
注册
登录
Session
发布留言
修改留言
删除留言
数据流安全分析
这一部分回答的是:
把前面学的知识组合起来,做一个完整的小网站。
第四部分:网站上线后的服务器与安全
关键词:
Apache
Nginx
Java Web
日志
中间件
安全响应头
PHP 框架
这一部分回答的是:
代码写完以后,网站是怎么运行起来的?服务器怎么保护网站?
三、第一部分:Web 应用架构
1. B/S 架构是什么?
B/S 是:
B:Browser,浏览器
S:Server,服务器
也就是:
浏览器 ←→ 服务器 ←→ 数据库我们平时打开网页、登录账号、提交表单,本质上都是:
浏览器向服务器发请求;
服务器处理请求;
服务器把结果返回给浏览器。
传统 B/S 架构
传统方式是:
服务器直接生成完整网页,浏览器只负责显示。
比如你点击“下一页”:
浏览器发请求
↓
PHP 查询数据
↓
PHP 生成一整张 HTML 页面
↓
浏览器重新加载整个页面这就像你每改一个菜,都要把整张餐桌重新摆一遍。
特点:
简单;
对搜索引擎友好;
但每次操作经常刷新整个页面;
用户体验相对较差。
2. 前后端分离是什么?
现代网站通常会把“页面”和“数据”分开。
前端 React/Vue
↓ 请求数据
后端 API
↓ 查询
数据库后端不再直接返回完整 HTML,而是返回 JSON 数据,例如:
{
"id": 1,
"username": "admin"
}前端拿到数据后,再用 JavaScript 把数据显示在页面上。
用餐厅比喻
传统模式:
后厨把菜完全做好、摆盘完成,再端给你。
前后端分离:
后厨把加工好的食材交给前台,前台再根据你的餐桌界面进行摆盘。
优点
页面不用每次整体刷新;
一套后端可以同时支持网页、手机 App、小程序;
前端和后端可以分开开发、分开部署。
安全重点
前后端分离以后,前端页面只是“皮肤”。
真正重要的是后端 API,因为数据都通过 API 进出。
所以安全测试时重点看:
API 是否验证身份;
API 是否检查权限;
API 是否过滤输入;
API 是否返回了不该返回的数据。
3. MVC 是什么?
MVC 是一种“分工方式”,把后端代码分成三类。
用户请求进来后:
用户请求
↓
Controller 接收请求
↓
调用 Model 查询或修改数据
↓
Controller 拿到结果
↓
交给 View 生成页面
↓
返回给用户举个例子
用户要查看自己的留言:
Controller 接收请求:“用户想看留言”;
Model 去数据库查询留言;
View 把留言排版成 HTML;
浏览器显示出来。
为什么要分 MVC?
因为混在一起会很乱。
如果接收请求、查询数据库、显示页面都写在一个文件里,项目小还能看,项目大以后就很难维护。
4. RESTful API 是什么?
RESTful API 可以理解为:
前后端之间约定好的一套“访问规则”。
例如用户资源叫:
/api/users不同操作通过 HTTP 方法区分:
可以把它理解成:
URL 表示“操作什么东西”;
HTTP 方法表示“要做什么”。
例如:
DELETE /api/users/42意思不是访问一个叫 DELETE 的页面,而是:
删除编号为 42 的用户。
四、第二部分:PHP 如何处理用户数据
这一部分最重要,因为很多安全问题都发生在这里。
1. $_GET 和 $_POST 是什么?
它们是 PHP 用来接收用户数据的“收件箱”。
$_GET
通常接收 URL 后面的数据。
例如:
search.php?keyword=test&page=2其中:
keyword = testpage = 2
PHP 可以这样拿:
$keyword = $_GET["keyword"];
$page = $_GET["page"];可以理解为:
用户把参数写在“快递单外面”,一眼就能看到。
$_POST
通常接收表单提交的数据,比如:
登录密码;
注册信息;
留言内容。
PHP 可以这样拿:
$username = $_POST["username"];
$password = $_POST["password"];可以理解为:
用户把数据放进“包裹里面”提交给服务器。
但注意:
POST只是不像GET那样直接显示在地址栏,并不代表它绝对安全。
攻击者仍然可以修改 POST 数据。
2. 为什么“永远不要相信用户输入”?
因为用户提交给你的不一定是正常内容。
比如正常用户输入用户名:
zhangsan攻击者可能输入:
<script>alert(1)</script>或者:
admin' OR '1'='1所以服务器必须先检查:
长度对不对;
类型对不对;
格式对不对;
是否在允许范围内;
是否包含危险内容。
生活类比
别人寄给你一个包裹,你不能直接打开使用,而要先检查:
是不是你期待的东西;
尺寸是否正常;
有没有危险物品;
寄件信息是否可信。
用户输入也一样。
3. 输入验证是做什么的?
文章里列了几种验证方式。
类型验证
比如年龄必须是数字:
$age = filter_input(INPUT_POST, "age", FILTER_VALIDATE_INT);如果用户输入的是:
abc那就不能接受。
长度验证
比如用户名必须在 3 到 20 个字符之间:
if (strlen($username) < 3 || strlen($username) > 20) {
die("用户名长度必须在 3-20 之间");
}防止用户提交特别短、特别长或者无意义的数据。
白名单验证
白名单的意思是:
只允许明确列出来的值,其他全部拒绝。
<?php
$role = $_POST["role"] ?? "";
$allowed_roles = ["user", "editor", "moderator"];
if (!in_array($role, $allowed_roles)) {
die("无效的角色");
}
>例如用户角色只能是:
["user", "editor", "moderator"]如果用户提交:
admin但系统不允许用户自己选择 admin,就拒绝。
这比“只禁止某些危险值”更安全。
正则验证
正则表达式就是“格式检查器”。
$phone = $_POST["phone"] ?? "";
if (!preg_match('/^1[3-9]\d{9}$/', $phone)) {
die("手机号格式不正确");
}例如检查手机号:
/^1[3-9]\d{9}$/意思是:
必须以 1 开头;
第二位必须是 3 到 9;
后面还有 9 位数字;
总共 11 位。
你不用一开始背正则,先知道它是“检查格式”的工具即可。
4. PDO 是什么?
PDO 是 PHP 连接数据库的一种标准方式。
PDO(PHP Data Objects)是 PHP 操作数据库的标准接口,支持预编译语句(Prepared Statements),是防御 SQL 注入的正确方式。
你可以把它理解成:
PHP 和 MySQL 之间的“翻译器”和“通信管道”。
PHP 不直接摸数据库,而是通过 PDO:
PHP → PDO → MySQLPDO 可以做这些事:
连接数据库;
查询数据;
新增数据;
修改数据;
删除数据。
5. SQL 注入是什么?
先看危险写法:
$sql = "SELECT * FROM users WHERE username = '$username'";这相当于把用户输入直接拼进 SQL 句子里。
如果用户输入:
admin' OR '1'='1最终可能变成:
SELECT * FROM users WHERE username = 'admin' OR '1'='1'数据库就会理解为:
只要用户名是 admin,或者 1 等于 1。
而 1=1 永远成立,所以攻击者可能绕过登录。
生活类比
原本 SQL 是一句固定命令:
请帮我找到名字叫“张三”的人。
正常名字应该只是填空。
但 SQL 注入相当于用户在空格里面写:
张三,顺便把保险柜也打开。
如果服务器直接照搬,就会出大问题。
6. 预编译语句为什么安全?
安全写法是:
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username");
$stmt->execute([":username" => $username]);它的核心思想是:
SQL 结构和用户数据分开发送。
可以理解为给数据库一张固定表格:
查询用户名 = ______用户只能往空格里填“值”,不能修改表格本身。
即使用户填的是:
admin' OR '1'='1数据库也只会把它当成一个普通字符串,而不是 SQL 命令。
小白记住一句话
不要把用户输入直接拼进 SQL,要用 PDO 预编译。
7. password_hash() 是什么?
注册时,绝对不能把密码明文存进数据库。
错误做法:
用户名:zhangsan
密码:123456如果数据库泄露,所有用户密码都会直接暴露。
正确做法是哈希:
$hash = password_hash($password, PASSWORD_DEFAULT);哈希像什么?
像把肉放进绞肉机:
原始密码 → 哈希结果但是你很难从绞肉恢复成原来的肉。
所以哈希是一种“不容易逆向”的处理方式。
登录时用:
password_verify($password, $user["password_hash"]);它会判断:
用户这次输入的密码,和数据库里的密码哈希是否匹配。
8. Session 是什么?
HTTP 本身记性不好。
你访问登录页面和访问首页,对服务器来说可能是两次完全独立的请求。
Session 就像健身房发给你的手环:
你登录成功;
服务器给你一个身份标识;
之后你每次访问页面都带着它;
服务器一看,就知道你已经登录了。
代码里:
$_SESSION["user_id"] = $user["id"];意思是:
在服务器端记录“当前这个用户是谁”。
登录成功以后还要执行:
session_regenerate_id(true);相当于换一个新的手环,防止别人提前塞给你一个旧手环冒充登录状态。
五、第三部分:留言板项目到底在做什么?
文章中的留言板项目包含:
注册;
登录;
发布留言;
查看留言;
修改留言;
删除留言。
这就是所谓的 CRUD:
几乎大部分网站都是在做这四件事:
用户系统:新增用户、查看用户、修改资料、删除账号;
电商系统:新增商品、查看商品、修改商品、下架商品;
留言板:新增留言、查看留言、修改留言、删除留言。
项目文件可以理解为一栋小房子
guestbook/
├── config.php
├── db.php
├── auth.php
├── index.php
├── register.php
├── login.php
├── logout.php
├── post.php
├── edit.php
├── delete.php
└── templates/简单理解:
这样做的目的是:
不要把所有代码都塞进一个文件,而是让每个文件负责一件事。
注册功能的完整逻辑
注册不是简单地“把用户名密码存起来”,而是:
接收用户名和密码
↓
检查用户名长度和格式
↓
检查密码长度
↓
检查两次密码是否一致
↓
检查用户名是否已经存在
↓
对密码进行哈希
↓
存入数据库也就是:
先检查,再处理,最后才入库。
登录功能的完整逻辑
登录流程是:
接收用户名和密码
↓
根据用户名查询数据库
↓
判断用户是否存在
↓
用 password_verify 验证密码
↓
成功后创建 Session
↓
跳转到首页注意文章中的一个细节:
用户名或密码错误它不会明确告诉你:
用户名不存在;
还是密码错误。
因为如果提示太具体,攻击者就可以判断哪些用户名存在。
例如:
提示“用户不存在”:说明账号没注册;
提示“密码错误”:说明账号存在,只是密码不对。
这会给攻击者提供信息。
修改和删除为什么要检查权限?
假设每条留言都有 ID。
你登录后可以删除自己的留言:
delete.php?id=10但如果系统只检查“你有没有登录”,不检查“这条留言是不是你的”,那么你可能把地址改成:
delete.php?id=11然后删掉别人的留言。
这就是典型的越权问题。
所以正确逻辑应该是:
检查用户是否登录;
查询这条留言;
判断留言作者是不是当前用户;
只有作者是本人,才允许修改或删除。
六、数据流安全分析:全文最核心的思想
文章最重要的图其实是这一条:
用户输入
↓
前端验证
↓
HTTP 请求
↓
PHP 接收数据
↓
服务端验证
↓
SQL 查询
↓
数据库执行
↓
PHP 生成页面
↓
浏览器显示这条路径上的每一步都可能出问题。
1. 前端验证为什么不安全?
前端验证就是浏览器里的 JavaScript 检查,比如:
密码必须 6 位;
邮箱格式必须正确;
用户名不能为空。
它主要是为了让用户体验更好。
但攻击者可以:
禁用 JavaScript;
用工具直接构造请求;
修改浏览器提交的数据。
所以:
前端验证只能提升体验,不能作为真正的安全防线。
真正的安全检查必须放在服务器端。
2. SQL 注入发生在哪里?
发生在:
Text
PHP 接收输入 → 拼接 SQL → MySQL 执行防御方式:
使用 PDO 预编译,不直接拼接用户输入。
3. XSS 是什么?
XSS 可以理解为:
攻击者把一段恶意脚本当作普通内容提交给网站,网站又把它显示给其他用户。
例如攻击者提交留言:
<script>alert(1)</script>如果网站直接显示,其他用户打开页面时,浏览器会把它当成代码执行。
防御方式:
htmlspecialchars($content, ENT_QUOTES, "UTF-8");它会把特殊符号转换成普通文本。
比如:
<script>变成类似:
<script>浏览器就会把它当文字显示,而不是当脚本执行。
小白记住
进数据库前防 SQL 注入,显示到页面前防 XSS。
4. 文件上传为什么危险?
如果网站允许用户上传头像,但不检查文件类型,攻击者可能上传:
shell.php如果服务器把它当 PHP 文件执行,攻击者就可能控制网站。
所以上传文件时应该:
限制文件类型;
限制文件大小;
不使用用户原始文件名;
重新生成随机文件名;
上传目录尽量不要允许执行 PHP。
七、第四部分:服务器、中间件和日志
1. Apache 和 Nginx 是什么?
它们是 Web 服务器。
可以理解为:
网站门口的接待员。
浏览器访问网站时,请求先到 Nginx 或 Apache,再由它们决定:
请求的是静态文件,直接返回;
请求的是 PHP 页面,就交给 PHP 处理;
请求的是后端接口,就转发给后端服务。
简单分工:
浏览器
↓
Nginx / Apache
↓
PHP
↓
MySQL2. 安全响应头是什么?
安全响应头可以理解为:
服务器告诉浏览器:“请遵守这些安全规则。”
例如:
X-Frame-Options: DENY意思是:
不允许别人把本网站嵌入 iframe 中,降低点击劫持风险。
还有:
X-Content-Type-Options: nosniff意思是:
浏览器不要自作主张猜测文件类型,防止把文本误当成脚本执行。
以及:
Content-Security-Policy: default-src 'self'意思是:
默认只允许加载本站资源,减少恶意脚本来源。
你可以把安全响应头理解成网站贴在门口的规章制度。
3. 为什么要隐藏服务器版本?
比如服务器返回:
Apache/2.4.49攻击者看到后,就可能搜索:
Apache 2.4.49 有什么已知漏洞?
所以要尽量隐藏详细版本信息,减少给攻击者的提示。
4. 日志是什么?
日志就像网站的监控录像。
它会记录:
谁访问了网站;
什么时间访问的;
访问了哪个地址;
使用了什么浏览器或工具;
请求是否成功。
例如安全人员可以通过日志发现:
某个 IP 访问特别频繁;
有人尝试 SQL 注入;
有人使用扫描工具;
有人频繁访问不存在的路径。
例子
统计访问次数最多的 IP:
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10你不用先背命令,只需要理解它在做:
提取 IP
↓
排序
↓
统计每个 IP 出现次数
↓
按次数从高到低排列
↓
取前 10 名5. 中间件是什么?
中间件是位于用户和后端服务之间的“中间层”。
它们不是业务代码本身,但会影响网站安全和稳定性。
6. Java Web 部分需要掌握什么?
这部分不用一开始深入 Java。
只需要知道:
Java 也能开发 Web 后端;
Servlet 类似“处理某个 URL 请求的程序”;
Spring Boot 是常见 Java Web 框架;
Java 项目也会分成 Controller、Service、Repository、Model。
它和 PHP 的对应关系大概是:
安全思路类似:
是否参数化查询;
是否验证输入;
是否编码输出;
是否检查权限;
是否暴露调试信息。
八、把全文压缩成一张“小白地图”
你可以把整篇文章理解成下面这张图:
一、先知道网站怎么组成
浏览器 → Web 服务器 → 后端程序 → 数据库
二、再知道后端怎么分工
Controller 管请求
Model 管数据库
View 管页面展示
三、然后学习 PHP 如何处理请求
GET/POST 接收数据
输入验证过滤危险内容
PDO 预编译操作数据库
password_hash 保存密码
Session 记住登录状态
四、接着做一个留言板
注册、登录、发留言、改留言、删留言
五、最后把网站放到服务器上
Nginx/Apache 接收访问
配置安全响应头
分析访问日志
使用 WAF、CDN 等中间件九、最值得你优先掌握的 10 个概念
如果你是完全小白,可以按这个顺序学:
第一组:网站运行基础
1. 浏览器
负责展示页面、提交请求。
2. 服务器
负责接收请求、运行后端代码。
3. 数据库
负责长期保存数据。
4. HTTP
浏览器和服务器之间的通信规则。
第二组:代码分工
5. 前端
负责用户看到的界面。
6. 后端
负责业务逻辑,比如登录、注册、查询留言。
7. MVC
把后端代码分成 Controller、Model、View,方便维护。
第三组:安全核心
8. 输入验证
不直接相信用户提交的数据。
9. 预编译语句
防止用户输入被当成 SQL 命令执行。
10. 输出编码
防止用户输入被浏览器当成脚本执行。
十、用一句话记住每个安全点
十一、建议你这样学这份内容
第一步:先画请求流程
不要急着看代码,先把这个流程画熟:
浏览器输入数据
→ HTTP 请求
→ Web 服务器
→ PHP
→ MySQL
→ PHP
→ HTTP 响应
→ 浏览器显示第二步:理解注册和登录
注册重点看:
输入是否合法;
用户名是否重复;
密码是否哈希;
是否用预编译插入数据库。
登录重点看:
根据用户名查询;
用
password_verify验证密码;登录成功后写 Session;
错误提示不要暴露具体原因。
第三步:理解增删改查
重点回答四个问题:
新增留言时,用户输入怎么进数据库?
查询留言时,数据怎么从数据库到页面?
修改留言时,怎么确认只能改自己的?
删除留言时,怎么防止删除别人的?
第四步:最后看服务器配置
先知道 Nginx/Apache 是“接待员”,再学习:
如何隐藏版本;
如何添加安全响应头;
如何禁止访问隐藏文件;
如何分析日志。
十二、最简版总结
这份内容可以浓缩成五句话:
Web 应用就是浏览器、服务器和数据库之间不断交换数据。
前端负责展示,后端负责处理,数据库负责保存。
用户输入不能直接相信,必须验证、过滤和编码。
操作数据库要用 PDO 预编译,保存密码要用哈希。
Web 安全的核心,是检查数据从输入到输出的每一步是否处理正确。
如果你刚开始学,不用先死磕所有命令和配置。先牢牢掌握这条主线:
用户输入从哪里来,经过哪些代码,最后去了数据库还是页面。