zoukankan      html  css  js  c++  java
  • java学习笔记38(sql注入攻击及解决方法)

    上一篇我们写了jdbc工具类:JDBCUtils ,在这里我们使用该工具类来连接数据库,

    在之前我们使用 Statement接口下的executeQuery(sql)方法来执行搜索语句,但是这个接口并不安全,容易被注入攻击,注入攻击示例:

    首先我们需要一个存放登录用户名密码的表:

    use qy97;
    create table login(
      id int primary key auto_increment,
      sname varchar(50),
      pwd varchar(50)
    );
    insert into login values
    (1,'zhangsan','111'),
    (2,'lisi','123');

    然后我们写代码实现登陆:

    package com.zs.Demo;
    
    import JDBCUtils.JDBCUtils;
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.Scanner;
    
    public class SQLZhuRu {
        public static void main(String[] args) {
            Scanner sc=new Scanner(System.in);
            System.out.println("请输入用户名:");
            String name = sc.nextLine();
            System.out.println("请输入密码:");
            String pwd = sc.nextLine();
            login(name,pwd);
        }
    
        private static void login(String name, String pwd) {
            Connection conn = JDBCUtils.getConnection();
            String sql = "select * from login where sname='"+name+"'and pwd='"+pwd+"';";
            System.out.println(sql);
            Statement stat = null;
            ResultSet rs=null;
            try {
                stat = conn.createStatement();
                rs = stat.executeQuery(sql);
                if (rs.next()) {
                    System.out.println("登陆成功,欢迎" + rs.getString("sname"));
                } else {
                    System.out.println("登录失败!!");
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
    
            JDBCUtils.close(conn,stat,rs);
        }
    }

    运行结果如下:

    输入账号密码,然后在数据库中搜索,搜索到数据则登录成功,否则登录失败:

    可是,当我们这样输入时,也能登陆成功:

    从上面语句可以看出,执行的sql与语句是:select * from login where sname='lisi'and pwd='789 'or'1=1';

    1=1是恒成立的,or 只要两边有一个为true 则为 true  ,所以登录成功,这是一个最简单的注入攻击,

    解决方法:使用prepareStatement接口,以上一个例子为基础做修改

    package com.zs.Demo;
    
    import JDBCUtils.JDBCUtils;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.util.Scanner;
    
    public class PerpareStatementDemo {
        public static void main(String[] args) {
            Scanner sc=new Scanner(System.in);
            System.out.println("请输入用户名:");
            String name = sc.nextLine();
            System.out.println("请输入密码:");
            String pwd = sc.nextLine();
            try {
                login(name,pwd);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //传递变量name pwd给方法
        private static void login(String name, String pwd) throws Exception {
            Connection conn = JDBCUtils.getConnection();
    //        设置?占位置,将查询的参数用?来替换
            String sql="select * from login where sname=? and pwd=?";
            PreparedStatement pre = conn.prepareStatement(sql);
    //        setObject方法来设置占位的?的值
            pre.setObject(1,name);//设置第一个?的值为变量name
            pre.setObject(2,pwd);//设置第二个?的值为变量pwd
            ResultSet rs = pre.executeQuery();
            if (rs.next()) {
                System.out.println("登陆成功");
            } else {
                System.out.println("登录失败");
            }
            JDBCUtils.close(conn, pre, rs);
        }
    }

    运行结果:

     

    可以看出,在不改变sql语句的情况下将?替换为变量的值,当注入攻击时:

    可以看出来这个接口更加安全,所以建议使用这个接口来实现增删改查;关于PrepareStatement接口:(官方文档)

      PrepareStatement接口:

        表示预编译的SQL语句的对象。

        SQL语句已预编译并存储在PreparedStatement对象中。 然后可以使用该对象多次有效地执行此语句。

        注意:setter方法( setShortsetString用于设置IN参数值必须指定与所定义的SQL类型的输入参数的兼容的类型,等等)。 例如,如果IN参数具有SQL类型INTEGER ,   则应使用方法setInt

    使用PrepareStatemnet接口实现数据库的更新:

    package com.zs.Demo;
    
    import JDBCUtils.JDBCUtils;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    
    public class PrepareStatementDemo2 {
        public static void main(String[] args) {
            Connection conn = JDBCUtils.getConnection();
            String sql="update login set sname = ? where id=?;";
            PreparedStatement pst =null;
            try {
                pst = conn.prepareStatement(sql);
                pst.setObject(1, "dijia");
                pst.setObject(2,1);
                pst.executeUpdate();
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                JDBCUtils.close(conn, pst);
            }
        }
    }
  • 相关阅读:
    406, "PRECONDITION_FAILED
    windows10x64环境安装RabbitMQ
    jquery插件formValidator的ajaxValidator传参数问题
    “~/Views/Home/Text.aspx”处的视图必须派生自 ViewPage、ViewPage<TModel>、ViewUserControl 或 ViewUserControl<TModel>。
    无法安装程序包“MIcrosoft.Owin.Security 2.0.2”。您正在尝试将此程序包安装到某个将“.NETFramework,Version=v4.0”作为目标的项目中。
    MSSQL优化之——查看语句执行情况
    C# 测试代码运行时间
    转换 Html 内容为纯文本内容(html,文本互转)
    腾讯微博OAuth2.0 .NET4.0 SDK 发布以及网站腾讯微博登陆示例代码(原创)
    QQ互联OAuth2.0 .NET SDK 发布以及网站QQ登陆示例代码(转)
  • 原文地址:https://www.cnblogs.com/Zs-book1/p/10638578.html
Copyright © 2011-2022 走看看