Java SQL注入案例

wen java案例 2

本文目录导读:

Java SQL注入案例

  1. 有SQL注入漏洞的案例
  2. 存在漏洞的登录验证示例
  3. 使用PreparedStatement的正确防御
  4. MyBatis中的SQL注入预防
  5. 最佳实践总结

我来为你提供几个Java中SQL注入的典型案例,以及相应的防护措施。

有SQL注入漏洞的案例

案例1:字符串拼接(最危险)

// 有漏洞的代码
public User getUserByUsername(String username) {
    String sql = "SELECT * FROM users WHERE username = '" + username + "'";
    Statement stmt = connection.createStatement();
    ResultSet rs = stmt.executeQuery(sql);
    // 处理结果...
}
// 攻击示例
// 输入: admin' OR '1'='1
// 生成的SQL: SELECT * FROM users WHERE username = 'admin' OR '1'='1'
// 结果:返回所有用户信息

案例2:拼接ORDER BY或LIKE子句

// 有漏洞的ORDER BY
public List<User> getUsersSorted(String sortColumn) {
    String sql = "SELECT * FROM users ORDER BY " + sortColumn;
    Statement stmt = connection.createStatement();
    ResultSet rs = stmt.executeQuery(sql);
}
// 攻击示例
// 输入: id; DROP TABLE users; --
// 生成的SQL: SELECT * FROM users ORDER BY id; DROP TABLE users; --

案例3:拼接LIKE查询

// 有漏洞的LIKE查询
public List<User> searchUsers(String keyword) {
    String sql = "SELECT * FROM users WHERE username LIKE '%" + keyword + "%'";
    Statement stmt = connection.createStatement();
    ResultSet rs = stmt.executeQuery(sql);
}

存在漏洞的登录验证示例

public boolean login(String username, String password) {
    String sql = "SELECT * FROM users " +
                 "WHERE username = '" + username + "' " +
                 "AND password = '" + password + "'";
    Statement stmt = connection.createStatement();
    ResultSet rs = stmt.executeQuery(sql);
    return rs.next(); // 只要有结果就登录成功
}
// 攻击示例
// 用户名: admin' --
// 密码: 任意
// 生成的SQL: SELECT * FROM users WHERE username = 'admin' -- ' AND password = '任意密码'
// 结果:成功绕过密码验证

使用PreparedStatement的正确防御

示例1:基本的参数化查询

// 安全的查询方式
public User getUserByUsername(String username) {
    String sql = "SELECT * FROM users WHERE username = ?";
    PreparedStatement pstmt = connection.prepareStatement(sql);
    pstmt.setString(1, username);
    ResultSet rs = pstmt.executeQuery();
    if (rs.next()) {
        User user = new User();
        user.setId(rs.getInt("id"));
        user.setUsername(rs.getString("username"));
        user.setEmail(rs.getString("email"));
        return user;
    }
    return null;
}

示例2:安全的登录验证

public boolean login(String username, String password) {
    String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
    PreparedStatement pstmt = connection.prepareStatement(sql);
    pstmt.setString(1, username);
    pstmt.setString(2, password);
    ResultSet rs = pstmt.executeQuery();
    return rs.next();
}

示例3:安全的LIKE查询

public List<User> searchUsers(String keyword) {
    String sql = "SELECT * FROM users WHERE username LIKE ?";
    PreparedStatement pstmt = connection.prepareStatement(sql);
    pstmt.setString(1, "%" + keyword + "%");
    ResultSet rs = pstmt.executeQuery();
    List<User> users = new ArrayList<>();
    while (rs.next()) {
        User user = new User();
        user.setId(rs.getInt("id"));
        user.setUsername(rs.getString("username"));
        users.add(user);
    }
    return users;
}

示例4:处理排序字段的特殊情况

public List<User> getUsersSorted(String sortColumn) {
    // 白名单验证
    List<String> allowedColumns = Arrays.asList("id", "username", "email", "created_at");
    if (!allowedColumns.contains(sortColumn)) {
        throw new IllegalArgumentException("Invalid sort column: " + sortColumn);
    }
    // 即使使用字符串拼接,由于有白名单验证,也是安全的
    String sql = "SELECT * FROM users ORDER BY " + sortColumn;
    PreparedStatement pstmt = connection.prepareStatement(sql);
    ResultSet rs = pstmt.executeQuery();
    // 处理结果...
}

MyBatis中的SQL注入预防

错误的写法(有注入风险)

<!-- 有SQL注入风险的写法 -->
<select id="getUser" parameterType="String" resultType="User">
    SELECT * FROM users WHERE username LIKE '%${username}%'
</select>
<!-- 有SQL注入风险的ORDER BY -->
<select id="getUsersSorted" resultType="User">
    SELECT * FROM users ORDER BY ${sortColumn}
</select>

正确的写法

<!-- 安全的写法 -->
<select id="getUser" parameterType="String" resultType="User">
    SELECT * FROM users WHERE username LIKE CONCAT('%', #{username}, '%')
</select>
<!-- 或者 -->
<select id="getUser" parameterType="String" resultType="User">
    SELECT * FROM users WHERE username LIKE '%' || #{username} || '%'
</select>
<!-- 对于ORDER BY,使用白名单 -->
<select id="getUsersSorted" resultType="User">
    SELECT * FROM users 
    <choose>
        <when test="sortColumn == 'username'">ORDER BY username</when>
        <when test="sortColumn == 'email'">ORDER BY email</when>
        <otherwise>ORDER BY id</otherwise>
    </choose>
</select>

最佳实践总结

  1. 始终使用PreparedStatement,避免字符串拼接
  2. 使用参数占位符 而不是直接拼接变量
  3. 对于ORDER BY等特殊场景,使用白名单验证
  4. 在MyBatis中使用 而不是
  5. 实施输入验证,对特殊字符进行过滤或转义
  6. 使用ORM框架(如Hibernate、MyBatis)并正确使用参数化查询
  7. 最小权限原则,数据库连接使用权限最小的账号
  8. 定期进行安全审计,使用工具扫描SQL注入漏洞

通过遵循这些最佳实践,可以有效防止SQL注入攻击,保护应用程序和数据库的安全。

抱歉,评论功能暂时关闭!