PHP/SQL Database querying good practice and security

后端 未结 6 2025
忘了有多久
忘了有多久 2020-12-14 04:54

So I\'m a slightly seasoned php developer and have been \'doin the damn thing\' since 2007; however, I am still relatively n00bish when it comes to securing my applications.

相关标签:
6条回答
  • 2020-12-14 05:07

    My recommendations:

    1. ditch mysqli in favor of PDO (with mysql driver)
    2. use PDO paremeterized prepared statements

    You can then do something like:

    $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 );
    

    PROs:

    1. No more manual escaping since PDO does it all for you!
    2. It's relatively easy to switch database backends all of a sudden.

    CONs:

    • i cannot think of any.
    0 讨论(0)
  • 2020-12-14 05:14

    Javier's answer which has the owasp link is a good start.

    There are a few more things you can do more:

    1. Regarding SQL injection attacks, you can write a function that will remove common SQL statements from the input like " DROP " or "DELETE * WHERE", like this:

      *$sqlarray = array( " DROP ","or 1=1","union select","SELECT * FROM","select host","create table","FROM users","users WHERE");*

      Then write the function that will check your input against this array. Make sure any of the stuff inside the $sqlarray won't be common input from your users. (Don't forget to use strtolower on this, thanks lou).

    2. I'm not sure if memcache works with PHP 4 but you can put in place some spam protection with memcache by only allowing a certain remote IP access to the process.php page X amount of times in Y time period.

    3. Privileges is important. If you only need insert privileges (say, order processing), then you should log into the database on the order process page with a user that only has insert and maybe select privileges. This means that even if a SQL injection got through, they could only perform INSERT / SELECT queries and not delete or restructuring.

    4. Put important php processing files in a directory such as /include. Then disallow all IPs access to that /include directory.

    5. Put a salted MD5 with the user's agent + remoteip + your salt in the user's session, and make it verify on every page load that the correct MD5 is in their cookie.

    6. Disallow certain headers (http://www.owasp.org/index.php/Testing_for_HTTP_Methods_and_XST) . Disallow PUT(If you dont need file uploads)/TRACE/CONNECT/DELETE headers.

    0 讨论(0)
  • 2020-12-14 05:29

    I don't usually work with PHP so I can't provide advice specifically targeted to your requirements, but I suggest that you take a look at the OWASP page, particularly the top 10 vulnerabilities report: http://www.owasp.org/index.php/Top_10_2007

    In that page, for each vulnerability you get a list of the things you can do to avoid the problem in different platforms (.Net, Java, PHP, etc.)

    Regarding the prepared statements, they work by letting the database engine know how many parameters and of what types to expect during a particular query, using this information the engine can understand what characters are part of the actual parameter and not something that should be parsed as SQL like an ' (apostrophe) as part of the data instead of a ' as a string delimiter. Sorry I can not provide more info targeted at PHP, but hope this helps.

    0 讨论(0)
  • 2020-12-14 05:30

    AFAIK, PHP/mySQL doesn't usually have parameterized queries.

    Using sprintf() with mysql_real_escape_string() should work pretty well. If you use appropriate format strings for sprintf() (e.g. "%d" for integers) you should be pretty safe.

    0 讨论(0)
  • 2020-12-14 05:30

    Use stored procedures for any activity that involves wrinting to the DB, and use bind parameters for all selects.

    0 讨论(0)
  • 2020-12-14 05:34

    I may be wrong, but shouldn't it be enough to use mysql_real_escape_string on user provided data?

    unless when they are numbers, in which case you should make sure they are in fact numbers instead by using for example ctype_digit or is_numeric or sprintf (using %d or %u to force input into a number).

    Also, having a serarate mysql user for your php scripts that can only SELECT, INSERT, UPDATE and DELETE is probably a good idea...


    Example from php.net

    Example #3 A "Best Practice" query

    Using mysql_real_escape_string() around each variable prevents SQL Injection. This example demonstrates the "best practice" method for querying a database, independent of the Magic Quotes setting.

    The query will now execute correctly, and SQL Injection attacks will not work.

       <?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";
        }
    
    0 讨论(0)
提交回复
热议问题