-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implementing $qb->setIdentifier()
to support literal-string
#9047
Conversation
Just adding the public methods to set/get Identifiers, to start the discussion on Issue doctrine#8933.
Thank you for the PR. I have changed the target branch to 2.10 because this change does not really pass as a bugfix. I'm afraid, I'm not really familiar with the |
🤔 I'm confused, this is the ORM, so the identifiers in this PR should not designate SQL objects such as tables
"field names" as in properties of a PHP class sounds correct, but "table" does not. People writing DQL are not supposed to deal with tables directly, are they? Also, we're discussing this internally, and there are several concerns with this:
|
I must confess, I'm not too familiar with Doctrine. I'm more of a code auditor, where I work with fairly typical software development teams to identify where they can make improvements. Last year I audited a couple of projects using Doctrine, and found the usual security mistakes, which resulted in SQL Injection vulnerabilities. While I appreciate Doctrine has documented these issues, developers aren't guaranteed to read or understand (especially junior developers); and even then, mistakes happen. @derrabus, thanks for updating the target branch. The @greg0ire, thanks for the clarification, I have been incorrectly reading this as SQL, as it acted like SQL when I found those injection vulnerabilities. Interestingly your example is very close to one of the vulnerabilities I found (slightly altered from the original, just to keep it simple, and avoid pointing fingers): $result = $qb
->select('u')
->from('User', 'u')
->where('u.id = ' . $_GET['id']); // INSECURE I believe this code should follow "binding parameters to your query", which uses a $result = $qb
->select('u')
->from('User', 'u')
->where('u.id = :id')
->setParameter('id', $_GET['id']); I appreciate integers cannot introduce an SQL Injection vulnerability, but following the discussion on the PHP Internals mailing list, treating some variables as safe because of their type, seemed to confuse a few people, especially when many projects let PHP be a little vague with types. False positives are a concern, but assuming you're using As to "what should happen if the newly introduced syntax for identifiers is used inside a string literal?"... I'm open to suggestions on the syntax, but going with: $result = $qb
->select('u')
->from('User', 'u')
->where('{my_field} = :my_value') // A nice simple `literal-string`.
->setIdentifier('my_field', $_GET['field']) // Applied to {my_field} using $platform->quoteIdentifier()
->setParameter('my_value', $_GET['id']); I don't think this syntax will cause issues for existing code, as the brackets cause a Syntax Error. |
The code like this, especially if embraced by the API: ->setIdentifier('my_field', $_GET['field']) Is as fundamentally wrong as: ->where('u.id = ' . $_GET['id']); The input must not define the application logic. The application logic should be defined by the developer. The new API allows |
@morozov, You are right, the value should be checked against an allow-list. I only wrote But I will note that it's not "as fundamentally wrong", because the second example provides a full Injection Vulnerability; whereas And this method would rarely be used, but it should exist to ensure variable identifiers are being included and quoted correctly (at the moment it's easier to include these values incorrectly, via basic concat)... and maybe the As an aside, $order_fields = [
'name',
'created',
'admin',
];
$order_id = array_search(($_GET['sort'] ?? NULL), $order_fields);
$sql .= ' ORDER BY ' . $order_fields[$order_id]; |
Filtering input that describes a data source (e.g. a table column) against a white list is a must first step. It should be done not only when building queries but in other cases as well (e.g. when fetching data from a query). The filtering logic may be more complex than Quoting identifiers is secondary. It's only needed to prevent the identifiers that contain SQL syntax elements from being interpreted as language instructions rather than values. Quoting an identifier will make it case-sensitive on Oracle and IBM DB2, so it cannot be applied just automatically until there's full support for handling identifiers as first-class citizens (see doctrine/dbal#4357, doctrine/dbal#4772). The API being proposed is a poor solution to the secondary problem sweeping the primary one under the rug. |
@morozov I agree. Filtering which fields are allowed is important, and it is a separate issue that's not really part of QueryBuilder (and hasn't been included in my proposal)... but if it was, a basic (and optional) one would at least prompt developers as they type: Interestingly your suggestion of using As to quoting identifiers, that's my main focus, because I'm trying to address Injection Vulnerabilities. And I should note, there is nothing "automatic" about this, as developers would use this new method to ensure all of these variable Identifiers are "always" being quoted, correctly (which would avoid your noted issues with the list of keywords, case-sensitivity, and special characters); it will also provide you with a way to receive Identifiers "as first-class citizens", in the same way that Parameters work. That said, I don't mind how variable Identifiers are provided to Doctrine, I just want to stop things like this from happening: ->where($_GET['where']); // INSECURE, in this case the value was coming from JavaScript :-) This is why certain parameters should use Also, following on from our email discussion on the 26th April, about the |
There hasn't been any activity on this pull request in the past 90 days, so it has been marked as stale and it will be closed automatically if no further activity occurs in the next 7 days. |
This pull request was closed due to inactivity. |
Not ready yet. Just trying to start a discussion on supporting
Identifiers
(table and field names), in a similar way to howParameters
work.This would allow several
QueryBuilder
methods to useliteral-string
values (strings written by the developer), so anyone using static-analysis will be prevented from creating Injection Vulnerabilities (ref #8933).The first commit just adds the public methods to set/get Identifiers. I'm not too sure where the
Identifier
values should be added to the SQL, maybe inQuery::parse()
, using$platform->quoteIdentifier()
?