9 ms·
Aren't there other benefits to server-side parameter binding besides just SQL-injection safety? For instance, using PG's extended protocol (binary) instead of
by benwilber0 1y ago
Aren't there other benefits to server-side parameter binding besides just SQL-injection safety? For instance, using PG's extended protocol (binary) instead of just raw SQL strings. Caching parameterized prepared statements, etc.
Also:
db.execute(t"QUERY WHERE name = {name}")
Is dangerously close to:
db.execute(f"QUERY WHERE name = {name}")
A single character difference and now you've just made yourself trivially injectible.
I don't think this new format specifier is in any way applicable to SQL queries.
- deleted 1y ago[deleted]
- VWWHFSfQ 1y ago> I don't think this new format specifier is in any way applicable to SQL queries. Agree. And the mere presence of such a feature will trigger endless foot-gunning across the Python database ecosystem.
- masklinn 1y ago> Aren't there other benefits to server-side parameter binding besides just SQL-injection safety? For instance, using PG's extended protocol (binary) instead of just raw SQL strings. Caching parameterized prepared statements, etc. All of which can be implemented on top of template strings. > A single character difference and now you've just made yourself trivially injectible. It's not just a one character difference, it's a different type. So `db.execute` can reject strings both statically and dynamically. > I don't think Definitely true. > this new format specifier is in any way applicable to SQL queries. It's literally one of PEP 750's motivations.
- VWWHFSfQ 1y ago> It's literally one of PEP 750's motivations. Python is notorious for misguided motivations. We're not "appealing to authority" here. We're free to point out when things are goofy.
- willcipriano 1y agofrom string.templatelib import Template def execute(query: Template) Should allow for static analysis to prevent this issue if you run mypy as part of your pr process. That would be in addition to doing any runtime checks.
- benwilber0 1y agoThe first mistake we're going to see a library developer make is: def execute(query: Union[str, Template]): Maybe because they want their execute function to be backwards compatible, or just because they really do want to allow either raw strings are a template string.
- masklinn 1y ago> they really do want to allow either raw strings are a template string. I’d consider that an invalid use case: 1. You can create a template string without placeholders. 2. Even if the caller does need to pass in a string (because they’re executing from a file, or t-strings don’t support e.g. facetting) then they can just… wrap the string in a template explicitly.
- woodrowbarlow 1y agonitpicking: > It's not just a one character difference, it's a different type. So `db.execute` can reject strings both statically and dynamically. in this case, that's not actually helpful because SQL statements don't need to have parameters, so db.execute will always need to accept a string.
- tczMUFlmoNk 1y ago> > I don't think > Definitely true. The rest of your comment is valuable, but this is just mean-spirited and unnecessary.
- rangerelf 1y ago>> I don't think >Definitely true. I thought we left middle-school playground tactics behind.
- deleted 1y ago[deleted]
- davepeck 1y ago> Caching parameterized prepared statements, etc. I didn’t explicitly mention this in my post but, yes, the Template type is designed with caching in mind. In particular, the .strings tuple is likely to be useful as a cache key in many cases.
- MR4D 1y agoDang! Thanks for pointing this out. I had to look SEVERAL times at your comment before I noticed one is an F and the other is a T. This won’t end well. Although I like it conceptually, this few pixel difference in a letter is going to cause major problems down the road.
- pphysch 1y agoHow? tstrings and fstrings are literals for completely different types. CS has survived for decades with 1 and 1.0 being completely different types.
- Izkata 1y agoBecause they're both passed to "execute", which can't tell between the f-string and a non-interpolated query, so it just has to trust you did the right thing. Typoing the "t" as an "f" introduces SQL injection that's hard to spot.
- vlovich123 1y agoAssuming `execute` takes both. You could have `execute(template)` and `execute_interpolated(str, ...args)` but yeah if it takes both you'll have challenges discouraging plain-text interpolation.
- Izkata 1y agoIt would have to be the other way around or be a (possibly major) breaking change. Just execute() with strings is already standard python that all the frameworks build on top of, not to mention tutorials: https://docs.python.org/3/library/sqlite3.html https://docs.python.org/3/library/sqlite3.html https://www.psycopg.org/docs/cursor.html https://www.psycopg.org/docs/cursor.html https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-execute.html https://dev.mysql.com/doc/connector-python/en/connector-pyth...
- 1y ago
- deleted 1y ago[deleted]
- WorldMaker 1y agoTemplates are a very different duck type from strings and intentionally don't support __str__(). The SQL tool can provide a `safe_execute(Template)` that throws if passed a string and not a Template. You can imagine future libraries that only support Template and drop all functions that accept strings as truly safe query libraries. > Caching parameterized prepared statements, etc. Templates give you all the data you need to also build things like cacheable parameterized prepared statements. For DB engines that support named parameters you can even get the interpolation expression to auto-name parameters (get the string "name" from your example as the name of the variable filling the slot) for additional debugging/sometimes caching benefits.
- deleted 1y ago[deleted]
- rastignack 1y agoQuite easy to detect with a proper linter.
- hombre_fatal 1y agoYou solve that with an execute(stmt) function that requires you to pass in a template. In Javascript, sql`where id = ${id}` is dangerously close to normal string interpolation `where id = ${id}`, and db libs that offer a sql tag have query(stmt) fns that reject strings.
- InstaPage 1y agot vs f going to be hard to spot.
- acdha 1y agoThis is true of many other things, which is why we have type checkers and linters to be perfectly rigorous rather than expecting humans to never make mistakes.
- PennRobotics 1y agoand syntax highlighting
- kazinator 1y agoBut t"..." and f"..." have different types; we can make db.execute reject character strings and take only template objects.
- HackerThemAll 1y agoYeah that would be a backward compatible way to do stuff.
- zahlman 1y ago> A single character difference and now you've just made yourself trivially injectible. No; a single character difference and now you get a `TypeError`, which hopefully the library has made more informative by predicting this common misuse pattern.