-
Notifications
You must be signed in to change notification settings - Fork 292
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
fix PersistDbSpecific escaping in persistent-postgresql #1123
Conversation
Note that while I believe fixing this bug is important and correct, it will cause issues for people who already use PersistDbSpecific with persistent-postgres, requiring them to manually add quotes around in existing toPersistValue implementations. I need advice on how we could proceed with fixing this. |
@@ -550,7 +551,7 @@ instance PGFF.FromField Unknown where | |||
Just dat -> return (Unknown dat) | |||
|
|||
instance PGTF.ToField Unknown where | |||
toField (Unknown a) = PGTF.Escape a | |||
toField (Unknown a) = PGTF.Plain $ BB.byteString a |
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.
@ldub Can you link to the corresponding lines in persist-mysql
and persist-sqlite
for comparison?
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.
e.g. whatever handles serializing PersistDbSpecific
in those packages.
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.
Yeah, they are linked at the top of my PR description, but here they are again:
Currently, the implementation of PersistDbSpecific
:
- (in persistent-mysql) does not escape the given ByteString: https://github.com/yesodweb/persistent/blob/master/persistent-mysql/Database/Persist/MySQL.hs#L239
- (in persistent-sqlite) does not escape the given ByteString: https://github.com/yesodweb/persistent/blob/master/persistent-sqlite/Database/Sqlite.hs#L470
- (in persistent-postgresql) does escape the given ByteString (with single quotes): https://github.com/yesodweb/persistent/blob/master/persistent-postgresql/Database/Persist/Postgresql.hs#L553
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.
Or did you mean linking to them directly in the code as a comment?
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.
No, I just jumped straight into the code changes w/o reading the PR description. Sorry for making extra work for you 😓
import qualified Data.ByteString as B | ||
import qualified Data.ByteString.Char8 as B8 | ||
|
||
data Geo = Geo ByteString deriving (Show, Eq) |
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.
@ldub You concluded that persist-postgres
's handling of PersistDbSpecific
was a bug because of differences in how other SQL backends handle PersistDbSpecific
when running this example. Can we move these test fixtures to a more-central location so that we can test this same example against all the SQL backends? That would help make the case that persist-postgres
's handling of PersistDbSpecific
is indeed a bug, and it would help prevent similar bugs in the future.
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.
We can't run this test against any other backend because PostGIS is a postgres-specific extension.
However, I can port the NullableGenerated
test from my other PR. Would that be good?
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.
So, what examples, specifically, led you to believe persist-postgres
was in error? It's something along those lines that we would need to automate.
For context, here's the PR that introduced this issue: #160 Prior to this PR, /cc @bergmark @gregwebs: Could you perhaps look over and chime in on this PR? I reviewed #160 and #153 and I don't see any obvious reason why escaping was necessary to add. It is incompatible with the mysql and sqlite implementations and, as you mentioned back in 2013, it breaks the Geo example. |
So, this seems potentially crazy dangerous to me, if we're saying that Persistent's Postgresql users will be opened up to SQL injection attacks from lack of escaping. I think the opposite direction, having MySQL and SQLite escape, is probably preferable. Any sort of SQL injection is a HUGE vulnerability that I think should come with bright red warning flags |
After discussion, @MaxGabriel @friedbrice and I have decided that the correct course of action is to improve #1122 instead of doing what I did in this PR. That will require a bit more work in the coming days/weeks. I still welcome any thoughts on this topic (figuring out how to support unescaped sql keywords, how to release a breaking change to escape mysql/sqlite PersistDbSpecific values, etc). |
@parsonsmatt I am worried that this would be a big breaking change for people currently using PersistDbSpecific with MySQL and SQLite. We are planning to implement PersistLiteral as is and have a separate PR for the MySQL and SQLite escaping changes. What do you think? |
I think it's important to get it right. Fixing it now in a major version bump is a good idea IMO. 2.11 is going to be a major version bump, and so it's Legal to throw that change in there. The changelog should say what's going on and point to the solution - If this is going to be a Massive Problem for folks - then we may want to figure out a larger migration plan and 'fix' it in 3.0. |
Yeah, this is done. On The commit that resolves this is aacd5e4
|
Closing this out since the work is handled in other PRs. |
Currently, the implementation of
PersistDbSpecific
:This inconsistency led me to believe that the persistent-postgresql behavior is a bug. And indeed, looking at Persistent's own documentation:
persistent/persistent/Database/Persist/Types/Base.hs
Lines 381 to 405 in 7f4abe9
We can see that
toPoint
escapes thePOINT(44 44)
entry to become'POINT(44 44)'
, and when inserting, persistent-postgresql will once again escape this to become''POINT(44 44)''
which will lead to a runtime error. This further indicates that the escaping in persistent-postgresql is a bug.I wrote a test to show this. It fails with the currently implementation of
instance PGTF.toField Unknown
:My change to stop escaping
PersistDbSpecific
fixes the test.This is related to my investigation/implementation in #1122. I chose to make this a standalone PR to more clearly demonstrate the issue.
cc/ @MaxGabriel @friedbrice @parsonsmatt