简介:这份资源是华中科技大学网络空间安全学院信息系统安全实验的完整课程资料,面向高校网络安全、信息安全相关专业学生及自学者,适合在课程设计、课程实验场景中动手实践。压缩包共73个文件,约4.65MB,以C语言源码、Python脚本、头文件、Makefile、Shell脚本、HTML/JS页面及PNG截图为主,另附Markdown说明文档,覆盖从实验目标、步骤到报告模板的完整链路。内容按lab1、lab2、lab3三个进阶阶段组织,涉及密码学、访问控制、漏洞利用、XSS与CSRF、SQL注入、chroot隔离、HTTP服务与数据库操作等知识点,源码可自行修改,便于深入理解漏洞成因与修复思路。目前已有133人学习下载,适合希望系统掌握信息系统安全实践、积累安全审计与开发经验的学习者参考。
1. 华中科技大学网络空间安全学院信息系统安全实验:一份能跑通的源码加说明书到底长什么样
如果你正在搜“华中科技大学网络空间安全学院 信息系统安全实验 源码 说明书”,大概率是三种人之一:要交实验报告的本科生、想拿一套完整靶场练手的自学者、或者准备网络空间安全毕设需要参考工程结构的同学。这个标题指向的不是一篇论文,而是一个可解压、可编译、可改参数的实验压缩包,里面通常包含实验指导书、源码目录、数据库脚本和部署说明。它的价值在于把“信息系统安全”这门课里散落在 PPT 上的知识点——身份认证、访问控制、注入防御、日志审计——落成一套能本地跑起来的系统。我见过太多人拿到压缩包后卡在环境配置上,所以这篇笔记按“先看懂结构、再跑通最小闭环、最后改出自己需要的东西”的顺序讲,源码和说明书怎么配合用,坑在哪,一次说清。
2. 拆开压缩包先看什么:目录结构、说明书与源码的对应关系
2.1 典型实验包的目录布局与文件职责
拿到一个信息系统安全实验的压缩包,不要急着双击运行。先解压到一个纯英文路径下,中文路径在部分 JDK 或 Python 虚拟环境里会引发编码异常,这是血泪经验。解压后你通常会看到类似下面的结构,不同年份的实验包会有差异,但核心组成逃不出这几类:
| 目录/文件 | 典型内容 | 你该先看哪个 |
|---|---|---|
docs/或说明书.pdf | 实验目的、环境要求、步骤、截图 | 先看环境要求和步骤 |
src/或code/ | Java/Python/PHP 源码 | 对照说明书找入口类 |
sql/或db/ | 建库建表脚本、初始数据 | 第二步执行 |
web/或static/ | 前端页面、配置文件 | 最后确认端口和路径 |
README.md | 快速启动命令 | 和说明书交叉验证 |
lib/或requirements.txt | 依赖库 | 决定你装什么版本 |
说明书里最容易被忽略的是“实验环境”那一页,它写明了 JDK 版本、数据库版本、浏览器要求。很多人翻车就翻在这里:用 JDK 17 去跑一个为 JDK 8 写的 Servlet 项目,编译能过,运行时报NoSuchMethodError,查半天查不出来。我的习惯是先把说明书的环境要求抄到记事本上,装完环境再动手。
2.2 说明书和源码对不上的三种情况怎么处理
实验包年代久远,说明书和源码不一致是常态。常见三种情况:一是说明书写的类名在源码里改了;二是数据库表结构和 SQL 脚本对不上;三是端口号说明书写 8080,配置文件里是 9090。处理原则是“以源码为准,以说明书为参考”。具体做法是先在源码里全局搜索说明书提到的关键词,比如“LoginServlet”“filter”“audit”,找到实际文件后再反推配置。
如果 SQL 脚本和源码实体类字段对不上,不要急着改源码,先看实体类的注解或映射文件。以 Java 为例,字段映射通常在*.hbm.xml或 JPA 注解里:
// 实体类字段与数据库列的映射示例 @Entity @Table(name = "sys_user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "user_id") // 数据库列名 private Integer userId; // Java 字段名 @Column(name = "user_name", length = 64, nullable = false) private String userName; @Column(name = "password_hash", length = 128) private String passwordHash; // 注意是哈希不是明文 }这段代码说明:数据库列名和 Java 字段名可以不同,靠@Column对齐。如果你执行 SQL 脚本后报表不存在,先核对@Table里的表名和脚本里的CREATE TABLE是否一致。参数上,length决定建表时的字符长度,nullable决定是否允许空值,改这两个参数要同步改 SQL 脚本,否则运行时报字段长度溢出。
3. 把实验跑起来的最小闭环:环境、数据库、启动、验证
3.1 环境准备与依赖安装的确定性做法
信息系统安全实验常见技术栈是 Java Web(Servlet/JSP/SSM)或 Python Flask/Django。不管哪种,确定性做法是:先确认版本,再装依赖,最后配数据库。以 Java Web 为例,说明书要求 JDK 8 + Tomcat 8 + MySQL 5.7,你就不要用 JDK 11 去试。安装命令按操作系统来,Windows 下配JAVA_HOME和CATALINA_HOME,Linux 下用包管理器或手动解压。
# 确认 Java 版本,必须是说明书要求的版本 java -version # 预期输出包含 1.8.0_xxx,如果是 11 或 17 请切换 # 确认 MySQL 服务状态 mysql --version systemctl status mysql # Linux # Windows 下用 services.msc 查看 MySQL 服务 # 导入数据库脚本,注意字符集 mysql -u root -p --default-character-set=utf8 < sql/init.sql逻辑说明:java -version是第一步,版本不对后面全白费。--default-character-set=utf8是为了防止中文数据导入乱码,很多实验包的初始数据含中文用户名或日志,不加这个参数会看到问号。参数上,-u root -p是用户名和密码,如果你的 MySQL 是 8.0 版本,连接旧项目可能需要在连接串加useSSL=false&serverTimezone=UTC,否则报时区错误。
3.2 数据库脚本执行与连接配置核对
数据库导入成功后,不要急着启动应用。先核对连接配置。配置文件通常在src/main/resources/下的jdbc.properties或application.yml,也可能是WEB-INF/classes/下的db.properties。打开它,逐项核对:
# db.properties 典型内容 jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/security_lab?useUnicode=true&characterEncoding=utf8&useSSL=false jdbc.username=root jdbc.password=your_password这里每个参数都有讲究。security_lab是数据库名,必须和你CREATE DATABASE的名字一致。useUnicode=true&characterEncoding=utf8解决中文乱码。useSSL=false在本地实验环境可以关掉,否则 MySQL 8.0 会警告。jdbc.driver如果是 MySQL 8.0,驱动类名要改成com.mysql.cj.jdbc.Driver,否则报驱动找不到。改完配置后,把编译输出目录里的旧配置文件也同步更新,否则改了个寂寞。
3.3 启动应用并验证核心安全功能是否生效
启动方式取决于项目类型。Tomcat 项目把编译后的war包丢进webapps目录,或者用 IDE 配置 Tomcat 运行。Python 项目通常是python app.py或flask run。启动后看日志,出现Server startup in xxx ms或Running on http://127.0.0.1:5000才算成功。
验证不要只看首页能不能打开,要验证安全功能。信息系统安全实验的核心功能通常包括:登录认证、SQL 注入防御、XSS 过滤、越权访问控制、操作日志。逐个验证:
- 登录认证:用错误密码登录,看是否拒绝;用正确密码登录,看是否跳转。
- SQL 注入防御:在登录框输入
' or '1'='1,看是否被拦截或报错,而不是直接登录成功。 - 越权访问:登录普通用户后,直接访问管理员页面 URL,看是否被重定向。
- 日志审计:执行一次登录,去数据库
log表看是否新增记录。
-- 验证日志审计是否生效 SELECT * FROM sys_log ORDER BY create_time DESC LIMIT 5; -- 预期看到刚才登录操作的时间、用户名、IP、操作类型如果日志表为空,先检查代码里日志写入逻辑是否被注释掉,再检查数据库连接是否和业务库一致。有些实验包把日志写到独立库,配置容易漏。
4. 源码里最值得改的四个安全模块与参数调优
4.1 身份认证模块:从明文比对到加盐哈希
实验包里的认证模块往往是最简陋的,常见问题是密码明文存储或简单 MD5。你要改的第一处就是密码存储。找到注册和登录的代码,把明文比对改成加盐哈希。以 Java 为例:
import java.security.MessageDigest; import java.security.SecureRandom; import java.util.Base64; public class PasswordUtil { // 生成随机盐,长度 16 字节 public static String generateSalt() { SecureRandom random = new SecureRandom(); byte[] salt = new byte[16]; random.nextBytes(salt); return Base64.getEncoder().encodeToString(salt); } // 加盐哈希,迭代 10000 次 public static String hash(String password, String salt) throws Exception { MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(Base64.getDecoder().decode(salt)); byte[] hashed = md.digest(password.getBytes("UTF-8")); // 实际项目建议用 PBKDF2 或 BCrypt,这里演示原理 for (int i = 0; i < 10000; i++) { md.reset(); hashed = md.digest(hashed); } return Base64.getEncoder().encodeToString(hashed); } }逻辑说明:generateSalt为每个用户生成独立盐值,存在用户表里。hash把盐和密码一起哈希,迭代 10000 次增加暴力破解成本。参数上,盐长度 16 字节是常见选择,迭代次数 10000 是底线,生产环境建议用 BCrypt 并设 cost 为 10 以上。改完后,注册时存salt和password_hash,登录时用同样盐值哈希后比对。注意:已有用户数据需要迁移,不能直接改代码就完事。
4.2 访问控制模块:把 URL 级过滤改成角色加资源双校验
很多实验包的访问控制只做了 URL 拦截,比如/admin/*需要管理员角色。这不够,因为普通用户可能通过修改参数访问不属于自己的资源,比如/order?userId=2。你要改成“角色 + 资源归属”双校验。找到过滤器或拦截器代码:
// 在拦截器中增加资源归属校验 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String uri = request.getRequestURI(); Integer currentUserId = (Integer) request.getSession().getAttribute("userId"); String role = (String) request.getSession().getAttribute("role"); // 管理员放行 if ("admin".equals(role)) { return true; } // 普通用户访问订单详情,校验订单归属 if (uri.startsWith("/order/detail")) { String orderId = request.getParameter("orderId"); Integer ownerId = orderService.getOwnerId(orderId); if (!currentUserId.equals(ownerId)) { response.sendRedirect("/error/403"); return false; } } return true; }逻辑说明:先判断角色,管理员直接放行;普通用户访问订单详情时,查订单归属,不匹配就跳 403。参数上,orderId来自请求参数,ownerId来自数据库,两者必须比对。这里容易漏的是“直接对象引用”场景,比如用户 ID 放在 URL 路径里而不是参数里,校验逻辑要同步覆盖。
4.3 输入过滤模块:SQL 注入与 XSS 的防御边界
实验包里通常有 SQL 注入和 XSS 的演示模块,你要做的是把演示变成真实防御。SQL 注入防御的核心是参数化查询,不是字符串拼接。找到所有Statement用法,改成PreparedStatement:
// 错误写法:字符串拼接,存在注入 String sql = "SELECT * FROM sys_user WHERE user_name = '" + userName + "'"; Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery(sql); // 正确写法:参数化查询 String sql = "SELECT * FROM sys_user WHERE user_name = ?"; PreparedStatement pstmt = connection.prepareStatement(sql); pstmt.setString(1, userName); ResultSet rs = pstmt.executeQuery();逻辑说明:?是占位符,setString把用户输入作为参数传入,数据库驱动会做转义,注入字符串不会被当作 SQL 语法。参数上,setString的索引从 1 开始,对应第一个?。XSS 防御则要在输出时转义,而不是输入时过滤。用StringEscapeUtils.escapeHtml4或前端框架的自动转义。注意:输入过滤不能替代输出转义,两者要配合。
4.4 日志审计模块:记录什么、存哪里、怎么防篡改
日志审计是信息系统安全实验的得分点,也是实际项目里最容易被敷衍的模块。你要确保日志记录:时间、用户、IP、操作类型、操作对象、结果。存储上,建议独立日志表,字段至少包含log_id、user_id、ip、action、target、result、create_time。防篡改的做法是日志表只允许插入,不允许更新和删除,数据库账号权限上限制。
-- 日志表结构示例 CREATE TABLE sys_log ( log_id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id INT, ip VARCHAR(45), action VARCHAR(64), target VARCHAR(128), result VARCHAR(16), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- 限制应用账号只能插入和查询 GRANT INSERT, SELECT ON security_lab.sys_log TO 'app_user'@'localhost'; -- 不授予 UPDATE 和 DELETE逻辑说明:ip字段长度 45 是为了兼容 IPv6。result存success或fail。权限上,应用账号只有INSERT和SELECT,这样即使应用被攻破,攻击者也无法删除日志。参数上,ENGINE=InnoDB支持事务,DEFAULT CHARSET=utf8支持中文。如果实验包用的是 MyISAM,建议改成 InnoDB。
5. 避坑与排查:实验包跑不起来时先查这五处
5.1 现象:启动报 ClassNotFoundException 或 NoClassDefFoundError
原因:依赖库缺失或版本不对。实验包里的lib目录可能不全,或者你用的 JDK 版本和编译版本不一致。解决:先看报错类名,去lib目录搜对应的 jar 包,没有就按说明书版本下载。如果是 JDK 版本问题,用javap -verbose看 class 文件的编译版本,52 对应 JDK 8,55 对应 JDK 11。版本不匹配就换 JDK,不要硬改。
5.2 现象:数据库连接失败,报 Access denied 或 Unknown database
原因:用户名密码错、数据库没建、或者权限不够。解决:先用mysql -u root -p手动登录,执行SHOW DATABASES;看目标库是否存在。不存在就重新执行 SQL 脚本。存在但连不上,检查配置文件里的用户名密码,注意 MySQL 8.0 的caching_sha2_password插件可能导致旧驱动连不上,需要改用户认证插件或升级驱动。
5.3 现象:页面中文乱码,数据库里是问号
原因:字符集不统一。解决:三处要统一为 UTF-8——数据库建库建表用utf8或utf8mb4,连接串加characterEncoding=utf8,Tomcat 的server.xml里Connector加URIEncoding="UTF-8"。如果已经导入乱码数据,需要清库重导,改字符集不会自动修复已有数据。
5.4 现象:安全功能验证时,SQL 注入演示直接登录成功
原因:演示模块故意留了漏洞,或者你改代码后没重新编译。解决:先确认你改的是运行时的代码,不是源码目录里的备份文件。Java Web 项目改完要重新编译并替换WEB-INF/classes下的 class 文件,只改源码不编译等于没改。另外,有些实验包把漏洞演示和防御演示分成两个入口,确认你访问的是防御入口。
5.5 现象:日志表没有新增记录,但操作确实执行了
原因:日志写入逻辑被异步执行且失败被吞掉,或者日志库和业务库不是同一个。解决:先看应用日志有没有异常堆栈,再检查日志写入代码是否用了try-catch但没打印异常。如果是独立日志库,检查连接配置。最后确认数据库账号对日志表有INSERT权限。
6. 把实验包改造成自己的项目:三个可复用的改造技巧
6.1 用配置开关控制漏洞演示与防御演示的切换
实验包通常同时包含漏洞代码和修复代码,但入口可能写死。你可以加一个配置开关,在web.xml或application.yml里设security.mode=demo或security.mode=secure,代码里根据开关决定走哪条分支。这样一套代码既能交实验报告,又能当靶场用。改造时注意开关不要暴露给前端,只从服务端配置读取。
6.2 把单机数据库改成可移植的嵌入式数据库
如果你只是想在本地快速验证,不想装 MySQL,可以把数据库换成 H2 或 SQLite。以 H2 为例,加依赖后在配置文件里改连接串:
jdbc.driver=org.h2.Driver jdbc.url=jdbc:h2:file:./data/security_lab;MODE=MySQL;DB_CLOSE_DELAY=-1 jdbc.username=sa jdbc.password=逻辑说明:MODE=MySQL让 H2 兼容 MySQL 语法,DB_CLOSE_DELAY=-1防止连接关闭后数据库消失。参数上,file:./data/security_lab是数据库文件路径,首次启动自动建库。注意 H2 和 MySQL 在函数和语法上有差异,复杂 SQL 需要调整。
6.3 用 Docker Compose 固化环境,避免换电脑就翻车
实验包最大的痛点是环境依赖。用 Docker Compose 把 Tomcat、MySQL、应用打包,换电脑一条命令启动。下面是一个最小示例:
version: '3' services: db: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: root123 MYSQL_DATABASE: security_lab volumes: - ./sql:/docker-entrypoint-initdb.d ports: - "3306:3306" app: build: . ports: - "8080:8080" depends_on: - db environment: DB_HOST: db DB_PASSWORD: root123逻辑说明:volumes把 SQL 脚本挂载到初始化目录,容器首次启动自动执行。depends_on保证数据库先启动。参数上,MYSQL_ROOT_PASSWORD和DB_PASSWORD要一致,ports映射宿主机端口。注意 MySQL 5.7 镜像在 ARM 架构上可能需要指定平台,Apple Silicon 用户加platform: linux/amd64。
我自己的习惯是,拿到任何实验包先跑通最小闭环,再动源码。跑不通就按“环境版本、数据库连接、编译输出、配置文件、日志堆栈”五步排查,基本能解决九成问题。这套东西改完,交实验报告够用,拿去当毕设基础也够用,关键是你要真的动手跑一遍,而不是只看说明书。希望帮到你。
本文还有配套的精品资源,点击获取