SQL注入问题的解决(PreparedStatement)

Posted 一切随缘~~~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL注入问题的解决(PreparedStatement)相关的知识,希望对你有一定的参考价值。

sql注入的问题

上篇博客用户登录业务简易实现结尾提到了代码的不足:存在SQL注入问题。

下面演示一下什么是SQL,注入问题。(就拿上篇的代码举个例子)


以上为正常现象,但有些“不法分子”抓住了代码的漏洞,干了一些不为人知的事情。

What!竟然登录成功了!发生了甚么?让我们Debug一下,一探究竟。

select * from t_user where username = ‘jiuzhe’ and userpwd = ‘jiuzhe’ or ‘1’=‘1’

‘1’='1’为true,从而导致了整个柿子返回结果为true。

如何解决sql注入的问题(PreparedStatement)

导致SQL注入的根本原因是什么?

​ 用户输入的信息中含有SQL语句的关键字,最为致命的是这些关键字参与了SQL语句的编译过程

​ 导致SQL语句的原意被扭曲,进而达到SQL注入。

如何解决SQL注入的问题?

​ 只要用户输入的信息不参与SQL语句的编译过程,问题就解决了。

​ 即使用户输入的信息含有SQL语句的关键字,但由于不参与SQL语句的编译过程,那么也起不到作用。

​ 为此,我们要使用Java.sql.PreparedStatement。

​ PreparedStatement的原理是:预先对SQL语句的框架进行编译,然后再给SQL语句传“值”。

修改后的代码:

public class userLogin2 
    public static void main(String[] args) 
        // 初始化界面,返回用户的信息。
        Map<String, String> userLoginInfo = initUI();
        // 验证用户名和密码
        boolean loginSuccess = login(userLoginInfo);
        System.out.println(loginSuccess ? "Success" : "False");
    

    private static boolean login(Map<String, String> userLoginInfo) 
        // 打一个标记
        boolean loginSuccess = false;

        String loginName = userLoginInfo.get("userLoginName");
        String loginPwd = userLoginInfo.get("userLoginPwd");

        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try 
            // 1.注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2.获取连接
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/userdata",
                    "root", "root");
            // 3.获取预编译的数据库操作对象
            // SQL语句的框架,其中一个?,表示一个占位符,一个?将来接收一个“值”,注意占位符不能用单引号括起来。
            String sql = "select * from t_user where username = ? and userpwd = ?";// sql语句的框架
            // 程序运行到此处,会发送sql语句框架传给DBMS,然后DBMS对sql语句进行预编译。
            ps = conn.prepareStatement(sql);
            // 给占位符?传值(第一个?下标为1,第二个?下表为2。。。。。。)
            ps.setString(1, loginName);
            ps.setString(2, loginPwd);
            // 4.执行sql语句
            rs = ps.executeQuery();
            // 5.处理查询结果集
            if (rs.next()) 
                loginSuccess = true;
            
         catch (ClassNotFoundException | SQLException e) 
            e.printStackTrace();
         finally 
            // 6.关闭资源
            if (rs != null) 
                try 
                    rs.close();
                 catch (SQLException e) 
                    e.printStackTrace();
                
            
            if (ps != null) 
                try 
                    ps.close();
                 catch (SQLException e) 
                    e.printStackTrace();
                
            
            if (conn != null) 
                try 
                    conn.close();
                 catch (SQLException e) 
                    e.printStackTrace();
                
            
        
        return loginSuccess;
    

    private static Map<String, String> initUI() 
        // 获取用户信息
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入账号:");
        String userLoginName = sc.nextLine();
        System.out.println("请输入密码:");
        String userLoginPwd = sc.nextLine();
        Map<String, String> userLoginInfo = new HashMap<>();
        // 将用户信息存入Map中
        userLoginInfo.put("userLoginName", userLoginName);
        userLoginInfo.put("userLoginPwd", userLoginPwd);
        return userLoginInfo;
    

对于不法分子,我想说:就这?

Statement和PreparedStatement的对比

  • Statement存在SQL注入问题,PreparedStatement解决了SQL注入问题。
  • Statement是编译一次执行一次,而PreparedStatement是编译一次,可执行N次,效率较高一些。
  • PreparedStatement在编译过程中进行类型的安全检查。

我们以后大部分情况下,都会使用PreparedStatement。

只有在业务方面必须支持SQL注入,进行SQL语句拼接的时候,必须使用Statement。

以上是关于SQL注入问题的解决(PreparedStatement)的主要内容,如果未能解决你的问题,请参考以下文章

jfinal_sql注入问题解决

SQL注入问题的解决(PreparedStatement)

目标存在SQL注入漏洞。如何解决?

站点SQL注入问题分析及解决

无法解决SQL注入WAF保护

怎么检测网站存在注入漏洞 防注入都有哪些解决办法