MySQL PHP PDO prepared statements - performance issues vs security

前端 未结 4 1687
一个人的身影
一个人的身影 2021-01-12 14:32

I am thinking of rewriting some open-source application for my purposes to PDO and transactions using InnoDB (mysql_query and MyISAM now).

My question is: Which case

相关标签:
4条回答
  • 2021-01-12 15:17

    I think this falls in the "premature optimization" category.

    How significant is the overhead? Have you measured it? Does it affect your server performance at all?

    Odds are it doesn't.


    On the plus side, you have an undeniable gain in terms of security (which should be a major concern for any internet-based shop).

    On the downside, you have the risk that it might affect performance. In the link you provided, it shows that poorly implemented PDO preparation results in slightly lower performance than non prepared statement in some circumstances. Performance difference on 5000 runs is 0.298 seconds.

    Insignificant. Even more so when you realize that the "non prepared" queries are run without the input sanitizing routines that would be required to make them safe in a live environment. If you don't use the prepared queries, you need some form of input sanitizing to prevent SQL attacks, and depending on how it is done, you may need to massage back the result sets.

    Bottom line, there is no significant performance issue, but there is a significant security benefit. Thus the official recommendation of using prepared statements.

    In your question, you speak of "the common eshop". The "common eshop" will never have enough traffic to worry about the performance issue, if there is one. The security issue on the other end...

    0 讨论(0)
  • 2021-01-12 15:17

    My question is: Which cases are reasonable for using prepared statements?

    Well actually, that's hard to say. Especially as you didn't even tell which open source application you speak about here.

    To give you an example: For a ultra-lame guestbook app PDO with prepared statements will be the perfect choice, as well for 99% of all other open source apps out there. But for some this actually can make a difference. The important part here is: You have not told anything about the application.

    As the database is not unimportant to an application, it's the other way round as well: the application is not unimportant to the database.

    So you either need to share more about that "mysterious" open-source application you ask about or you need to tell us, what exactly you would like to know. Because generally, it's simple: Take PDO. But in specific, there are differences, so you need to tell us what the application in specific is, otherwise your question is already answered.

    And btw., if the application is mysql_* style, it's much easier to just replace with mysqli_* interface. If you had done some actually rewriting, even just for fun, you would have seen that.

    So better add more meat here or live with some not-so-precise answers.

    0 讨论(0)
  • 2021-01-12 15:22

    While this question is rather old, some topics were not really discussed that should be outlined here for others researching the same as the OP.

    To summarize everything below:

    • Yes always use prepare statements
    • Yes use PDO over mysqli over mysql. This way if you switch database systems all you need to do is update the queries instead of queries, function calls, and arguments given it supports prepared statements.
    • Always sanitize user supplied data despite using prepared statements with parameters
    • Look into a DBAL (Database Abstraction Layer) to ease working with all of these factors and manipulating queries to suit your needs.

    There is the topic of PDO::ATTR_EMULATE_PREPARES which will increase the performance of calling cached queries in MySQL >= 5.1.21 when emulation is turned OFF, which is ENABLED by default. Meaning PHP will emulate the prepare before execute sends it to the actual database. The time between emulated and non-emulated is normally negligible unless working with an external database (not localhost), such as on a cloud, that may have an abnormally high ping rate.

    The caching depends on your MySQL settings in my.cnf as well, but MySQL optimization outside the scope of this post.

    <?php
    $pdo = new \PDO($connection_string); 
    $pdo->setAttribute( \PDO::ATTR_EMULATE_PREPARES, false );
    ?>
    

    So keep this in mind since mysqli_ does not provide an API for client side emulation and is always going to use MySQL for preparing statements. http://www.php.net/manual/en/mysqli.quickstart.prepared-statements.php

    Despite having similar features there are differences and you may need features that one API provides while the other does not. See PHP's reference on choosing one API over the other: http://www.php.net/manual/en/mysqlinfo.api.choosing.php

    So this pretty much goes along with what you asked with defining your statements application-wide, as cacheable queries would be cached on the MySQL server, and wouldn't need to be prepared application-wide. The other benefit is that exceptions in your Query would be thrown at prepare() instead of execute() which aids in development to ensure your Queries are correct.

    Regardless there is no real world performance benefits of using prepare or not.

    Another benefit of prepared statements is working with Transactions if you use InnoDB for MySQL. You can start a transaction, insert a record, get the last insert id, update another table, delete from another, and if anything fails along the way you can rollBack() to before the transaction took place. Otherwise commit the changes if you choose to. For example working with a new order and setting the user's last order column to the new order id, and delete a pending order, but the supplied payment type did not meet the criteria for placing orders from the order_flags table, so you can rollBack() and show the user a friendly error message.

    As for security, I am rather baffled no one touched on this. When sending any user supplied data to ANY system including PHP and MySQL, sanitize and standardize it. Yes prepared statements do provide some security when it comes to escaping the data but it is NOT 100% bullet proof.

    So always using prepared statements is far more beneficial than not with no real performance loss, and some benefits with caching, but you should still sanitize your user supplied data. One step is to typecast the variables to the desired data type you are working with. Using objects would further ease this since you work within a single Model for the data types as opposed to having to remember it each time you work with the same data.

    To add on to the above you should look into a database abstraction layer that uses PDO. For example Doctrine DBAL: http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/query-builder.html

    The added benefits of working with a DBAL+PDO are that

    • You can standardize and shorten the amount of work you have to do.
    • Aid in sanitization of user supplied data
    • Easily manipulate complex queries
    • Use nested transactions
    • Easily switch between databases
    • Your code becomes more portable and usable in other projects

    For example I extended PDO and overrode the query(), fetchAll(), and fetch() methods so that they would always use prepared statements and so that I could write SQL statements inside fetch() or fetchAll() instead of having to write everything out again. EG:

    <?php
    $pdo = new PDOEnhanced( $connection );
    $pdo->fetchAll( "SELECT * FROM foo WHERE bar = 'hi'", PDO::FETCH_OBJ ); 
    
    //would automatically provide
    $stmt = $pdo->prepare( "SELECT * FROM foo WHERE bar=?" );
    $stmt->execute( array( 'hi' ) );
    $resultSet = $stmt->fetchAll( PDO::FETCH_OBJ )
    ?>
    

    As for people suggesting that mysql_* style, is much easier to just replace with mysqli_* API. It is not the case. A large portion of mysql_* functions were left out or had arguments changes with mysqli_* See: http://php.net/manual/en/mysqli.summary.php

    You can however get a converter released by Oracle to ease the process: https://wikis.oracle.com/display/mysql/Converting+to+MySQLi

    Keep in mind that it is a file source text parser and is not 100% accurate so validate the changes before merging them. It will also add a significant amount of overhead for the globals it creates.

    0 讨论(0)
  • 2021-01-12 15:23

    My question is: Which cases are reasonable for using prepared statements?

    All of them. The community is openly-opposed to the usage of mysql_* functions.

    Note: Suggested alternatives

    Use of this extension is discouraged. Instead, the MySQLi or PDO_MySQL extension should be used. See also MySQL: choosing an API for more information.

    Alternatives to this function include:

    • mysqli_connect()
    • PDO::__construct()

    source

    But thinking it over and over it comes to mind that having to prepare the statement every time and then use it once.. It doesn't make sense

    You're trading in a Geo for a Jaguar and you're complaining that you don't like the Jaguar because you don't always use the seat-heaters. You don't have to be consistently using every function of a library to mean it's good.

    I found there is this mysql_real_escape called $pdo->quote as well for the purpose of single query. Why not to use this? Why to bother with preparing?

    If you are using this function to build SQL statements, you are strongly recommended to use PDO::prepare() to prepare SQL statements with bound parameters instead of using PDO::quote() to interpolate user input into an SQL statement. Prepared statements with bound parameters are not only more portable, more convenient, immune to SQL injection, but are often much faster to execute than interpolated queries, as both the server and client side can cache a compiled form of the query. source

    0 讨论(0)
提交回复
热议问题