0
点赞
收藏
分享

微信扫一扫

SQL注入问题

登高且赋 2022-01-20 阅读 96

1.简介

// 比如验证用户登录需要 username 和 password,编写的 SQL 语句如下:
select * from t_user where (username = '"+ username +"') and (password = '"+ password +"');
// username 和 password 字段被恶意填入
username = "1' OR '1'='1";
password = "1' OR '1'='1";
// 将导致原本的 SQL 字符串被填为:
select * from t_user where (username = '1' or '1'='1') and (password = '1' or '1'='1');
// 此时实际上运行的sql为
select * from t_user;
// 也就是不再需要 username 和 password 账密即达到登录的目的,结果不言而喻。
public static void main(String[] args) {
    // 此时真实数据库中只有一个用户,username与password均为admin
    login("admin","admin"); //登录成功
    login("admin","111"); // 登录失败
    login("1' or '1' = '1","1' or '1' = '1"); //登录成功
}

public static void login(String username,String password){
    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    String url = "jdbc:mysql://127.0.0.1:3306/ums?useUnicode=true&characterEncoding=utf-8";
    User user = null;
    try {
        Class.forName("com.mysql.jdbc.Driver");
        conn = DriverManager.getConnection(url,"root","");
        String sql = new StringBuffer()
                .append(" select id,username,password,phone,address ")
                .append(" from t_user ")
                .append(" where username = '"+ username +"' ")
                .append(" and password = '"+ password +"' ")
                .toString();
        ps = conn.prepareStatement(sql);
        rs = ps.executeQuery();
        while(rs.next()){
            System.out.println("登录成功");
            return;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("登录失败");
}

2.解决sql注入问题

public static void main(String[] args) {
    login("admin","admin"); //登录成功
    login("admin","111"); // 登录失败
    login("'1' or '1' = '1'","'1' or '1' = '1'"); // 登录失败
}

public static void login(String username,String password){
    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    String url = "jdbc:mysql://127.0.0.1:3306/ums?useUnicode=true&characterEncoding=utf-8";
    User user = null;
    try {
        Class.forName("com.mysql.jdbc.Driver");
        conn = DriverManager.getConnection(url,"root","");
        String sql = new StringBuffer()
                .append(" select id,username,password,phone,address ")
                .append(" from t_user ")
                .append(" where username = ? ")
                .append(" and password = ? ")
                .toString();
        ps = conn.prepareStatement(sql);
        ps.setString(1,username);
        ps.setString(2,password);
        rs = ps.executeQuery();
        while(rs.next()){
            System.out.println("登录成功");
            return;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("登录失败");
}

3.MyBatis中的Sql注入问题

<!-- sql注入问题 -->
<select id="selectByUsernameAndPassword4" resultType="user">
    select <include refid="userColumn"></include>
    from t_user
    where username = ${username}
    and password = ${password}
</select>
// 在遇到sql注入后,相当于查询了所有
public List<User> selectByUsernameAndPassword4(@Param("username") String username, @Param("password") String password);

// 测试
SqlSession session = null;
try {
    session = MyBatisUtil.getSession();
    UserDao userDao = session.getMapper(UserDao.class);
    List<User> users = userDao.selectByUsernameAndPassword4("'1' or '1'='1'","'1' or '1'='1'");
    // 此时查询了所有的t_user表中的数据
    // 可以将此时的sql语句看做:select * from user
    System.out.println(users);
    session.commit();
} catch (Exception e) {
    e.printStackTrace();
    session.rollback();
} finally {
    MyBatisUtil.close();
}

运行后控制台效果如下

 

根据最终展现效果我们可以发现

4.MyBatis解决sql注入问题

<!-- 避免sql注入 -->
<select id="selectByUsernameAndPassword5" resultType="user">
    select <include refid="userColumn"></include>
    from t_user
    where username = #{username}
    and password = #{password}
</select>
SqlSession session = null;
try {
    session = MyBatisUtil.getSession();
    UserDao userDao = session.getMapper(UserDao.class);
    List<User> users = userDao.selectByUsernameAndPassword5("'1' or '1'='1'","'1' or '1'='1'");
    // 此时将传递的参数整体作为一个字符串
    // 即username的值为:'1' or '1'='1'
    // password的值为:'1' or '1'='1'
    // 因此没有查询到对应的数据
    session.commit();
} catch (Exception e) {
    e.printStackTrace();
    session.rollback();
} finally {
    MyBatisUtil.close();
}

运行后控制台效果如下

根据最终展现效果我们可以发现

 

举报

相关推荐

0 条评论