-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
SQLite: Is there a way to load extensions? #1460
Comments
TL;DR: this isn't currently supported. There's We would probably want to expose the C API to do this, rustqlite supports this in kind of an interesting way, it provides I think I would prefer to limit this even further, and only allow declaring what extensions to load in impl SqliteConnectOptions {
pub fn load_extension(self, path: impl AsRef<Path>, entrypoint: Option<String>) -> SqliteConnectOptions { ... }
} The other question is how do we make this work with the macros? If we add extensions to
The other option would be something like we were discussing in #121. |
@abonander: Thanks for your response!
The main concern is SQL injection (giving attackers access to the extension-loading functionality). So if a user is careful to deactivate extension-loading after loading all extensions, there shouldn't be a problem. On the other hand, adding native support to SQLx for loading extensions (as you propose) shouldn't be significantly more work. Unfortunately, I don't know C, so I can't help implement it, I believe.
Personally, I'd prefer a second environment variable like An alternative would be to use the URL fragment for configuration, which only requires to escape
The URL fragment isn't sent from clients to servers, so this also might serve as a hint, that this is client-side configuration. I think, SQLite extension-loading would be a great addition to SQLx. My own use-case is to load an extension for transparent row-level text compression (my project will have a huge amount of text). I guess, for now, I have to use |
Today I thought about this a bit more... Wouldn't it be a security risk to load database extensions via environment variables? If an attacker can somehow change environment variables, and can add/change a database extension, he/she can execute arbitrary code, I believe. For example, if a web application has an unsafe file upload feature, an attacker can:
I only recently started to study web application security, so I'm not remotely an expert in this kind of stuff. But if I can come up with a potential way to exploit such a feature, then criminal hacker surely can as well. The above is mostly a problem if we use the environment variable to automatically load database extensions at runtime. The benefit of this would be, that a user only needs to define database extensions once (via the One easy solution would be to only use the environment variable data for the validation the macros do (as mentioned above). There would be a risk that a user extracts the database extension information from Another way would be to have some kind of global configuration macro: sqlx::sqlite::config_database_extensions!(config); ...but I'm not sure, if that is even possible (I've never used procedural macros before). I think it's pretty imported to think about this carefully, to not introduce a remote code execution vulnerability. I think a "global config macro" approach would be safest, because in this case an attacker needs to be able to change the source code (which is much less likely than being able to change environment variables. The source code can't be changed at runtime, but environment variables can). Besides the production server, other potential targets could be the machine of a developer, and the CI server (which often contains API key and other credentials). I can't come up with a potential attack scenario for these targets, but that doesn't mean that criminal hackers can't. This is another reason why I believe a global config macro would be safest. |
In your attack scenario, if an attacker is able to overwrite the |
environment variables doesn't mean then need to come from .env. |
Sure, my point is just that an upload feature that's broken so severely would allow lots of other attacks too. Here's some other examples:
If an attacker had control over the environment variables for a web app outside of |
I think with env variables depending how they are passed (not from .env) this could be done without write access to the host. |
@jplatte: Sure there are several possible ways such a vulnerability can be exploited, and all have advantages and disadvantages. For example, what will you do, if the binary hasn't a common name like You can brute-force a name like "my-xy-application", but this is much harder than overwriting a Also, if you replace the main binary, it's immediately obvious that something is wrong (because the web application doesn't work anymore, after you trigger the restart). An infected database probably can go undetected for a long time. And you only have one attempt. If you make any mistake, you get caught (or at least can't try again because th web application is down). A database extension can be tested locally to be relatively confident, that it won't crash the database and web application. Besides that, my attack scenario was just an example I came up (in a few seconds) to illustrate how such a feature might be exploited. I don't know enough about Linux (let alone other operating systems) to be confident that there aren't other ways to exploit this feature (if the environment variable is used at runtime). You never know in what environment someone is running something and what other vulnerabilities exist, etc. Maybe every possible way to exploit this feature would also enable another attack with similar or higher severity, maybe this feature would enable unique exploits, who knows? So if there is a way to implement something in a way that might be exploitable, and there is a way to implement it in a way that can't be exploited (without having write access to the source code) — why would we choose the former? I don't believe, that preventing the need to duplicate one line of code is worth it, to be honest. Remote code execution is generally a vulnerability of the highest severity, so I'd be rather safe than sorry – especially with a library that is used as much as |
I'm going to make a judgement call here, and say that to obviate various issues, the list of extensions to load should more often than not be hardcoded anyway so I now think it should not be part of the database URL or determined by an environment variable. This makes it harder to forget to specify extensions to be loaded at runtime that are important for an application's function, such as ones that add new SQL functions. You can parse a let mut options = SqliteConnectOptions::parse(&env::var("DATABASE_URL")?)?;
options.load_extension("sqlite-std");
let pool = SqlitePool::connect_with(options).await?; As for the macros, it's the same thing. You don't want to forget to list extensions in the database URL or miscellaneous environment variable that are necessary to compile, so it makes sense to specify them in the application code: sqlx::config_macros!(sqlite_extension = "sqlite-zstd"); If you want the list of extensions to be runtime-specifiable still, you can integrate that into your application: for ext in env::var("SQLITE_EXTENSIONS").ok().unwrap_or_else(String::new).split(",") {
options.load_extension(ext);
} |
closed by #2062 |
So, is there any way to load extensions for macros? |
Still can't specify extensions for |
Hi,
I'm looking for a way to load custom extensions into SQLite, but I can't find anything.
I'm not very experienced with SQLite and completely new to SQLx – is this somehow possible?
The text was updated successfully, but these errors were encountered: