java审计-JDBC注入审计
sql注入
基础
- 在常见的web漏洞中,SQL注入漏洞较为常见,危害也较大。攻击者一旦利用系统中存在的SQL注入漏洞来发起攻击,在条件允许的情况下,不仅可以获取整站数据,还可通过进一步的渗透来获取服务器权限,从而进入内网。
- 注入攻击的本质,是把用户输入的数据当做代码执行。这里有两个关键条件,第一个是用户能够控制输入;第二个是原本程序要执行的代码,拼接了用户输入的数据。接下来说下SQL注入漏洞的原理。
例子
-
当用户发送GET请求:
http://www.xxx.com/news.jsp?id=1
-
这是一个新闻详情页面,会显示出新闻的title和content,程序内部会接收这个id参数传递给SQL语句,SQL如下:
SELECT title,content FROM news WHERE id = 1
-
这是SQL的原义,也是程序员想要得到的结果,但是如果用户改变了id的内容,修改成如下:
http://www.jd.com/news.jsp?id=1 and 1=2 UNION SELECT username, password FROM admin
-
此时内部程序执行的SQL语句为:这条SQL的原义就会被改变,导致将管理员数据表中的用户名显示在页面title位置,密码显示在页面content位置,攻击成功。
SELECT title,content FROM news WHERE id = 1 and 1=2 UNION SELECT username, password FROM admin
解决
- 参数过滤
- 预处理
JDBC
基础
- JDBC的连接是比较繁琐的,并且是最原始的连接方式,我们来看看JDBC的最原始的连接代码
例子-直接拼接where
@GetMapping("/jdbc/vuln")//public String jdbc_sqli_vul(@RequestParam("username") String username) {public String jdbc_sqli_vul( String username) {StringBuilder result = new StringBuilder();try {Class.forName(driver);Connection con = DriverManager.getConnection(url, user, password);if (!con.isClosed())System.out.println("Connect to database successfully.");// sqli vuln codeStatement statement = con.createStatement();String sql = "select * from users where username = '" + username + "'";logger.info(sql);ResultSet rs = statement.executeQuery(sql);while (rs.next()) {String res_name = rs.getString("username");String res_pwd = rs.getString("password");String info = String.format("%s: %s\\n", res_name, res_pwd);result.append(info);logger.info(info);}rs.close();con.close();
解决
- 参数过滤
- 预处理
例子-like预处理写法
-
错误写法
// error codeString sql = "select * from users where username like %?%";PreparedStatement st = con.prepareStatement(sql);st.setString(1, username);
-
正确写法
// fix code String sql = "select * from users where username like ?"; PreparedStatement st = con.prepareStatement(sql); st.setString(1, "%"+username+"%");logger.info(st.toString()); // sql after prepare statement ResultSet rs = st.executeQuery();
例子-order by 预处理写法
-
错误写法
String sql = "select * from users where username order by ?"; PreparedStatement st = con.prepareStatement(sql); st.setString(1, username);
- 正确写法
- 写死order by
总结
- jdbc方式进行拼接的,可以直接使用预处理来规避sql注入,但是如果有like、order by 进行参数拼接不能直接使用预处理来解决,必须在set处把%拼接上。