CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
计算机科学入门/课时/安全基础
RawBlame
课时目录12 节

计算机科学入门

  1. 01计算机如何工作
  2. 02数据结构
  3. 03算法与搜索排序
  4. 04复杂度分析
  5. 05离散数学基础
  6. 06操作系统概念
  7. 07数据库原理
  8. 08计算机网络
  9. 09系统设计入门
  10. 10安全基础
  11. 11设计模式与 UML
  12. 12综合练习

安全基础

加密、哈希、OWASP Top 10。

30 分钟

安全基础

这一课你将能做到

  1. 用 CIA 三原则(机密性、完整性、可用性)分析一个系统面临的风险
  2. 区分对称加密、非对称加密、哈希/消息摘要的用途,并正确存储用户密码
  3. 识别 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);
    }
}

选择规则要刻进脑子:

  • 数据要能还原 → 加密;双方同一把钥匙(AES)或公私钥对(RSA/ECIES)
  • 只需验证内容没改、来源可信 → 普通哈希(SHA-256)或带密钥的 HMAC
  • 需要防抵赖 → 数字签名(私钥签、公钥验,JWT 的签名、软件发布签名)
  • 哈希 ≠ 加密:哈希不可逆;不要发明自己的加密算法,也不要用 MD5/SHA-1(已不安全)

步骤 3:防住 SQL 注入

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class ProblemRepository {

    private final JdbcTemplate jdbc;

    public ProblemRepository(JdbcTemplate jdbc) {
        this.jdbc = jdbc;
    }

    public Integer findByTitle(String title) {
        // ❌ 拼接:title = "x' OR '1'='1" 即可绕过条件,甚至拖走全表
        // String sql = "SELECT id FROM problems WHERE title='" + title + "'";

        // ✅ 参数化:SQL 结构与参数分离,参数只被当作值,永远不会被解释成 SQL
        String sql = "SELECT id FROM problems WHERE title = ?";
        return jdbc.queryForObject(sql, Integer.class, title);
    }
}

MyBatis 中用 #{}(预编译参数)而不是 ${}(字符串拼接,仅在必须动态指定表名/列名时使用且要白名单校验)。注入是 OWASP Top 10 的常客,根因永远是「把用户输入当成了代码执行」。

步骤 4:XSS、CSRF 与越权

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/submissions")
public class SubmissionController {

    // 越权防御:水平越权=用户 A 查看用户 B 的记录;垂直越权=普通用户调用管理接口
    // 不能只靠「前端不显示按钮」,每个接口都要在服务端校验资源归属
    @GetMapping("/{id}")
    @PreAuthorize("@submissionGuard.isOwner(#id) or hasRole('ADMIN')")
    public String getOne(@PathVariable Long id) {
        return "submission-" + id;
    }

    @DeleteMapping("/{id}")
    @PreAuthorize("hasRole('ADMIN')")
    public void delete(@PathVariable Long id) {
        // 管理操作必须有角色校验,并写审计日志(谁、何时、删了什么)
    }
}

两类前端侧漏洞直觉:

  • XSS(跨站脚本):用户输入被当作脚本在别人的页面执行。防御:输出到 HTML 时做转义(模板默认转义)、富文本用白名单过滤库(如 OWASP Java HTML Sanitizer)、Cookie 加 HttpOnly 防窃取
  • CSRF(跨站请求伪造):诱导已登录用户在第三方站点发起请求。防御:敏感操作使用 CSRF Token/ SameSite Cookie;纯 JSON API + JWT 在 Header 中传递时天然不易受攻击,但仍要校验来源

讲清楚要点

  1. 认证 Authentication 与授权 Authorization 是两件事:先确认「你是谁」(登录、JWT/Session),再判断「你能做什么」(角色、权限、资源归属);顺序不能反,且授权必须在服务端每个敏感接口执行。
  2. 最小权限原则:用户、服务账号、数据库账号都只授予完成任务的最小权限;判题机执行用户代码用低权限账户 + 容器隔离,限制文件、网络、系统调用。
  3. 敏感数据要分级:密码、身份证、手机号、代码源码各有保护级别;日志里不要打印密码与完整身份证号,接口返回要脱敏,备份与传输同样要加密。
  4. 可用性攻击(DDoS/CC):流量型靠带宽与清洗服务,请求型靠限流、验证码、WAF;判题平台还要防「恶意提交死循环代码」耗尽判题产能(结合 MQ 排队与每用户提交频率限制)。
  5. 安全的纵深防御:网络层(防火墙/WAF)、主机层(补丁、最小化服务)、应用层(输入校验、参数化、CSRF/XSS 防护)、数据层(加密、备份、权限);任何单点被突破,其他层仍能兜底。

你可能会懵的地方

  • 加盐有什么用?盐不是保密的吗? 盐不需要保密,它通常和哈希一起存储。盐的作用是让每个用户的哈希都不同:攻击者无法用一张预计算的彩虹表批量破解,必须逐个加盐猜测,成本大增。

  • JWT 安全吗?存在哪、被盗了怎么办? JWT 是带签名的令牌,防篡改但默认不加密(payload 仅 Base64,别放敏感信息)。被盗用的风险与 Cookie 相同:用 HTTPS、短有效期 + Refresh Token、必要时绑定设备/IP 特征,服务端维护吊销名单。

  • 前端做了校验,后端还要做吗? 必须做。前端校验只为体验,攻击者可以绕过浏览器直接构造请求。所有安全校验的「生效位置」只能是服务端。

  • HTTPS 已经加密,是不是就不会被攻击了? HTTPS 解决传输链路的窃听与篡改,但它不防应用层漏洞:注入、越权、弱密码、XSS 照样成立。加密是安全的一环不是全部。

  • 发现漏洞后该怎么做? 先止损(下线或限流受影响接口、封禁攻击源),再修复并验证,然后排查数据是否已被利用(查审计日志),最后复盘补充监控与测试;切忌悄悄修复不告知、不留记录。

错法对照

错法问题正解
明文或 MD5 存密码拖库即全部泄漏bcrypt/Argon2 加盐慢哈希
用 ${} 拼 MyBatis 参数SQL 注入#{} 参数化;动态结构用白名单
接口只按 ID 查询不校验归属水平越权服务端校验当前用户与资源关系
日志打印完整手机号/密码日志泄漏即数据泄漏脱敏打印;密码绝不入日志
自行设计加密/签名方案几乎必然有缺陷用经过审计的标准库与协议

卡点急救

  1. 怀疑被刷接口/撞库:立即对登录和提交接口加限流与验证码,封禁异常 IP/账号;核查失败日志的规模与来源分布。
  2. 发现注入点:先关闭或限流相关接口,确认数据访问账号权限(是否过大),修复为参数化后再上线,并审计历史异常请求。
  3. 权限疑似被绕过:复核 Security 配置是否对新接口生效(避免只保护了旧路径),用未登录/低权限账号实际回归一遍全部敏感接口。

面试常问

  • 说一下对称加密、非对称加密和哈希的区别与使用场景。 对称(AES)一把钥匙、速度快,用于数据加密;非对称(RSA/ECDSA)公私钥对,用于密钥协商与数字签名;哈希(SHA 系列)单向定长,用于完整性与密码存储(密码必须加盐慢哈希)。TLS 是三者组合的标准案例。

  • 如何防止 SQL 注入? 参数化查询(预编译)使代码与数据分离;最小权限账号;避免拼接表名/列名,必要时白名单校验;ORM 用安全占位符。可补充 WAF 只能作为补充,不能替代参数化。

  • 什么是越权?水平和垂直越权怎么防? 越权是绕过授权访问未授权资源。水平越权访问同权限他人数据(用 ID 直接查),靠资源归属校验;垂直越权访问高权限功能,靠服务端角色/权限注解,前端隐藏按钮不算防御。

自测三问

  1. 用 CIA 给判题平台各列两个威胁与对应措施,能补上不可否认性更好。
  2. 用户登录全链路中,密码在前端、传输、存储、校验四个环节分别怎么处理?
  3. XSS 和 CSRF 的攻击方向有何不同?Cookie 的 HttpOnly 与 SameSite 分别防谁?

小结一句话

安全以 CIA 为目标、以「输入皆恶意、权限服务端兜底、密码加盐慢哈希、系统永不自创密码学」为基本纪律,靠纵深防御把单点失陷的风险层层稀释。

延伸

  • OWASP Top 10 官方项目(2021 版)——Web 应用最关键风险清单与防护指南
  • Spring Security 官方参考文档——认证授权架构与配置的权威资料
  • NIST 数字身份指南(SP 800-63B)——密码与身份验证的国际权威建议
  • 下一课:设计模式与 UML——掌握了安全与设计的原则,下一课学习如何把良好结构固化为可复用的模式:GoF 经典模式与 UML 表达。
加载本节练习…
← 上一课系统设计入门下一课 →设计模式与 UML