• ref:web 防止SQL注入方法


    ref:https://blog.csdn.net/beidou321/article/details/6482618

    小结:spring采用JdbcTemplate来操作sql,一般不要自行拼接sql,而是使用参数化的构造方式,则不会存在注入问题。

    SQL注入往往是在程序员编写包含用户输入的动态数据库查询时产生的,但其实防范SQL注入的方法非常简单。程序员只要

    a)不再写动态查询b)防止用户输入包含能够破坏查询逻辑的恶意SQL语句,就能够防范SQL注入。

    在这篇文章中,我们将会说明一些非常简单的防止SQL注入的方法。我们用以下Java代码作为示例,

    String query ="SELECT account_balance FROM user_data WHERE user_name ="
      + request.getParameter("customerName");//sql语句拼接一般都有问题。除+外还有append函数也可以搜索下。
    try {
    Statement statement  = connection.createStatement( …);
    ResultSet results = Statement.executeQuery(query);
    }

    在以上代码中,我们可以看到并未对变量customerName做验证,customerName的值可以直接附在query语句的后面传送到数据库执行,则攻击者可以将任意的sql语句注入。

    一般来说,sql注入有两种:int型注入和字符串注入。对于int注入,只要在拼接时严格设置为int类型,例如intval或者java中函数参数为int,即可防止注入。

    对于字符串注入,只要对'进行转义即可。 

    防范方法1:参数化查询

    参数化查询是所有开发人员在做数据库查询时首先需要学习的,参数化查询迫使所有开发者首先要定义好所有的SQL代码,然后再将每个参数逐个传入,这种编码风格就能够让数据库辨明代码和数据。

    参数化查询能够确保攻击者无法改变查询的内容,在下面修正过的例子中,如果攻击者输入了UsrID是“’or ‘1 ‘=’1”,参数化查询会去查找一个完全满足名字为‘or ‘1 ‘=’ 1的用户。

    对于不同编程语言,有一些不同的建议:

    Java EE——使用带绑定变量的PreparedStatement()

    .Net——使用带绑定变量的诸如SqlCommand()OleDbCommand()的参数化查询;

    PHP——使用带强类型的参数化查询PDO(使用bindParam());

    Hibernate——使用带绑定变量的createQuery()

    Java示例:
    
    String custname = request.getParameter("customerName");
    String query ="SELECT account_balance FROM user_data WHERE user_name= ?";
    PreparedStatement pstmt =connection.prepareStatement(query);
    Pstmt.setString(1,custname);
    ResultSet results = pstmt.executeQuery();
    
    C# .Net示例:
    String query ="SELECT account_balance FROM user_data WHERE user_name = ?";
    Try {     
    OleDbCommand command = new OleDbCommand(query,connection);
    command.Parameters.Add(new OleDbParameter("customerName",CustomerName.Text));
    OleDbDataReader reader = command.ExecuteReader();
    }catch (OleDbException se){
    //error handling
    }

    防范方法二:存储过程

    存储过程和参数化查询的作用是一样的,唯一的不同在于存储过程是预先定义并存放在数据库中,从而被应用程序调用的。

    Java存储过程示例:
          String custname = request.getParameter("customerName");
          try {
    CallableStatement cs = connection.prepareCall("call sp_getAccountBalance(?)}");
    cs.setString(1,custname);
    Result results = cs.executeQuery();
          }catch(SQLException se){
                 //error handling
          }
    
    VB .Net存储过程示例:
    Try
    Dim command As SqlCommand = new SqlCommand("sp_getAccountBalance",connection)
     command.CommandType = CommandType.StoredProcedure
     command.Parameters.Add(new SqlParameter("@CustomerName",CustomerName.Text))
     Dim reader As SqlDataReader = command.ExecuteReader()
     ‘…
    
    Catch se As SqlException
     ‘error handling
    End Try

    防范方法三:对所有用户输入进行转义

    我们知道每个DBMS都有一个字符转义机制来告知DBMS输入的是数据而不是代码,如果我们将所有用户的输入都进行转义,那么DBMS就不会混淆数据和代码,也就不会出现SQL注入了。

    当然,如果要采用这种方法,那么你就需要对所使用的数据库转义机制,也可以使用现存的诸如OWASP ESAPIescaping routinesESAPI目前是基于MySQLOracle的转义机制的,使用起来也很方便。一个OracleESAPI的使用示例如下:

    ESAPI.encoder().encodeForSQL(new OracleCodec(),queryparam);

    那么,假设你有一个要访问Oracle数据库的动态查询代码如下:

    String query =SELECT user_id FROM user_data WHERE user_name = ‘+req.getParameter(userID)+’ and user_password = ‘+req.getParameter(pwd)+;

    try {

          Statement statement = connection.createStatement(…);

          ResultSet results = statement.executeQuery(query) ;

    }

    那么,你就必须重写你的动态查询的第一行如下:

    Codec ORACLE_CODEC = new OracleCodec();
    String query ="SELECT user_id FROM user_data WHERE user_name = "+//注意必须有引号,如果没有,则int类型注入就可绕过。
    ESAPI.encoder().encodeForSQL(ORACLE_CODEC,req.getParameter("userID"))+" and user_password = ‘"+
    ESAPI.encoder().encodeForSQL(ORACLE_CODEC,req.getParameter("pwd"))+"’"; 

    当然,为了保证自己代码的可读性,我们也可以构建自己的OracleEncoder

    Encoder e = new OracleEncoder();

    String query =SELECT user_id FROM user_data WHERE user_name = ‘

          + oe.encode(req.getParameter(userID)) +’ and user_password = ‘

          + oe.encode(req.getParameter(pwd))+;

    除了上面所说的三种防范方法以外,我们还建议可以用以下两种附加的方法来防范SQL注入:最小权限法、输入验证白名单法。

    最小权限法:

    为了避免注入攻击对数据库造成的损害,我们可以把每个数据库用户的权限尽可能缩小,不要把DBA或管理员的权限赋予你应用程序账户,在给用户权限时是基于用户需要什么样的权限,而不是用户不需要什么样的权限。当一个用户只需要读的权限时,我们就只给他读的权限,当用户只需要一张表的部分数据时,我们宁愿另建一个视图让他访问。如果你的策略是都是用存储过程的话,那么仅允许应用程序的账户执行这些查询,而不给他们直接访问数据库表的权限。诸如此类的最小权限法能够在很大程度上保证我们数据库的安全。

    输入验证白名单法:

    输入验证能够在数据传递到SQL查询前就察觉到输入是否正确合法,采用白名单而不是黑名单则能在更大程度上保证数据的合法性。

  • 相关阅读:
    【Python】在控制台输出不同颜色的文字
    【python】如何去掉使用BeautifulSoup读取html出现的警告UserWarning: You provided Unicode markup but also provided a value for from_encoding
    【nodejs】修改了下对股票表进行crud操作的代码
    【nodejs】用express又做了份crud
    day20_day23课堂笔记
    Myeclipse中java web.xml报错cvc-complex-type.2.3: Element 'web-app' cannot have character [children], because the type's content type is element- only.
    html中让input标签只读不可编辑的方法
    Win10锁屏壁纸位置在哪? 默认锁屏壁纸怎么提取?
    Potplayer怎么实现视频的镜面翻转?
    How to export Excel files in a Python/Django application
  • 原文地址:https://www.cnblogs.com/studyskill/p/9640461.html
Copyright © 2020-2023  润新知