zoukankan      html  css  js  c++  java
  • SQL注入与防范

    首先给大家看个例子:

    1)小编首先在数据库中建立了一张测试表logintable,表内有一条测试信息:

    然后写了个测试程序:

    package com.java.SqlInject;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    public class SqlInject {
    
        private static String Driver="com.mysql.jdbc.Driver"; //数据库驱动
        //连接数据库的URL地址
        private static String url="jdbc:mysql://localhost:3306/hellojdbc?useUnicode=true&characterEncoding=UTF-8";
        private static String username="root";//数据库连接用户名
        private static String password="123456";//数据库连接密码
        
        private static Connection conn=null;//数据库连接对象
        private static Statement stat=null;//语句陈述对象
        private static ResultSet rs=null;//结果数据集
        private static PreparedStatement pst=null;//预编译语句
        
        
        //使用静态块的方式加载驱动
            static {
                try {
                    //调用Class对象的静态forName()方法加载数据库驱动类
                    Class.forName(Driver);
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
                
            }
            
            //使用单例模式返回数据库连接对象
            public static Connection getConnection() throws SQLException{
                if(conn==null){
                    conn=DriverManager.getConnection(url, username, password);
                    return conn;
                }
                return conn;
    
            } 
            
            
            
            public static void login(String name,String password){
                try {
                    conn=getConnection();
                    stat=conn.createStatement();
                    //使用动态拼接的方式拼接sql语句
                    rs=stat.executeQuery("select * from logintable where name='"+name+"' and password='"+password+"'");
                    if(rs.next()){
                        System.out.println("用户已注册");
                    }else
                        System.out.println("无记录");
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            
            
            
        
        public static void main(String[] args) {
            login("zhangsan","123456");
    
        }
    
    }

    输出结果为:

    2)然后我们修改main()方法中,login()方法调用时的参数,改为:

    public static void main(String[] args) {
            login("zhangsan","123");
    
        }

    执行结果:

    3)似乎一切都天经地义,没什么问题。但是这时我们再对login()方法调用的参数做一下修改:

    public static void main(String[] args) {
            //注意:第一个参数两个短杠后面有空格
            login("zhangsan';-- ","123");
    
        }

    测试执行结果又变成了:

    明明用户名和密码都不对,数据库中也没有这条记录,为什么会出现这种情况?

    这就是SQL注入带来的漏洞问题

    恶意用户通过伪装请求,来骗过我们的业务程序,达到获取数据库核心数据的目的。

    通过上面的例子,我们可以看到我们最后一次改写参数来调用login()方法的时候,java业务程序中接收到的不是我们期望的那个sql语句。

    由于分号的存在,使得我们的sql语句拼接后完变成了这样:

    select * from logintable where name='zhangsan';
    --  'password='123';

    这样就由一条sql语句变成了两条sql语句。在第一条的sql语句中去掉了密码的检索条件,同时注释掉了第二条sql语句。

    (两个横线为注释符)

    总结一下:

    SQL注入就是用户在输入表单或者URL参数中输入SQL命令,到达欺骗应用程序的目的,破坏原有SQL的语义,发送恶意的SQL到后端数据库,导致数据库信息出现泄露的漏洞。

    发生这种漏洞的原因是:

    我们的sql语句是通过动态拼接组成的,在拼接完成之前,sql语句是不完整的,所以当在拼接时新加入的参数中有sql命令的注入就有可能改变原有的sql语义。

    比方像上面的例子中,密码被恶意地屏蔽注释掉了。

    解决方法:

    传入外部参数时,不使用动态拼接的方式拼接sql语句;使用参数化方式的sql实现方式(格式化,占位符),即使用预编译的statement。

    然后传参:

    所以上面例子中相关代码应修改为:

                    conn=getConnection();
                    //stat=conn.createStatement();
                    //使用组合的方式拼接sql语句
                    //rs=stat.executeQuery("select * from logintable where name='"+name+"' and password='"+password+"'");
                    
                    pst=conn.prepareStatement("select * from logintable where name= ? and password= ?");
                    pst.setString(1, name);
                    pst.setString(2, password);
                    rs=pst.executeQuery();
                    
                    if(rs.next()){
                        System.out.println("用户已注册");
                    }else
                        System.out.println("无记录");

    其他注意事项:


    使用严格的数据库管理权限:

    1.仅给予Web应用访问数据库的最小权限;

    2.避免Drop table等权限。

    封装数据库错误:

    1.禁止直接将后端数据库异常信息暴露给用户;

    2.对后端异常信息进行必要的封装,避免用户直接查看到后端异常。

    机密信息禁止明文存储:

    1.涉密信息需要加密处理;

    2.使用AES_ENCRYPT/AES_DECRYPT加密和解密。

  • 相关阅读:
    C语言的数组,指针,二级指针,指针数组和数组指针的简单理解
    bash shell 中时间操作常用方法总结
    常见字符串操作方式总结
    查看机器负载常用姿势总结
    netstat命令常用总结
    【技术累积】【点】【java】【20】static关键字
    【技术累积】【点】【java】【19】访问权限
    【技术累积】【点】【java】【18】URLEncode
    【技术累积】【点】【sql】【17】了解索引
    【技术累积】【点】【算法】【17】算法的时间复杂度和空间复杂度
  • 原文地址:https://www.cnblogs.com/dudududu/p/8539157.html
Copyright © 2011-2022 走看看