代码之家  ›  专栏  ›  技术社区  ›  lsl

查询良好实践和安全性的PHP/SQL数据库

  •  7
  • lsl  · 技术社区  · 16 年前

    因此,我是一个稍微有经验的PHP开发人员,从2007年开始就“干这该死的事情”;但是,在保护我的应用程序方面,我仍然是一个不太好的人。我不知道我所知道的一切,我可以也应该知道。

    我已经接电话了 Securing PHP Web Applications 我正在读我的方法,一路测试。我有一些关于数据库查询(主要在mysql下)的常规so组的问题:

    当创建将数据放入数据库的应用程序时,mysql的真正转义字符串和输入数据的常规检查(数字等)是否足够?与SQL注入不同的其他类型的攻击呢?

    有人能解释存储过程和准备好的语句吗?你能用更多的信息来解释它们并调用它们。我想知道它们是如何工作的,哪些验证是在幕后进行的。

    我在一个php4绑定的环境中工作,目前还不能选择php5。以前有没有人做过这样的工作,当所有的酷孩子都在使用这个可爱的新mysqli界面时,你做了什么来保护你的应用程序?

    人们发现有哪些一般的好做法是有利的,重点是创建能够承受升级和可能迁移的基础设施(如将php4移动到php5)。

    注意:在搜索中找不到与此类似的内容,这些内容会影响php-mysql的安全性。

    6 回复  |  直到 16 年前
        1
  •  6
  •   Kris    16 年前

    我的建议:

    1. 抛弃mysqli PDO (使用MySQL驱动程序)
    2. 使用PDO缩减的已准备语句

    然后您可以执行如下操作:

    $pdo_obj = new PDO( 'mysql:server=localhost; dbname=mydatabase', 
                        $dbusername, $dbpassword );
    
    $sql = 'SELECT column FROM table WHERE condition=:condition';
    $params = array( ':condition' => 1 );
    
    $statement = $pdo_obj->prepare( $sql, 
        array( PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY ) );
    $statement->execute( $params );
    $result = $statement->fetchAll( PDO::FETCH_ASSOC );
    

    赞成的意见:

    1. 没有更多的手动逃逸,因为PDO为你做了一切!
    2. 突然切换数据库后端相对容易。

    欺骗:

    • 我想不出任何。
        2
  •  9
  •   SteveGSD    16 年前

    有OWASP链接的Javier的答案是一个很好的开始。

    您还可以做更多的事情:

    1. 关于SQL注入攻击,您可以编写一个函数,该函数将从输入中删除常见的SQL语句,如“drop”或“delete*where”,如下所示:

      *$sqlarray=array(“drop”,“or 1=1”,“union select”,“select*from”,“select host”,“create table”,“from users”,“users where”);*

      然后编写一个函数,根据这个数组检查您的输入。确保$sqlarray中的任何内容都不会是用户的常用输入。(别忘了在这上面使用strtolower,谢谢卢)。

    2. 我不确定memcache是否与php 4一起工作,但是您可以通过memcache设置一些垃圾邮件保护,只允许在y时间段内对process.php页面进行一定的远程IP访问x次。

    3. 特权很重要。如果您只需要插入权限(例如,订单处理),那么您应该使用只有插入权限或可能选择权限的用户登录到“订单处理”页上的数据库。这意味着,即使通过了SQL注入,它们也只能执行插入/选择查询,而不能删除或重新构造。

    4. 将重要的PHP处理文件放在/include等目录中。然后禁止所有IP访问该/include目录。

    5. 在用户会话中放置一个带有用户代理+远程IP+您的salt的MD5,并在每次页面加载时验证其cookie中是否存在正确的MD5。

    6. 不允许某些邮件头( http://www.owasp.org/index.php/Testing_for_HTTP_Methods_and_XST )不允许放置(如果不需要文件上载)/跟踪/连接/删除邮件头。

        3
  •  3
  •   Javier    16 年前

    我通常不使用PHP,因此我无法提供针对您需求的建议,但我建议您查看owasp页面,尤其是前10个漏洞报告: http://www.owasp.org/index.php/Top_10_2007

    在该页面中,对于每个漏洞,您可以获得在不同平台(.NET、Java、PHP等)中避免问题的列表。

    对于准备好的语句,它们的工作方式是让数据库引擎知道在特定查询期间需要多少参数和类型,使用这些信息,引擎可以理解哪些字符是实际参数的一部分,而不是像'(撇号)那样作为数据指令的一部分应被解析为SQL的内容。作为字符串分隔符的'ad。抱歉,我不能提供更多针对PHP的信息,但希望这有帮助。

        4
  •  2
  •   Jonathan Maddison    16 年前

    afaik、php/mysql通常没有参数化查询。

    使用 sprintf() 具有 mysql_real_escape_string() 应该工作得很好。如果使用适当的格式字符串 Simulf() (例如整数为“%d”)您应该相当安全。

        5
  •  1
  •   Svish    16 年前

    我可能错了,但它不应该足够用吗 mysql_real_escape_string 关于用户提供的数据?

    除非它们是数字,在这种情况下,您应该确保它们实际上是数字,而不是使用例如 ctype_digit is_numeric sprintf (使用) %d %u 强制输入数字)。

    另外,对于只能选择、插入、更新和删除的PHP脚本,使用serarate mysql用户可能是一个好主意…


    php.net示例

    示例3“最佳实践”查询

    在每个变量周围使用mysql_real_escape_string()可以防止SQL注入。这个例子演示了查询数据库的“最佳实践”方法,与magic quotes设置无关。

    现在查询将正确执行,SQL注入攻击将不起作用。

       <?php
        if (isset($_POST['product_name']) && isset($_POST['product_description']) && isset($_POST['user_id'])) {
            // Connect
    
            $link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password');
    
            if(!is_resource($link)) {
    
                echo "Failed to connect to the server\n";
                // ... log the error properly
    
            } else {
    
                // Reverse magic_quotes_gpc/magic_quotes_sybase effects on those vars if ON.
    
                if(get_magic_quotes_gpc()) {
                    $product_name        = stripslashes($_POST['product_name']);
                    $product_description = stripslashes($_POST['product_description']);
                } else {
                    $product_name        = $_POST['product_name'];
                    $product_description = $_POST['product_description'];
                }
    
                // Make a safe query
                $query = sprintf("INSERT INTO products (`name`, `description`, `user_id`) VALUES ('%s', '%s', %d)",
                            mysql_real_escape_string($product_name, $link),
                            mysql_real_escape_string($product_description, $link),
                            $_POST['user_id']);
    
                mysql_query($query, $link);
    
                if (mysql_affected_rows($link) > 0) {
                    echo "Product inserted\n";
                }
            }
        } else {
            echo "Fill the form properly\n";
        }
    
        6
  •  0
  •   pauljwilliams    16 年前

    将存储过程用于涉及到对数据库进行写操作的任何活动,并将绑定参数用于所有选择。