Skip to content
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

Revisit prisma.$queryRaw("...") vs. prisma.$queryRaw template literal #7142

Closed
2 of 3 tasks
Tracked by #8628
matthewmueller opened this issue May 18, 2021 · 6 comments · Fixed by #8728
Closed
2 of 3 tasks
Tracked by #8628

Revisit prisma.$queryRaw("...") vs. prisma.$queryRaw template literal #7142

matthewmueller opened this issue May 18, 2021 · 6 comments · Fixed by #8728
Assignees
Labels
kind/improvement An improvement to existing feature and code. team/client Issue for team Client. topic: raw $queryRaw(Unsafe) and $executeRaw(Unsafe): https://www.prisma.io/docs/concepts/components/prisma-cli topic: security
Milestone

Comments

@matthewmueller
Copy link
Contributor

matthewmueller commented May 18, 2021

Problem

Right now it's really easy to write a raw query that's susceptible to SQL injections

// Raw query. Susceptible to SQL injections! 
prisma.$queryRaw(`SELECT \* FROM User WHERE email = ${email}`);

// Prepared query. Not susceptible to SQL injections.
prisma.$queryRaw`SELECT \* FROM User WHERE email = ${email}`;

The difference is in the ( and ). This is far too subtle and there's no warning about which is which.

Suggested solution

  • Investigate: Can we differentiate between prisma.$queryRaw("...") and the prisma.$queryRaw template literal?

If so,

  • Rename prisma.$queryRaw("...") to something else. Perhaps $queryDangerouslyRaw.

    I think there are since there are places where you can't use a prepared statement (e.g. CREATE TABLE "${table}"). If so, I don't think we want to disallow the capability entirely.

  • Consider writing a codemod for npx @prisma/codemods to rename function calls (not template literals) to the new method

If not,

  • Consider other alternatives for clearly separating these two behaviors

Other Ideas

  • Maybe it's possible for our VS Code extension to detect it and return a warning.
  • Or maybe it's possible at runtime to detect that it's used the wrong way and throw an error?
@matthewmueller matthewmueller added process/candidate kind/improvement An improvement to existing feature and code. team/client Issue for team Client. labels May 18, 2021
@matthewmueller matthewmueller changed the title Revisit prisma.$queryRaw(...) vs. prisma.$queryRaw... Revisit prisma.$queryRaw(...) vs. prisma.$queryRaw template May 18, 2021
@matthewmueller matthewmueller changed the title Revisit prisma.$queryRaw(...) vs. prisma.$queryRaw template Revisit prisma.$queryRaw(...) vs. prisma.$queryRaw template literal May 18, 2021
@matthewmueller matthewmueller changed the title Revisit prisma.$queryRaw(...) vs. prisma.$queryRaw template literal Revisit prisma.$queryRaw(\...\) vs. prisma.$queryRaw template literal May 18, 2021
@matthewmueller matthewmueller changed the title Revisit prisma.$queryRaw(\...\) vs. prisma.$queryRaw template literal Revisit prisma.$queryRaw(...) vs. prisma.$queryRaw template literal May 18, 2021
@matthewmueller matthewmueller changed the title Revisit prisma.$queryRaw(...) vs. prisma.$queryRaw template literal Revisit prisma.$queryRaw("...") vs. prisma.$queryRaw template literal May 18, 2021
@pantharshit00
Copy link
Contributor

Related: #7095

@janpio janpio added topic: raw $queryRaw(Unsafe) and $executeRaw(Unsafe): https://www.prisma.io/docs/concepts/components/prisma-cli topic: security labels May 18, 2021
@matthewmueller
Copy link
Contributor Author

Internal Note: we consider this breaking change before the next major release.

@matthewmueller
Copy link
Contributor Author

matthewmueller commented Aug 14, 2021

The design of this change is the following:

Narrowed $queryRaw (breaking change)

  • $queryRaw now only supports a template literal.
  • This is always a parameterized query and therefore not susceptible to SQL injections.
  • The signature is prisma.$queryRaw`query`.
  • For example, prisma.$queryRaw`select * from users where email = ${email}`

Added $queryRawUnsafe

  • $queryRawUnsafe is a new function that can be a string or template string.
  • The signature is prisma.$queryRawUnsafe(query, args...).
  • This allows you to pass a raw template string in. For example, prisma.$queryRawUnsafe("create table ${table}").
  • You could still have a parameterized query. For example, prisma.$queryRawUnsafe("select * from users where email = $1", "alice@prisma.io"). This is mostly to make the upgrade path easier.

$queryRaw to $queryRawUnsafe codemod

We plan to add a codemod to https://github.com/prisma/codemods that will turn all $queryRaw functions into $queryRawUnsafe functions. It will ignore $queryRaw tagged templates, since those work as is.

@Sytten
Copy link
Contributor

Sytten commented Aug 16, 2021

Discussed it with @millsp on slack, but basically I got into the code of a pretty large customer that uses prisma and I found a lot of sql injections due to improper use of prisma raw queries. So I support that 100%.

Basically I want the following to fail:

let query = `SELECT * FROM table`
if (id) {
  query += `WHERE id = ${id}`
}
prisma.$queryRaw(query)

But this should still work:

let query = sql`SELECT * FROM table`
if (id) {
  query = sql`${query} WHERE id = ${id}`
}
prisma.$queryRaw(query)

@millsp
Copy link
Member

millsp commented Aug 16, 2021

Yes, the last call will work while the first one will fail.

@matthewmueller
Copy link
Contributor Author

Closing since we've learned this will be possible.

Remaining tasks are tracked in: #8628

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/improvement An improvement to existing feature and code. team/client Issue for team Client. topic: raw $queryRaw(Unsafe) and $executeRaw(Unsafe): https://www.prisma.io/docs/concepts/components/prisma-cli topic: security
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants