-
Notifications
You must be signed in to change notification settings - Fork 11.1k
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
[5.8] Correctly escape single quotes in json paths #28160
Conversation
5167fc6
to
be1896c
Compare
Thanks for pointing at this, but please next time send an email to: [email protected] directly for all security vulnerabilities as described in the readme.md |
@jmarcher This vulnerability has been disclosed and discussed privately a while ago. Taylor decided not to fix it, so it's public now: https://murze.be/an-important-security-release-for-laravel-query-builder |
@@ -1119,6 +1119,8 @@ protected function wrapJsonFieldAndPath($column) | |||
*/ | |||
protected function wrapJsonPath($value, $delimiter = '->') | |||
{ | |||
$value = preg_replace("/([\\\\]+)?\\'/", "\\'", $value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With preg_replace("/(\\\\)*'/", ...)
, the tests still pass. Is there a difference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You sure? Because it won't match \'
, this would cause only the '
to be escaped. Resulting in \\'
as the end result, which in turn allows for the attack.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't the tests check this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same thoughts as staudenmeir, preg_replace("/\\\\*'/", ...)
appears to be a strictly equivalent code. But simpler thus less error-prone.
I guess you got a bit confused between PHP and regex escaping ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Describing the code:
- replace: quote preceded by 0 or more backslashes
- with: quote preceded by one backslash
Note that you should never allow users to control the columns of your query without a white list. PDO does not allow binding column names as parameters and thus we can't offer much real protection there. |
Even with this fix, I DO NOT encourage anyone to allow users to dictate the columns of their query without a white list. |
@taylorotwell I agree that these kinds of scenarios should be avoided at all costs. Have you considered adding a general warning to the docs? Doctrine, for example, states the following:
— https://www.doctrine-project.org/projects/doctrine-dbal/en/2.9/reference/security.html The Laravel documentation states the follwing:
— https://laravel.com/docs/master/queries#introduction This statement can be confusing for beginners and even seasoned developers (our query builder package is a good example of that). I think it would be good to add a clear warning about the use of user input as column names. |
Since this is considered a security fix, will it be backported to 5.7 and 5.5? |
Looks like 'wrapJsonPath' was only introduced in 5.6 |
@GavG The |
There's a potential SQL injection vulnerability with the JSON query syntax. This PR fixes that.
Laravel will parse JSON paths to
json_extract
functions. Say you've got the following:This will be parsed to:
The actual parsing is done in
\Illuminate\Database\Query\Grammars\Grammar::wrapJsonFieldAndPath()
It is however possible to provide a single quote as the "field" value, which will close the
json_extract
early. This gives an attacker the possibility to insert his own malicious SQL code. Take for example this input (indented for clarity):By manually inserting
'
afterlang->**"
, we're able to break out of thejson_extract
function and inject our malicious code.In this example we're joining on the migrations table, but it's possible to join on anything.
In order for this attack to work, two requirements have to be met:
The solution is to escape all single quotes passed as
$value
in\Illuminate\Database\Query\Grammars\Grammar::wrapJsonPath()
. Because attackers could potentially chain multiple backslashes, this PR will take all single quotes, with or without preceding backslashes, and replace it with\'
.I decided to use a HEREDOC in the tests, for clarity. If this is not ok for Laravel, I'll be happy to change it.