安全基础
加密、哈希、OWASP Top 10。
安全基础
这一课你将能做到
- 用 CIA 三原则(机密性、完整性、可用性)分析一个系统面临的风险
- 区分对称加密、非对称加密、哈希/消息摘要的用途,并正确存储用户密码
- 识别 SQL 注入、XSS、CSRF、越权访问四类常见 Web 漏洞及其防御手段
为什么要学
判题平台有用户身份、有用户上传的代码、有管理员后台、有开放接口——它几乎集齐了 Web 安全的全部攻击面。一次安全事故的代价远超普通 Bug:密码库被拖库、用户代码被窃取、后台被入侵植入恶意内容、接口被恶意刷爆导致服务不可用。
安全不是「上线前加个过滤器」,而是贯穿设计的思维方式:先假设输入是恶意的、网络是不可信的、权限会被试探。 本课建立安全的总框架(CIA)、密码学工具箱和与 Java Web 最相关的漏洞防御。它们也是第 8 课 TLS、第 11 课安全过滤器设计的落地基础。
先建立图像
CIA 三原则(信息安全的总目标)
机密性 Confidentiality 不该看的看不到 → 加密、权限控制
完整性 Integrity 数据没被篡改 → 哈希、签名、校验
可用性 Availability 该用的时候能用 → 防 DDoS、限流、容灾备份
(扩展:不可否认性 —— 做过的操作抵赖不掉 → 数字签名、审计日志)
密码学三件套
对称加密 同一把钥匙,快 AES 加密大量数据
非对称加密 公钥/私钥对 RSA/ECDSA 密钥协商、数字签名
哈希摘要 单向不可逆 SHA-256, 完整性校验、密码存储
bcrypt/Argon2(慢哈希+盐)
一次请求的攻防地图
用户输入 ──▶ 认证(你是谁) ──▶ 授权(你能干什么) ──▶ 参数处理(注入/XSS)
◀── 响应(防敏感信息泄漏/Cookie 安全属性) ──
跟着做
步骤 1:安全地存储密码(最重要的单一实践)
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class PasswordDemo {
public static void main(String[] args) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(12);
// 注册:绝不存明文,也不用 MD5/SHA-256 直接存(太快,易被彩虹表/撞库破解)
String raw = "MyPass_2026";
String encoded = encoder.encode(raw);
System.out.println("入库的密码哈希: " + encoded);
// 同一密码每次结果不同,因为哈希内含随机盐(salt),盐让相同密码哈希不同
// 登录:用 matches 校验,不自己解哈希(不可逆,也解不出来)
System.out.println(encoder.matches(raw, encoded)); // true
System.out.println(encoder.matches("wrong", encoded)); // false
}
}
关键认知:密码哈希必须加盐(防彩虹表)且故意设计得慢(bcrypt/Argon2/PBKDF2,让离线猜测成本极高)。数据库即使被拖库,攻击者也难以还原密码;同时要强制弱密码检测、登录失败限流,防范撞库。
步骤 2:用对三种密码学工具
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.HexFormat;
public class CryptoToolbox {
// HMAC:带密钥的哈希,保证「消息来自持有密钥的一方且未被篡改」
// 典型用途:Webhook 回调签名、判题结果回调验签
static String hmacSha256(String data, String secret) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] raw = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
return HexFormat.of().formatHex(raw);
}
public static void main(String[] args) throws Exception {
String body = "{\"submissionId\":1024,\"status\":\"AC\"}";
String sign = hmacSha256(body, "judge-callback-secret");
System.out.println("签名: " + sign);
}
}