关注墨瑾轩,带你探索编程的奥秘!
超萌技术攻略,轻松晋级编程高手
技术宝库已备好,就等你来挖掘
订阅墨瑾轩,智趣学习不孤单
即刻启航,编程之旅更有趣
想象一下:你的Java应用是一座巍峨的城堡,而安全漏洞就是那些悄悄蔓延的裂缝。
如果你现在还用“String + SQL
”拼接查询,或者对用户输入的“”一视同仁,那恭喜你——你的城堡已经成了黑客的游乐场!
本文将带你从0到1,用代码和工具亲手“修补裂缝”,让你的Java城堡坚不可摧!
工具推荐:
<build>
<plugins>
<plugin>
<groupId>org.owaspgroupId>
<artifactId>dependency-check-mavenartifactId>
<version>6.4.2version>
<executions>
<execution>
<goals>
<goal>checkgoal>
goals>
execution>
executions>
plugin>
plugins>
build>
注释:
mvn dependency-check:check
会生成报告,告诉你哪些依赖库有漏洞。log4j-core:2.14.0
有漏洞,直接升级到 2.17.0
!工具推荐:
# 启动ZAP进行动态扫描
zap.sh -daemon -port 8090 -host localhost -config api.key=your_api_key -config scanner.attackOnStart=true -config target=http://yourapp.com
注释:
漏洞代码(危险!):
public User getUserById(String userId) {
String query = "SELECT * FROM users WHERE id = '" + userId + "'";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(query);
// ...
}
修复代码(安全!):
public User getUserByIdSafe(String userId) {
String query = "SELECT * FROM users WHERE id = ?";
try (PreparedStatement pstmt = connection.prepareStatement(query)) {
pstmt.setString(1, userId); // 参数化查询
ResultSet rs = pstmt.executeQuery();
// ...
} catch (SQLException e) {
e.printStackTrace();
}
}
注释:
PreparedStatement
可以防止用户输入中的恶意SQL代码。"1'; DROP TABLE users;--"
,参数化查询会把它当作普通字符串处理,而不是执行命令!漏洞代码(危险!):
public String getGreeting(String userName) {
return "Welcome, " + userName + "!"; // 直接拼接用户输入
}
修复代码(安全!):
import org.owasp.encoder.Encode;
public String getGreeting(String userName) {
return "Welcome, " + Encode.forHtml(userName) + "!"; // HTML编码
}
注释:
Encode.forHtml()
会把 <
转为 <
,把 >
转为 >
,让攻击者的脚本失效。""
,前端会显示成 <script>...
,彻底“哑火”!漏洞代码(危险!):
@GetMapping("/request")
public String requestUrl(@RequestParam("url") String urlString) throws IOException {
URL url = new URL(urlString); // 直接使用用户输入
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// ...
}
修复代码(安全!):
@GetMapping("/request")
public String requestUrl(@RequestParam("url") String urlString) throws IOException {
if (!urlString.startsWith("https://")) {
throw new IllegalArgumentException("仅允许HTTPS请求");
}
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// ...
}
注释:
file:///etc/passwd
或 http://169.254.169.254/latest/meta-data/
,直接拦截!public boolean isValidEmail(String email) {
// 使用正则表达式校验邮箱格式
String regex = "^[A-Za-z0-9+_.-]+@(.+)$";
return email.matches(regex);
}
注释:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN") // 只有管理员才能访问
.anyRequest().authenticated()
.and()
.formLogin(); // 使用表单登录
}
}
注释:
Spring Security
可以轻松实现权限控制。/admin/deleteAllUsers
直接“403 Forbidden”!public void logSecurityEvent(String event) {
// 记录敏感操作日志
logger.info("Security Event: {}", event);
}
注释:
PreparedStatement
会将用户输入视为“数据”,而不是“指令”。Struts2 2.5.26
或更高版本。struts.xml
配置文件,禁用危险功能。
<constant name="struts.multipart.saveDir" value="/tmp/uploads" />
<constant name="struts.action.extension" value="action" />
注释:
OGNL
表达式“劫持”了!通过本文的三个步骤,你已经掌握了:
最后的小彩蛋:
如果你遇到更复杂的漏洞(比如反序列化漏洞),可以尝试用ObjectInputStream
的自定义resolveClass
方法,或者直接用Jackson
替代Java原生序列化
!
Q:为什么我的依赖库有漏洞,但升级不了?
A:
Log4j
换成 Logback
)。Q:如何测试修复效果?
A:
Postman
或 curl
模拟攻击请求。ZAP
或 Burp
再次扫描,确认漏洞消失。