跳到主要内容
Java 安全开发实战:从代码防护到架构安全 | 极客日志
Java java
Java 安全开发实战:从代码防护到架构安全 Java 安全开发实战涵盖核心原则与威胁模型,重点解决 SQL 注入、XSS、CSRF 及文件上传漏洞。通过最小权限、纵深防御等原则构建防护体系。认证授权方面采用密码加密存储、JWT 安全配置及 RBAC 模型。微服务架构下需保障网关安全、服务间通信加密及配置中心安全。结合 SonarQube、OWASP ZAP 等工具进行静态扫描与动态渗透测试,实现生产环境服务器、中间件及数据库的安全加固与应急响应。
随缘 发布于 2026/2/10 更新于 2026/5/29 24 浏览Java 安全开发实战:从代码防护到架构安全
一、章节学习目标与重点
1.1 学习目标
理解 Java 应用面临的核心安全威胁(注入攻击、跨站脚本、权限漏洞等),掌握安全开发的核心原则与防护体系。
熟练运用代码级安全防护技巧,解决 SQL 注入、XSS、CSRF、文件上传漏洞等常见安全问题。
掌握认证授权机制的安全设计(密码加密、JWT 安全、OAuth2.0 实战),避免权限越界与身份伪造。
实现微服务架构下的安全防护(API 网关安全、服务间通信加密、配置中心安全),构建端到端安全体系。
能够独立完成 Java 应用的安全审计与漏洞排查,结合实际场景制定安全加固方案并落地。
1.2 学习重点
Java 应用常见安全漏洞(SQL 注入、XSS、CSRF 等)的原理与代码级防护。
认证授权安全:密码加密存储、JWT 令牌安全、RBAC 权限模型实战。
微服务安全:网关安全防护、服务间 HTTPS 通信、配置与敏感数据加密。
安全审计与漏洞排查工具(SonarQube、OWASP ZAP)的实战应用。
生产环境安全加固:服务器配置、依赖包漏洞修复、日志安全审计。
二、Java 安全开发基础:核心原则与威胁模型
2.1 安全开发核心原则
💡 安全开发的核心是'最小权限、纵深防御、数据脱敏、可审计',从设计、编码、测试到部署全流程规避风险:
最小权限原则 :应用、用户、进程仅拥有完成任务必需的最小权限,如数据库账号仅授予 SELECT/INSERT 权限,而非 ROOT 权限。
纵深防御原则 :构建多层防护体系,即使某一层防护失效,其他层仍能阻挡攻击,如'输入验证 + 参数绑定+ORM 框架'共同防御 SQL 注入。
数据最小化原则 :仅收集和存储业务必需的数据,敏感数据(如身份证号、手机号)需脱敏存储(如仅保留后 4 位)。
可审计原则 :记录关键操作日志(如登录、支付、权限变更),包含操作人、时间、IP、操作内容,便于安全事件追溯。
默认安全原则 :开发框架、服务器、数据库默认配置需开启安全选项,禁用不必要的功能(如 Tomcat 默认关闭管理后台)。
2.2 Java 应用核心安全威胁模型
Java 应用面临的安全威胁主要来自'输入验证失效、认证授权缺陷、敏感数据泄露、配置不当'四大类,常见威胁如下:
威胁类型 典型场景 危害程度 SQL 注入(SQL Injection) 用户输入拼接 SQL 语句(如WHERE) 数据库数据泄露、篡改、删除 跨站脚本(XSS) 恶意脚本注入网页(如评论区输入<script>) 窃取 Cookie、钓鱼攻击、会话劫持 跨站请求伪造(CSRF) 伪造用户身份发起请求(如伪造转账操作) 越权操作、财产损失 文件上传漏洞 上传恶意文件(如.jsp 脚本、病毒) 服务器被入侵、挖矿、数据泄露 权限越界(Broken Access Control) 低权限用户访问高权限资源(如普通用户查看他人订单) 敏感信息泄露、越权操作 敏感数据泄露 密码明文存储、接口明文传输敏感数据 用户隐私泄露、账号被盗 依赖包漏洞(Supply Chain Attack) 使用存在漏洞的第三方依赖(如 Log4j2 漏洞) 远程代码执行、服务器被控制
配置不当 数据库弱密码、Redis 未授权访问 服务器被入侵、数据泄露
2.3 安全开发生命周期(SDL) 安全不是'事后补丁',而是贯穿软件全生命周期的工程实践,Java 应用安全开发生命周期(SDL)分为 5 个阶段:
需求设计阶段 :识别安全需求(如支付功能需防篡改)、进行威胁建模(如 STRIDE 模型)。
编码阶段 :遵循安全编码规范、使用安全框架、避免高危 API。
测试阶段 :进行安全测试(静态扫描、动态渗透测试、漏洞扫描)。
部署阶段 :安全配置服务器、数据库、中间件,加固运行环境。
运维阶段 :持续监控安全事件、及时修复漏洞、定期安全审计。
三、代码级安全防护:抵御常见漏洞
3.1 SQL 注入防护 💡 SQL 注入的本质是'用户输入被当作 SQL 语句执行',防护核心是'避免直接拼接 SQL,使用参数化查询或 ORM 框架'。
3.1.1 核心防护技巧
最小权限数据库账号 :数据库账号仅授予必需权限,如查询用账号仅授予 SELECT 权限,禁止授予 DROP、ALTER 权限。
输入验证与过滤 :对用户输入的 SQL 关键字(如OR、UNION、DROP)进行过滤,作为辅助防护。
示例(SQL 关键字过滤):
public String filterSqlKeyword (String input) {
if (input == null ) return "" ;
String[] keywords = {"OR" , "UNION" , "SELECT" , "INSERT" , "DELETE" , "DROP" };
for (String keyword : keywords) {
input = input.replaceAll("(?i)" + keyword, "" );
}
return input;
}
使用 ORM 框架(MyBatis/Hibernate) :ORM 框架默认支持参数化查询,需避免使用动态 SQL 拼接。
MyBatis 安全用法:
<select id ="findUser" parameterType ="Long" resultType ="User" >
SELECT * FROM user WHERE id = #{id}
</select >
<select id ="findUser" parameterType ="String" resultType ="User" >
SELECT * FROM user WHERE id = ${id}
</select >
⚠️ 注意:MyBatis 中若需动态表名、排序字段,必须手动过滤白名单,如:
public String getSortSql (String sortField) {
List<String> allowedFields = Arrays.asList("id" , "create_time" );
if (!allowedFields.contains(sortField)) {
sortField = "id" ;
}
return "ORDER BY " + sortField;
}
使用参数化查询(PreparedStatement) :将用户输入作为参数传入 SQL,而非拼接字符串,避免 SQL 注入。
正例(JDBC 参数化查询):
String sql = "SELECT * FROM user WHERE id = ? AND username = ?" ;
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setLong(1 , userId);
pstmt.setString(2 , username);
ResultSet rs = pstmt.executeQuery();
String sql = "SELECT * FROM user WHERE id = '" + userId + "' AND username = '" + username + "'" ;
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql);
3.1.2 漏洞排查工具
静态扫描工具:SonarQube(检测代码中 SQL 拼接、危险 API 使用)。
动态测试工具:OWASP ZAP(自动扫描接口是否存在 SQL 注入)。
代码审计:重点检查 Statement、StringBuilder 拼接 SQL 的场景。
3.2 XSS(跨站脚本)防护 💡 XSS 的本质是'恶意脚本被浏览器执行',分为存储型 XSS(脚本存入数据库,如评论区)和反射型 XSS(脚本通过 URL 参数注入,如搜索框),防护核心是'输入过滤、输出编码、CSP 策略'。
3.2.1 核心防护技巧 使用 HttpOnly Cookie :设置 Cookie 的 HttpOnly 属性,防止 JavaScript 读取 Cookie,避免 XSS 窃取会话。
Spring Boot 配置:
server:
servlet:
session:
cookie:
http-only: true
secure: true
设置 CSP(内容安全策略) :通过 HTTP 响应头限制网页可加载的资源(如仅允许加载本域名脚本),阻止恶意脚本执行。
Spring Boot 配置 CSP:
@Component
public class CspFilter implements Filter {
@Override
public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("Content-Security-Policy" , "default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self'" );
chain.doFilter(request, response);
}
}
输出编码 :将后端返回的数据进行 HTML 编码,确保浏览器当作文本解析,而非脚本执行。
Spring Boot 自动编码:Spring MVC 默认对 model.addAttribute() 传递的变量进行 HTML 编码,无需手动处理。
手动编码示例(Velocity/Freemarker 模板):
<!-- Velocity 模板:使用#escape 进行 HTML 编码 -->
#escape($!stringUtils.escapeHtml($content)) $content #end
<!-- Freemarker 模板:使用?html 进行 HTML 编码 -->
${content?html}
输入过滤 :过滤用户输入中的 <script>、onclick、javascript: 等危险标签和属性。
示例(Java XSS 过滤工具类):
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;
public class XssFilterUtil {
public static String filterHtml (String html) {
if (html == null ) return "" ;
Whitelist whitelist = Whitelist.basic()
.addTags("p" , "img" , "h1" , "h2" )
.addAttributes("img" , "src" , "alt" )
.removeAttributes("*" , "onclick" , "onload" , "onerror" );
return Jsoup.clean(html, whitelist);
}
public static String filterText (String text) {
if (text == null ) return "" ;
text = text.replace("<" , "<" )
.replace(">" , ">" )
.replace("\"" , """ )
.replace("'" , "'" )
.replace("javascript:" , "" );
return text;
}
}
⚠️ 依赖:需引入 Jsoup 依赖(安全的 HTML 解析库):
<dependency >
<groupId > org.jsoup</groupId >
<artifactId > jsoup</artifactId >
<version > 1.17.2</version >
</dependency >
3.2.2 常见 XSS 场景防护 场景 防护方案 评论区、富文本编辑器 使用 Jsoup 过滤 HTML 标签,仅允许白名单标签 用户名、标题输入框 文本转义(<→<等),禁止 HTML 标签 URL 参数传递 对参数进行 URL 编码,后端验证参数格式 前端渲染数据 模板引擎自动编码,避免使用 v-html 等危险指令
3.3 CSRF(跨站请求伪造)防护 💡 CSRF 的本质是'攻击者利用用户已登录的会话,伪造用户身份发起请求',防护核心是'验证请求来源的合法性'。
3.3.1 核心防护技巧 使用 SameSite Cookie :设置 Cookie 的 SameSite 属性,限制 Cookie 仅在同站请求中携带,阻止跨站请求伪造。
配置示例:
server:
servlet:
session:
cookie:
same-site: Lax
验证 Referer/Origin 请求头 :检查请求的 Referer(来源页面)或 Origin(来源域名)是否为信任域名,拒绝非法来源请求。
自定义 CSRF 过滤器:
@Component
public class RefererCsrfFilter implements Filter {
private static final List<String> TRUSTED_ORIGINS = Arrays.asList("https://www.example.com" );
@Override
public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String origin = httpRequest.getHeader("Origin" );
if (origin != null && !TRUSTED_ORIGINS.contains(origin)) {
httpResponse.setStatus(HttpStatus.FORBIDDEN.value());
httpResponse.getWriter().write("CSRF attack detected" );
return ;
}
chain.doFilter(request, response);
}
}
使用 CSRF Token :服务器生成随机 Token(如 UUID),存储在 Session 或 Cookie 中,前端请求时携带 Token,服务器验证 Token 有效性。
Spring Security 自动实现 CSRF 防护(默认开启):
① 后端配置(Spring Boot):
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain (HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
return http.build();
}
}
import Cookies from 'js-cookie' ;
const csrfToken = Cookies .get ('XSRF-TOKEN' );
axios.post ('/api/order/submit' , orderData, {
headers : {'X-XSRF-TOKEN' : csrfToken}
});
3.3.2 无需防护的场景
纯查询接口(如获取商品列表),无状态变更,CSRF 无危害。
接口使用 JWT 令牌在请求头携带(非 Cookie 存储),CSRF 无法获取令牌。
接口仅允许 HTTPS 访问,且验证客户端证书。
3.4 文件上传漏洞防护 💡 文件上传漏洞的核心是'攻击者上传恶意文件(如.jsp、.php 脚本)并执行',防护核心是'严格校验文件类型、重命名文件、限制存储路径'。
3.4.1 核心防护技巧
校验文件后缀名(白名单,如仅允许.jpg、.png、.pdf)。
校验文件 MIME 类型(通过 Content-Type 头,如image/jpeg)。
校验文件魔数(文件头部字节,如 JPG 文件头部为FF D8 FF)。
示例(文件类型校验工具类):
public class FileUploadUtil {
private static final Set<String> ALLOWED_EXTENSIONS = new HashSet <>(Arrays.asList("jpg" , "png" , "pdf" , "doc" ));
private static final Map<String, byte []> ALLOWED_MAGIC_NUMBERS = new HashMap <>();
static {
ALLOWED_MAGIC_NUMBERS.put("jpg" , new byte []{(byte ) 0xFF , (byte ) 0xD8 , (byte ) 0xFF });
ALLOWED_MAGIC_NUMBERS.put("png" , new byte []{(byte ) 0x89 , (byte ) 0x50 , (byte ) 0x4E , (byte ) 0x47 });
ALLOWED_MAGIC_NUMBERS.put("pdf" , new byte []{(byte ) 0x25 , (byte ) 0x50 , (byte ) 0x44 , (byte ) 0x46 });
}
public static boolean validateFile (MultipartFile file) throws IOException {
if (file.isEmpty()) return false ;
String originalFilename = file.getOriginalFilename();
String extension = FilenameUtils.getExtension(originalFilename).toLowerCase();
if (!ALLOWED_EXTENSIONS.contains(extension)) {
return false ;
}
byte [] magicNumber = new byte [4 ];
file.getInputStream().read(magicNumber);
byte [] expectedMagic = ALLOWED_MAGIC_NUMBERS.get(extension);
if (expectedMagic == null ) return false ;
for (int i = 0 ; i < expectedMagic.length; i++) {
if (magicNumber[i] != expectedMagic[i]) {
return false ;
}
}
return true ;
}
}
限制存储路径与权限 :
将上传文件存储在非 Web 访问目录(如/data/upload),避免直接执行脚本文件。
若需 Web 访问,通过后端接口转发(如/api/file/{fileName}),而非直接暴露文件路径。
服务器文件目录设置只读权限,禁止执行权限(如 chmod 644)。
限制文件大小 :防止超大文件上传导致磁盘空间耗尽或 DOS 攻击。
Spring Boot 配置:
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 50MB
文件重命名 :上传文件后重命名为随机文件名(如 UUID),避免攻击者猜测文件路径和名称,同时防止文件名包含恶意字符。
示例:
public String uploadFile (MultipartFile file) throws IOException {
String extension = FilenameUtils.getExtension(file.getOriginalFilename()).toLowerCase();
String fileName = UUID.randomUUID().toString() + "." + extension;
String storagePath = "/data/upload/files/" ;
File destFile = new File (storagePath + fileName);
file.transferTo(destFile);
return "/api/file/" + fileName;
}
⚠️ 依赖:需引入 commons-io 获取文件后缀:
<dependency >
<groupId > commons-io</groupId >
<artifactId > commons-io</artifactId >
<version > 2.15.1</version >
</dependency >
3.4.2 额外防护措施
使用云存储(如阿里云 OSS、七牛云)存储上传文件,避免本地服务器风险。
对上传的压缩包(如.zip、.rar)进行解压校验,防止解压后包含恶意文件。
前端仅允许通过指定组件上传文件,禁止直接构造表单提交。
3.5 敏感数据泄露防护 💡 敏感数据包括用户密码、身份证号、手机号、银行卡号等,防护核心是'加密存储、加密传输、脱敏展示'。
3.5.1 密码加密存储(核心) 绝对禁止明文存储密码,必须使用不可逆加密算法(如 BCrypt、Argon2),避免 MD5、SHA-1 等弱哈希算法(易被彩虹表破解)。
Spring Security 集成 BCrypt 加密:
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Component
public class PasswordUtil {
private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder ();
public String encryptPassword (String rawPassword) {
return passwordEncoder.encode(rawPassword);
}
public boolean verifyPassword (String rawPassword, String encryptedPassword) {
return passwordEncoder.matches(rawPassword, encryptedPassword);
}
}
⚠️ 特点:BCrypt 自动生成随机盐值,每次加密结果不同,但验证时可通过盐值匹配,安全性高。
<dependency >
<groupId > org.springframework.security</groupId >
<artifactId > spring-security-core</artifactId >
</dependency >
3.5.2 敏感数据加密传输 所有敏感数据传输必须使用 HTTPS,避免 HTTP 明文传输被窃听。
Spring Boot 配置 HTTPS:
@Configuration
public class HttpsConfig {
@Bean
public ServletWebServerFactory servletContainer () {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory () {
@Override
protected void postProcessContext (Context context) {
SecurityConstraint securityConstraint = new SecurityConstraint ();
securityConstraint.setUserConstraint("CONFIDENTIAL" );
SecurityCollection collection = new SecurityCollection ();
collection.addPattern("/*" );
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
tomcat.addAdditionalTomcatConnectors(redirectConnector());
return tomcat;
}
private Connector redirectConnector () {
Connector connector = new Connector ("org.apache.coyote.http11.Http11NioProtocol" );
connector.setScheme("http" );
connector.setPort(80 );
connector.setSecure(false );
connector.setRedirectPort(443 );
return connector;
}
}
server:
port: 443
ssl:
key-store: classpath:example.jks
key-store-password: 123456
key-alias: example
key-store-type: JKS
keytool -genkeypair -alias example -keyalg RSA -keysize 2048 -keystore example.jks -validity 3650
3.5.3 敏感数据脱敏展示 接口返回和页面展示敏感数据时,需进行脱敏处理,仅展示部分信息:
public class SensitiveDataUtil {
public static String maskPhone (String phone) {
if (phone == null || phone.length() != 11 ) return phone;
return phone.replaceAll("(\\d{3})\\d{4}(\\d{4})" , "$1****$2" );
}
public static String maskIdCard (String idCard) {
if (idCard == null || idCard.length() != 18 ) return idCard;
return idCard.replaceAll("(\\d{6})\\d{8}(\\d{4})" , "$1********$2" );
}
public static String maskBankCard (String bankCard) {
if (bankCard == null || bankCard.length() < 10 ) return bankCard;
return bankCard.replaceAll("(\\d{6})\\d+(\\d{4})" , "$1****$2" );
}
}
四、认证授权安全:身份与权限防护
4.1 认证安全:确保'你是你声称的人' 认证的核心是'验证用户身份合法性',常见认证方式有'用户名密码认证、短信验证码认证、OAuth2.0 第三方认证',需避免'弱密码、会话劫持、认证绕过'等风险。
4.1.1 用户名密码认证安全
会话安全 :
会话超时时间不宜过长(如 30 分钟无操作自动登出)。
登录成功后生成新会话 ID,注销时销毁会话。
敏感操作(如支付、修改密码)需二次认证。
限制登录尝试次数 :防止暴力破解,如 5 分钟内连续输错 5 次密码,锁定账号 15 分钟。
示例(基于 Redis 的登录次数限制):
@Component
public class LoginLimitUtil {
@Autowired
private StringRedisTemplate redisTemplate;
private static final String LOGIN_LIMIT_KEY = "login:limit:%s" ;
private static final int MAX_ATTEMPTS = 5 ;
private static final int LOCK_MINUTES = 15 ;
public boolean checkLoginLimit (String username) {
String key = String.format(LOGIN_LIMIT_KEY, username);
String attempts = redisTemplate.opsForValue().get(key);
if (attempts == null ) {
redisTemplate.opsForValue().set(key, "1" , 5 , TimeUnit.MINUTES);
return true ;
}
int count = Integer.parseInt(attempts);
if (count >= MAX_ATTEMPTS) {
return false ;
}
redisTemplate.opsForValue().increment(key);
return true ;
}
public void clearLoginLimit (String username) {
String key = String.format(LOGIN_LIMIT_KEY, username);
redisTemplate.delete(key);
}
}
强制密码复杂度 :要求密码长度≥8 位,包含大小写字母、数字、特殊字符,禁止弱密码(如123456、password)。
示例(密码复杂度校验):
public boolean validatePasswordStrength (String password) {
String regex = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@#$%^&*()])[A-Za-z\\d@#$%^&*()]{8,20}$" ;
return password.matches(regex);
}
4.1.2 JWT 认证安全 JWT(JSON Web Token)是微服务架构中常用的无状态认证方式,需注意'令牌泄露、过期时间、签名安全'等问题:
合理设置过期时间 :访问令牌(Access Token)过期时间设为 1-2 小时,刷新令牌(Refresh Token)设为 7-30 天,避免长期有效令牌泄露风险。
令牌传输安全 :JWT 令牌通过 HTTP 请求头(如Authorization: Bearer {token})传输,禁止通过 URL 参数或 Cookie 传输(易泄露)。
避免存储敏感信息 :JWT 令牌 payload 部分仅加密不签名(可解码),禁止存储密码、银行卡号等敏感数据。
使用强签名算法 :采用 HS256(HMAC-SHA256)或 RS256(RSA-SHA256)算法,避免使用 HS512 以下的弱算法,禁止使用 None 算法(无签名)。
示例(JWT 工具类,使用 HS256):
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import javax.crypto.SecretKey;
import java.util.Date;
@Component
public class JwtUtil {
@Value("${jwt.secret:abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRST}")
private String secret;
@Value("${jwt.expire:3600000}")
private long expire;
private SecretKey getSecretKey () {
return Keys.hmacShaKeyFor(secret.getBytes());
}
public String generateToken (Long userId, String username) {
return Jwts.builder()
.setSubject(userId.toString())
.claim("username" , username)
.setIssuedAt(new Date ())
.setExpiration(new Date (System.currentTimeMillis() + expire))
.signWith(getSecretKey(), io.jsonwebtoken.SignatureAlgorithm.HS256)
.compact();
}
public boolean validateToken (String token) {
try {
Jwts.parserBuilder().setSigningKey(getSecretKey()).build().parseClaimsJws(token);
return true ;
} catch (Exception e) {
return false ;
}
}
}
4.1.3 OAuth2.0 第三方认证安全 OAuth2.0 用于第三方登录(如微信、QQ 登录),需注意'授权码泄露、回调地址篡改、Scope 权限控制':
使用授权码模式(Authorization Code) :避免使用简化模式(Implicit),授权码通过后端交换令牌,减少泄露风险。
校验回调地址 :第三方平台回调时,验证回调地址是否与注册地址一致,防止回调地址篡改。
限制 Scope 权限 :仅申请必需的权限(如微信登录仅申请snsapi_userinfo),避免过度授权。
验证令牌签名 :第三方返回的 ID Token 需验证签名,确保令牌未被篡改。
4.2 授权安全:确保'你有权做你想做的事' 授权的核心是'验证用户是否有权执行操作或访问资源',Java 应用中常用 RBAC(基于角色的访问控制)模型,需避免'权限越界、垂直越权、水平越权'。
4.2.1 RBAC 权限模型实战(Spring Security) RBAC 模型包含'用户 - 角色 - 权限'三层关系(用户关联角色,角色关联权限),Spring Security 可快速实现:
@RestController
@RequestMapping("/api/order")
public class OrderController {
@GetMapping("/view/{id}")
@PreAuthorize("hasAuthority('order:view')")
public Order viewOrder (@PathVariable Long id) {
}
@DeleteMapping("/delete/{id}")
@PreAuthorize("hasAuthority('order:delete')")
public void deleteOrder (@PathVariable Long id) {
}
@GetMapping("/my/{id}")
@PreAuthorize("hasAuthority('order:view') and @orderSecurityService.isOwner(authentication, #id)")
public Order viewMyOrder (@PathVariable Long id) {
}
}
@Service
public class OrderSecurityService {
@Autowired
private OrderRepository orderRepository;
public boolean isOwner (Authentication authentication, Long orderId) {
String username = authentication.getName();
Order order = orderRepository.findById(orderId).orElseThrow();
return order.getUsername().equals(username);
}
}
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public SecurityFilterChain filterChain (HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**" ).permitAll()
.requestMatchers("/api/admin/**" ).hasRole("ADMIN" )
.requestMatchers("/api/order/view" ).hasAuthority(Permission.ORDER_VIEW.getValue())
.requestMatchers("/api/order/create" ).hasAuthority(Permission.ORDER_CREATE.getValue())
.anyRequest().authenticated())
.formLogin(form -> form.permitAll())
.logout(logout -> logout.permitAll());
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder () {
return new BCryptPasswordEncoder ();
}
}
public enum Permission {
ORDER_VIEW("order:view" ),
ORDER_CREATE("order:create" ),
ORDER_DELETE("order:delete" );
private final String value;
Permission(String value) {
this .value = value;
}
public String getValue () {
return value;
}
}
public enum Role {
USER("ROLE_USER" , Arrays.asList(Permission.ORDER_VIEW, Permission.ORDER_CREATE)),
ADMIN("ROLE_ADMIN" , Arrays.asList(Permission.ORDER_VIEW, Permission.ORDER_CREATE, Permission.ORDER_DELETE));
private final String value;
private final List<Permission> permissions;
Role(String value, List<Permission> permissions) {
this .value = value;
this .permissions = permissions;
}
public String getValue () {
return value;
}
public List<Permission> getPermissions () {
return permissions;
}
}
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-security</artifactId >
</dependency >
4.2.2 常见授权漏洞防护
垂直越权(低角色访问高角色资源) :
接口级:通过 URL 路径控制(如/api/admin/**仅允许管理员访问)。
方法级:使用 @PreAuthorize("hasRole('ADMIN')") 注解。
水平越权(同角色访问他人资源) :
核心:每个操作都需验证'资源归属'(如订单的用户 ID 是否与当前登录用户 ID 一致)。
避免使用'前端传入用户 ID'查询资源,直接从当前登录上下文获取用户 ID。
权限继承漏洞 :避免角色权限过度宽松(如普通用户继承管理员权限),严格控制角色 - 权限映射关系。
五、微服务架构安全:端到端防护
5.1 网关安全:微服务入口防护 网关作为微服务的统一入口,需承担'身份认证、权限校验、限流熔断、安全过滤'等核心安全职责,避免恶意请求进入后端服务。
5.1.1 网关安全核心功能(Spring Cloud Gateway) 安全过滤 :网关层过滤 XSS、SQL 注入等恶意请求。
示例(网关 XSS 过滤过滤器):
@Component
public class GatewayXssFilter implements GlobalFilter , Ordered {
@Override
public Mono<Void> filter (ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpRequest filteredRequest = new XssFilteredRequest (request);
return chain.filter(exchange.mutate().request(filteredRequest).build());
}
@Override
public int getOrder () {
return -90 ;
}
private static class XssFilteredRequest extends ServerHttpRequestDecorator {
public XssFilteredRequest (ServerHttpRequest delegate) {
super (delegate);
}
@Override
public MultiValueMap<String, String> getQueryParams () {
MultiValueMap<String, String> params = super .getQueryParams();
return filterParams(params);
}
private MultiValueMap<String, String> filterParams (MultiValueMap<String, String> params) {
MultiValueMap<String, String> filtered = new LinkedMultiValueMap <>();
params.forEach((key, values) -> {
List<String> filteredValues = values.stream()
.map(XssFilterUtil::filterText)
.collect(Collectors.toList());
filtered.put(key, filteredValues);
});
return filtered;
}
}
}
限流与黑名单 :网关层限制单 IP、单用户的请求频率,拦截恶意 IP。
示例(基于 Sentinel 的网关限流):
spring:
cloud:
sentinel:
scg:
fallback:
response-body: '{"code":429,"msg":"请求过于频繁"}'
transport:
dashboard: localhost:8083
gateway:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/order/**
filters:
- name: SentinelScgFilter
args:
resourceName: order-service
ruleType: PATH
controlBehavior: DEFAULT
count: 100
权限校验 :网关层校验用户权限是否允许访问目标服务/接口。
示例(基于请求路径的权限校验):
private boolean hasPermission (Claims claims, String path) {
List<String> permissions = claims.get("permissions" , List.class);
Map<String, String> pathPermissionMap = new HashMap <>();
pathPermissionMap.put("/api/order/create" , "order:create" );
pathPermissionMap.put("/api/order/delete" , "order:delete" );
String requiredPermission = pathPermissionMap.get(path);
if (requiredPermission == null ) return true ;
return permissions.contains(requiredPermission);
}
统一认证 :网关层统一校验 JWT 令牌,无需每个服务单独认证。
示例(网关全局认证过滤器):
@Component
public class GatewayAuthFilter implements GlobalFilter , Ordered {
@Autowired
private JwtUtil jwtUtil;
@Override
public Mono<Void> filter (ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
String path = request.getPath().value();
if (path.startsWith("/api/public/" ) || path.startsWith("/actuator/health" )) {
return chain.filter(exchange);
}
String authHeader = request.getHeaders().getFirst("Authorization" );
if (authHeader == null || !authHeader.startsWith("Bearer " )) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
String token = authHeader.substring(7 );
if (!jwtUtil.validateToken(token)) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
Claims claims = jwtUtil.parseClaims(token);
String userId = claims.getSubject();
String username = claims.get("username" , String.class);
ServerHttpRequest newRequest = request.mutate()
.header("X-User-Id" , userId)
.header("X-User-Name" , username)
.build();
return chain.filter(exchange.mutate().request(newRequest).build());
}
@Override
public int getOrder () {
return -100 ;
}
}
5.2 服务间通信安全 微服务间通信需避免'数据泄露、身份伪造、中间人攻击',核心防护手段是'HTTPS 通信、服务身份认证、接口权限控制'。
5.2.1 服务间 HTTPS 通信
每个微服务配置 SSL 证书(可使用自签名证书或 CA 证书)。
服务调用使用 HTTPS 协议(如 Feign 调用时指定https://)。
Feign 配置 HTTPS:
feign:
client:
config:
default:
url: https://user-service
httpclient:
enabled: false
okhttp:
enabled: true
5.2.2 服务身份认证(Spring Cloud Alibaba) 使用 Sentinel 或 Nacos 实现服务身份认证,避免非法服务接入:
服务间调用令牌校验:
服务 A 调用服务 B 时,在请求头携带服务令牌,服务 B 校验令牌有效性:
@Component
public class FeignAuthInterceptor implements RequestInterceptor {
@Value("${service.token:service-auth-token-123456}")
private String serviceToken;
@Override
public void apply (RequestTemplate template) {
template.header("Service-Token" , serviceToken);
}
}
@Component
public class ServiceAuthFilter implements Filter {
@Value("${service.token:service-auth-token-123456}")
private String serviceToken;
@Override
public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String token = httpRequest.getHeader("Service-Token" );
if (!serviceToken.equals(token)) {
httpResponse.setStatus(HttpStatus.FORBIDDEN.value());
return ;
}
chain.doFilter(request, response);
}
}
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
username: nacos
password: nacos
config:
server-addr: localhost:8848
username: nacos
password: nacos
5.3 配置中心安全(Nacos) 配置中心存储大量敏感配置(如数据库密码、API 密钥),需防护'未授权访问、配置泄露、配置篡改'。
5.3.1 核心安全配置
配置访问权限控制 :Nacos 中为不同命名空间、配置分组设置不同角色,限制配置读写权限。
敏感配置加密 :使用 Nacos 配置加密功能,加密存储数据库密码等敏感信息。
① 配置加密密钥(Nacos 启动参数):
java -jar nacos-server.jar -Dnacos.encrypt.key=abcdefghijklmnopqrstuvwxyz123456
② 加密敏感配置(如数据库密码):
使用 Nacos 提供的加密工具加密密码,配置时前缀cipher::
spring:
datasource:
password: cipher:EncryptedPassword123
开启身份认证 :Nacos 启用用户名密码登录,避免匿名访问。
修改 Nacos 配置文件 conf/application.properties:
nacos.core.auth.enabled=true
nacos.core.auth.server.identity.key=serverIdentity
nacos.core.auth.server.identity.value=security
nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012
5.4 容器化环境微服务安全 Docker+K8s 环境下的微服务,需额外关注'容器安全、镜像安全、集群安全':
镜像安全 :
使用官方或可信镜像,避免使用未知来源镜像。
镜像扫描(如 Trivy)检测漏洞,修复高危漏洞后再部署。
非 root 用户运行容器,降低容器被入侵后的危害。
容器安全 :
限制容器资源(CPU、内存),避免资源耗尽攻击。
禁用容器特权模式(privileged: false),避免容器获取宿主机权限。
挂载必要的目录为只读(readOnly: true),防止容器内文件篡改。
K8s 集群安全 :
启用 RBAC 权限控制,限制 Pod 的 API 访问权限。
加密 K8s Secrets,避免敏感数据明文存储。
部署网络策略(NetworkPolicy),限制 Pod 间通信,仅允许必要的服务访问。
六、安全审计与漏洞排查
6.1 静态代码扫描(SonarQube) SonarQube 是开源的代码质量与安全扫描工具,可检测 Java 代码中的安全漏洞、代码异味、重复代码等问题。
6.1.1 部署与使用 Maven 项目集成 SonarQube:
① 在 pom.xml 中添加插件:
<plugin >
<groupId > org.sonarsource.scanner.maven</groupId >
<artifactId > sonar-maven-plugin</artifactId >
<version > 3.9.1.2184</version >
</plugin >
mvn sonar:sonar -Dsonar.host.url=http://localhost:9000 -Dsonar.login=admin -Dsonar.password=admin
docker run -d --name sonarqube -p 9000:9000 -e SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true sonarqube:9.9-community
6.1.2 关键安全规则 SonarQube 重点关注的 Java 安全规则:
避免 SQL 注入(S2077):禁止使用 Statement 拼接 SQL。
避免 XSS 漏洞(S5131):用户输入需进行 HTML 编码。
密码安全存储(S2068):禁止明文存储密码,使用 BCrypt 等算法。
敏感数据泄露(S3330):禁止日志打印密码、身份证号等敏感数据。
危险的反射使用(S4502):避免反射执行不可信代码。
6.2 动态渗透测试(OWASP ZAP) OWASP ZAP(Zed Attack Proxy)是开源的 Web 应用渗透测试工具,可自动扫描接口中的 SQL 注入、XSS、CSRF 等漏洞。
6.2.1 核心功能与使用
下载并启动 OWASP ZAP(官网链接)。
配置目标 URL(如http://localhost:8080/api)。
执行主动扫描(Active Scan),ZAP 会自动发送恶意请求,检测漏洞。
查看扫描报告,修复高危漏洞(如 SQL 注入、XSS)。
6.2.2 重点测试场景
所有用户输入接口(如登录、注册、评论):测试 SQL 注入、XSS。
权限相关接口(如查看订单、修改密码):测试越权访问。
文件上传接口:测试恶意文件上传。
会话管理:测试会话固定、会话劫持。
6.3 依赖包漏洞扫描(Dependency-Check) 依赖包漏洞是 Java 应用的重大安全隐患(如 Log4j2、Fastjson 漏洞),需定期扫描并修复。
6.3.1 Maven 项目集成 Dependency-Check
查看报告:在 target/dependency-check-report 目录下查看 HTML 报告,修复高危依赖(升级版本或替换安全依赖)。
mvn dependency-check:check
<plugin >
<groupId > org.owasp</groupId >
<artifactId > dependency-check-maven</artifactId >
<version > 8.4.0</version >
<executions >
<execution >
<goals >
<goal > check</goal >
</goals >
</execution >
</executions >
<configuration >
<format > HTML</format >
<outputDirectory > ${project.build.directory}/dependency-check-report</outputDirectory >
</configuration >
</plugin >
6.3.2 持续防护措施
集成 CI/CD 流程:每次构建时自动扫描依赖漏洞,高危漏洞阻断构建。
关注安全公告:及时了解 Log4j2、Spring 等核心框架的安全漏洞。
使用依赖管理工具:如 Maven Dependency Plugin 清理无用依赖,减少攻击面。
6.4 日志安全审计 安全日志是追溯安全事件的关键,需确保'日志完整、不可篡改、便于分析'。
6.4.1 关键操作日志记录 记录所有敏感操作日志,包含'操作人、时间、IP、操作内容、结果':
@Service
public class OrderService {
private static final Logger logger = LoggerFactory.getLogger(OrderService.class);
public Order createOrder (OrderDTO orderDTO, String username, String ip) {
logger.info("用户 [{}](IP:{})创建订单,订单信息:{}" , username, ip, orderDTO);
try {
Order order = saveOrder(orderDTO);
logger.info("用户 [{}] 创建订单成功,订单 ID:{}" , username, order.getId());
return order;
} catch (Exception e) {
logger.error("用户 [{}] 创建订单失败,原因:{}" , username, e.getMessage(), e);
throw e;
}
}
}
6.4.2 日志安全防护
日志脱敏:禁止日志打印密码、银行卡号等敏感数据。
日志存储:日志存储在安全服务器,设置只读权限,保留至少 90 天。
日志审计:定期审计关键操作日志,发现异常行为(如异地登录、批量删除数据)。
七、生产环境安全加固:最后一道防线
7.1 服务器安全加固
操作系统加固 :
关闭不必要的端口(如 22、3389 仅允许信任 IP 访问)。
禁用 root 用户直接登录,使用普通用户+sudo 授权。
开启防火墙(如 iptables、firewalld),限制端口访问。
定期更新系统补丁,修复内核漏洞。
Java 运行环境加固 :
使用 JDK 11+(安全性更高,修复大量漏洞)。
禁用 JVM 危险参数(如 -XX:+AllowUserSignalHandlers)。
限制 Java 进程权限,使用非 root 用户运行。
7.2 中间件安全加固
7.2.1 Tomcat 安全加固
禁用管理后台(tomcat-manager),或设置强密码。
隐藏 Tomcat 版本信息(修改 conf/server.xml,添加 server="Unknown")。
限制 HTTP 请求方法(仅允许 GET、POST、PUT、DELETE,禁用 OPTIONS)。
配置 HTTPS,禁用 SSLv3、TLSv1.0/1.1,仅支持 TLSv1.2/1.3。
7.2.2 数据库安全加固(MySQL)
设置强密码,定期更换,禁止空密码、弱密码。
限制数据库账号的访问 IP(如仅允许应用服务器 IP 连接)。
最小权限原则:应用账号仅授予 SELECT/INSERT/UPDATE/DELETE 权限,禁止 DROP、ALTER 权限。
开启二进制日志(binlog),便于数据恢复和审计。
禁用本地文件访问功能(secure_file_priv = ""),防止 SQL 注入读取本地文件。
7.3 应急响应流程 当发生安全事件(如服务器被入侵、数据泄露)时,需遵循'止损→排查→修复→追溯→优化'的应急响应流程:
紧急止损 :断开受影响服务器的网络连接,阻止攻击扩散;备份受影响数据。
漏洞排查 :使用安全工具(如 chkrootkit、rkhunter)检测恶意程序;分析日志定位攻击入口。
漏洞修复 :修复漏洞(如升级依赖包、修改配置、修补代码);清理恶意文件和账号。
安全加固 :加强防护措施(如开启防火墙、增加认证环节);恢复业务服务。
事件追溯 :分析攻击路径和原因,记录应急响应过程。
优化改进 :更新安全策略和流程,避免类似事件再次发生。
八、本章总结 ✅ 本章全面覆盖了 Java 应用安全开发的核心知识,从代码级漏洞防护到架构级安全设计,从认证授权到微服务安全,结合工具实战和配置示例,构建了全维度的 Java 安全防护体系。
Java 应用常见安全威胁(SQL 注入、XSS、CSRF 等)的原理与代码级防护技巧。
认证授权安全的核心实践:密码加密存储、JWT 安全配置、RBAC 权限模型实战。
微服务架构下的端到端安全防护:网关安全、服务间通信安全、配置中心安全。
安全审计与漏洞排查工具(SonarQube、OWASP ZAP、Dependency-Check)的实战应用。
生产环境安全加固措施:服务器、中间件、数据库的安全配置,应急响应流程。
安全开发是一个持续迭代的过程,没有绝对安全的系统,只有不断提升攻击成本。实际项目中,需结合业务场景和风险等级,制定合理的安全策略,平衡安全性与可用性。建议读者将安全开发融入日常开发流程,定期进行安全培训和漏洞扫描,构建'攻防兼备'的 Java 应用系统。
至此,《Java 开发从入门到精通》全书已完整呈现,从 Java 基础、Web 开发、框架应用、微服务架构、容器化部署到安全开发,形成了覆盖 Java 开发全生命周期的完整知识体系。希望读者能够将所学知识灵活应用于实际项目,开发出高性能、高可用、高安全的 Java 应用。
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online