fix PersistDbSpecific escaping in persistent-postgresql#1123
fix PersistDbSpecific escaping in persistent-postgresql#1123ldub wants to merge 1 commit intoyesodweb:masterfrom
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. |
|
|
||
| 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.
@ldub Can you link to the corresponding lines in persist-mysql and persist-sqlite for comparison?
There was a problem hiding this comment.
e.g. whatever handles serializing PersistDbSpecific in those packages.
There was a problem hiding this comment.
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.
Or did you mean linking to them directly in the code as a comment?
There was a problem hiding this comment.
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.
@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.
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.
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
toPointescapes 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
PersistDbSpecificfixes 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