Java应用程序安全:十大常见漏洞实战解析
Java应用程序安全不仅仅是清单上的一个勾选项,而是开发中至关重要的方面。根据OWASP数据,超过70%的现代Web应用程序至少包含一个严重漏洞。本文将结合实际代码示例,解析10种最常见威胁及其解决方案。无论您是初学者还是经验丰富的Java开发者,本文都将为您提供实用指导。
1. SQL注入(Injection)
SQL注入仍然是漏洞中的头号威胁。攻击者可以通过用户输入注入恶意SQL代码。
存在漏洞的代码:
String query = "SELECT * FROM users WHERE username = '" + username + "'";Statement stmt = connection.createStatement();ResultSet rs = stmt.executeQuery(query);修复后的代码(使用PreparedStatement):
String query = "SELECT * FROM users WHERE username = ?";PreparedStatement pstmt = connection.prepareStatement(query);pstmt.setString(1, username);ResultSet rs = pstmt.executeQuery();2. XSS(跨站脚本攻击)
XSS攻击允许在网页中注入客户端脚本。主要防护手段是输出转义。
存在漏洞的代码(JSP):
<%= request.getParameter("comment") %>修复后的代码:
<%= Encode.forHtml(request.getParameter("comment")) %>使用OWASP Java Encoder库进行可靠的转义:
import org.owasp.encoder.Encode;String safeOutput = Encode.forHtml(userInput);3. 不安全的反序列化
Java反序列化可能导致远程代码执行(RCE)。
存在漏洞的代码:
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());Object obj = ois.readObject(); // 危险!安全建议:
- 不要反序列化来自不可信来源的数据
- 反序列化时使用白名单类
- 使用JSON或XML替代Java序列化
// 带类检查的安全方法ObjectInputStream ois = new ObjectInputStream(inputStream) { @Override protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { if (!allowedClasses.contains(desc.getName())) { throw new InvalidClassException(desc.getName(), "未经授权的反序列化"); } return super.resolveClass(desc); }};4. CSRF(跨站请求伪造)
CSRF攻击迫使已认证用户在网站上执行非预期的操作。
使用令牌进行防护(Spring Security):
@Configuration@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); }}在表单中添加令牌:
<form action="/transfer" method="POST"> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> <input type="text" name="amount"/> <button type="submit">转账</button></form>5. 通过异常泄露信息
详细的错误消息可能暴露应用程序的内部结构。
存在漏洞的代码:
try { // 业务逻辑} catch (SQLException e) { response.getWriter().println("错误:" + e.getMessage()); // 信息泄露!}<