Hi Matt, I take it all back... I've been so sure of my own suggestion, I've not really given your RFC a proper read... and I think this could work.
The main difference I had was the ability to support to support the escaping functions (see pg_escape_literal for PostgreSQL, or htmlentities for html output)... and your solution of not supporting any of them keeps the whole thing very simple. Personally I would still like to check html encoding, which your solution won't do... but I realise that is quite tricky, and won't be a perfect solution: $url = 'javascript:alert(document.cookies)'; echo '<a href="' . htmlentities($url) . '">'; But may I request 2 changes: 1) Rather than calling the zend_string property "sql-safe constant", could it simply be "string literal", as in, the variable has only been created by T_STRING's... as this could be used for other things, e.g. executing commands via exec_bind: http://news.php.net/php.internals/87361 2) Include a function that allows the PHP developers to check if the variable being passed is a "string literal", as frameworks can check the state before performing an action, e.g. they could provide the exec_bind function: function exec_bind($cmd, $arguments) { if (!is_string_literal($cmd)) { throw new Exception('...'); } // using escapeshellarg for the $arguments } Craig On 31 Jul 2015, at 14:11, Matt Tait <matt.t...@gmail.com> wrote: >>> This may have been true at one point in time, but my own experience >>> and the statistics collected by Dan Kaminsky of White Hat Security >>> indicates that Cross-Site Scripting vulnerabilities are much more >>> prevalent in 2015 than SQL Injection, especially in business >>> applications. If Google has information that indicates that SQLi is >>> still more prevalent than XSS, I'd love to see this data. > > Thanks Scott! > > You are absolutely correct. SQL injection is a solved problem using > parameterized SQL. In fact, parameterizing queries to avoid SQL injection > is so uncontroversially accepted security advice, that this RFC *enforces* the > advice at the language level (unless the website administrator explicitly > disables the protection across the website via PHP.INI). > > Examples of SQL queries that *would* and *would not *be blocked by this > tool are given in the RFC. In your case, "ORDER BY {$column} ASC" would not > be blocked by this tool if $column came from within the PHP application, > but would be blocked if it came from, say, $_GET["column"]. > > Sadly, although SQL injection is a "solved problem" by using prepared > statements, not everyone follows the advice. Prior to working at Google, I > worked with a company called iSEC Partners who do application review for > various companies. From my experience, between a third and a half of all > the often-huge PHP websites I security-reviewed were vulnerable to SQL > injection somewhere. It wasn't uncommon for the company to have ~5000 or so > SQL queries in their PHP code, only 2-3 of which were vulnerable to > injection. But attackers only need one to ruin your company and steal your > users' data. > > To take apart some of the other valid comments on this thread: > > == SQL injection is dead == > This is objectively not the case > https://www.exploit-db.com/search/?action=search&description=SQL+injection > > == Won't this break every website? == > No. In its initial release, this feature will be released in "disabled" > mode. Website owners with heightened security requirements will be able to > upgrade this to "logging" or "blocking" mode. This means this feature will > have zero impact on websites that do not explicitly enable it. > > == We should be looking at XSS instead == > Solving SQL injection with parameterized SQL queries is uncontroversial and > universally accepted security advice. Lots of different (some working, some > not) advice for solving XSS exist, but this makes it harder to standardize > one of those ideas into the language without significant controversy. > > For example, one website may choose to store HTML content in their > database. This should be printed out to HTML verbatim. Other websites may > accidentally store HTML content in their database, leading to stored-XSS. > The language will not be able to distinguish these two use-cases. > > In contrast, taking content out of a database and gluing it into a SQL > statement is /always/ an error, as it can lead to second-order and > blind-SQL injection vulnerabilities. For this reason, this RFC will > initially only be looking at securing websites against SQL-injections, > although perhaps there is scope to also look at XSS-injection > vulnerabilities in a different RFC using similar tools at a later date. > > == This breaks applications that use OOP or other complicated ways of > sending data to a database == > This is not the case. This RFC doesn't use taint analysis to find SQL > injections; it uses reverse-taint analysis to avoid blocking provably safe > non-parameterized queries (so we don't block queries that are safely built > dynamically out of static strings and variables). Many examples of this are > given in the RFC. > > As you can see from this proof-of-concept ( > http://phpoops.cloudapp.net/oops.php?action=main&dbg_sql&limit=4%20uhoh), > all of the SQL statements are unparameterized, but only one unparameterized > SQL statement that includes attacker-controllable data is blocked, which, > as it turns out, is the only query vulnerable to SQL injection. > > Dynamically construct SQL statements out of provably safe components are > not detected as a SQL-injectable error by this RFC. > > == SQL injection is already solved! Why are you re-solving it? == > This RFC doesn't solve SQL injection in a new way. It blocks dynamic SQL > queries that are not parameterized by default, but uses reverse-taint > analysis to reduce false positives where developers are building SQL query > string out of other constant strings (such as config variables, table > names, column names etc). This feature only takes action when tainted data > is concatenated into a SQL query string and that query string is issued > against the database, and even then, only if PHP.INI has been configured to > do so. > > == We should log, rather than block exploit attempts == > The feature has three modes, which is configurable via PHP.INI: > "Safe" mode causes the query to be aborted, and a SecurityError exception > thrown. > "Logging" mode causes the query to be run, and an E_WARNING raised > "Ignore" more causes the query to be run and no other action to be taken. > > The default mode will be "ignore", i.e. PHP will simply continue as in > older versions. Developers who want to harden their code can run their > website in "logging" mode to find and improve dangerous code in their > codebase. Website administrators with heightened security awareness, or > developers writing new code from scratch will be able to run the feature in > "blocking" mode to prevent any possibility of SQL injection against their > website. > > == What about applications that pass user-submitted SQL statements to the > database by design? == > This is accounted for in the RFC. Developers will be able to explicitly > mark SQL queries as disabling the SQL-injection feature for the queries > that explicitly warrant this (PHPMyAdmin being a good example). Again, this > is only relevant if the website has been explicitly configured to use this > feature. > > Matt > > On 30 July 2015 at 14:43, Scott Arciszewski <sc...@paragonie.com> wrote: > >> On Tue, Jul 28, 2015 at 1:33 PM, Matt Tait <matt.t...@gmail.com> wrote: >>> Hi all, >>> >>> I've written an RFC (and PoC) about automatic detection and blocking of >> SQL >>> injection vulnerabilities directly from inside PHP via automated taint >>> analysis. >>> >>> https://wiki.php.net/rfc/sql_injection_protection >>> >>> In short, we make zend_strings track where their value originated. If it >>> originated as a T_STRING, from a primitive (like int) promotion, or as a >>> concatenation of such strings, it's query that can't have been >> SQL-injected >>> by an attacker controlled string. If we can't prove that the query is >> safe, >>> that means that the query is either certainly vulnerable to a >> SQL-injection >>> vulnerability, or sufficiently complex that it should be parameterized >>> just-to-be-sure. >>> >>> There's also a working proof of concept over here: >>> >>> http://phpoops.cloudapp.net/oops.php >>> >>> You'll notice that the page makes a large number of SQL statements, most >> of >>> which are not vulnerable to SQL injection, but one is. The proof of >> concept >>> is smart enough to block that one vulnerable request, and leave all of >> the >>> others unchanged. >>> >>> In terms of performance, the cost here is negligible. This is just basic >>> variable taint analysis under the hood, (not an up-front intraprocedurale >>> static analysis or anything complex) so there's basically no slow down. >>> >>> PHP SQL injections are the #1 way PHP applications get hacked - and all >> SQL >>> injections are the result of a developer either not understanding how to >>> prevent SQL injection, or taking a shortcut because it's fewer keystrokes >>> to do it a "feels safe" rather than "is safe" way. >>> >>> What do you all think? There's obviously a bit more work to do; the PoC >>> currently only covers mysqli_query, but I thought this stage is an >>> interesting point to throw it open to comments before working to complete >>> it. >>> >>> Matt >> >> Hi Matt, >> >>> PHP SQL injections are the #1 way PHP applications get hacked - and all >> SQL >>> injections are the result of a developer either not understanding how to >>> prevent SQL injection, or taking a shortcut because it's fewer keystrokes >>> to do it a "feels safe" rather than "is safe" way. >> >> This may have been true at one point in time, but my own experience >> and the statistics collected by Dan Kaminsky of White Hat Security >> indicates that Cross-Site Scripting vulnerabilities are much more >> prevalent in 2015 than SQL Injection, especially in business >> applications. If Google has information that indicates that SQLi is >> still more prevalent than XSS, I'd love to see this data. >> >> In my opinion, SQL injection is almost a solved problem. Use prepared >> statements where you can, and strictly whitelist where you cannot >> (i.e. "ORDER BY {$column} ASC") >> >> Scott Arciszewski >> Chief Development Officer >> Paragon Initiative Enterprises <https://paragonie.com> >> -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php