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

Update fileConfigPage.ts #7878

Merged
merged 9 commits into from
Oct 24, 2019
Merged

Update fileConfigPage.ts #7878

merged 9 commits into from
Oct 24, 2019

Conversation

aspnerd
Copy link
Contributor

@aspnerd aspnerd commented Oct 22, 2019

Issue #2796 - I added the selected database name to the table schema select statement to pull the accurate table schema list.

let query = '';
if (this.databaseDropdown.value !== null)
{
query = `SELECT name FROM [${this.databaseDropdown.value}].sys.schemas`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to have the ]'s escaped

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So what I'm talking about is that you need to escape ]'s in the DB name by doubling them. This is because currently if you try to run that query against a DB that has a ] in its name then you'd end up with a query like this (assuming you have a DB named my]db)

SELECT name FROM [my]db].sys.schemas

which would break because it would see the ] as the end of the object name and thus have invalid syntax.

So the fix is to do something like this

const query = this.databaseDropdown.value ? 'SELECT name FROM [${this.databaseDropdown.value.replace(/]/g, ']]')}].sys.schemas' : 'SELECT name FROM sys.schemas';

So that you end up with a query like this :

SELECT name FROM [my]]db].sys.schemas

which will then run correctly.

(This also safeguards against the SQL injection issues that were mentioned in the previous PR)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am more concerned about spaces in databases names. If they have a bracket in their name I think they have more issues to resolve. I also don't see how SQL injection would play since this is just populating a drop down which is then selected. Unless a user has the ability to adjust the drop down I'm not seeing how they would be able to inject anything.

Copy link
Contributor

@Charles-Gagnon Charles-Gagnon Oct 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bracket-quoting the name is correct, I agree.

But we do require all queries that use values outside of our control to be correctly escaped. And database names fall under that bucket of "out of our control" since a server could have a database with a malicious name (which - while unlikely - is possible).

Unless that is being done correctly we can't take this fix.

Copy link
Contributor Author

@aspnerd aspnerd Oct 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not quite sure how you would escape this, it's not like a quote character. The database names are coming directly from the database connection above which is in control, thus this would also be in control. This isn't a webpage, you can't edit the form and post to your app. Unless I'm missing something here.

Copy link
Contributor

@Charles-Gagnon Charles-Gagnon Oct 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gave you the code above to escape it (you escape them by replacing every ] with ]]) :

const query = this.databaseDropdown.value ? 'SELECT name FROM [${this.databaseDropdown.value.replace(/]/g, ']]')}].sys.schemas' : 'SELECT name FROM sys.schemas';

Here's a possible situation that we are preventing with this. Some bad actor has somehow gotten access to create DBs on the server but not anything else. They create a DB with this name

master].sys.tables; CREATE LOGIN foo WITH PASSWORD='12345' --

Then another person comes along with more permissions - such as being able to create a login. They open the dialog and your code above will create this query :

SELECT name FROM [master].sys.tables; CREATE LOGIN foo WITH PASSWORD='12345' --].sys.schemas

(Note the rest of the query is commented out because of the --)

This query is ran and now this bad actor has silently caused this other user to create a login on the DB. But you can run any query. This is extremely dangerous and as said - while unlikely to actually happen - is something we can't allow to be a possibility.

extensions/import/src/wizard/pages/fileConfigPage.ts Outdated Show resolved Hide resolved
@aaomidi
Copy link
Contributor

aaomidi commented Oct 22, 2019

#2797 @kburtram Do you know if this is still an issue here?

@aaomidi aaomidi requested a review from kburtram October 22, 2019 03:35
@abist
Copy link
Contributor

abist commented Oct 22, 2019

@Charles-Gagnon @aspnerd I think the correct solution here is to use

let metadataProvider = azdata.dataprotocol.getProvider<azdata.MetadataProvider(this.model.server.providerName, azdata.DataProviderType.MetadataProvider);
let databases = await metadataProvider.getDatabases();

That way you don't have to deal with escaping names.

Copy link
Contributor

@abist abist left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be using the MetadataProvider instead of QueryProvider to list the database names.

@Charles-Gagnon
Copy link
Contributor

@abist - This PR is about fixing the schema dropdown, not the database. And unless I'm missing something the metadata provider doesn't provide a way to query for the schemas so this manual query is necessary until that's added.

@aspnerd
Copy link
Contributor Author

aspnerd commented Oct 22, 2019

We should be using the MetadataProvider instead of QueryProvider to list the database names.

@abist, @Charles-Gagnon is correct, we are looking for schemas not databases for this drop down. The issue at hand is that the drop down populated pulls from master, therefore any selected database you want to import into does not list out the correct or available schemas. I ran into this issue when attempting to import a flat file into our 'Staging' schema, and it was not available on the drop down list. The issue is that if a database name has a space in it, if you don't use brackets it will not return a correct result. I would hope most databases don't have a space, but just in case I've added the brackets. We could remove those, then it would fail on databases with spaces.

let query = `SELECT name FROM sys.schemas`;
let databaseName = this.databaseDropdown.value.toString().replace(/]/g, ']]');

const query = this.databaseDropdown.value ? 'SELECT name FROM [${databaseName}].sys.schemas' : 'SELECT name FROM sys.schemas';
Copy link
Contributor

@Charles-Gagnon Charles-Gagnon Oct 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're checking for this.databaseDropdown.value to be truthy here but you've already used it in on line 273 - if it was undefined it would have failed there.

Also I just looked at it myself and the dropdown value is a string | CategoryValue - and specifically in this instance we're populating it with CategoryValue objects. Did you test this yourself? Because I'm surprised it worked with the code you had. Calling toString() on that is just going to return [object Object]

Something like this should work, but you should be testing this yourself too to make sure it works as expected.

const escapedQuotedDb = this.databaseDropdown.value ? `[${(<azdata.CategoryValue>this.databaseDropdown.value).name.replace(/]/g, ']]')}` : '';
const query = `SELECT name FROM ${escapedQuotedDb}.sys.schemas`;

@lgtm-com
Copy link

lgtm-com bot commented Oct 22, 2019

This pull request introduces 1 alert when merging c604abb into 397f6af - view on LGTM.com

new alerts:

  • 1 for Unused variable, import, function or class

@lgtm-com
Copy link

lgtm-com bot commented Oct 22, 2019

This pull request introduces 1 alert when merging 86493c4 into 03cb056 - view on LGTM.com

new alerts:

  • 1 for Unused variable, import, function or class

@@ -270,7 +270,8 @@ export class FileConfigPage extends ImportPage {
let connectionUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
let queryProvider = azdata.dataprotocol.getProvider<azdata.QueryProvider>(this.model.server.providerName, azdata.DataProviderType.QueryProvider);

let query = `SELECT name FROM sys.schemas`;
const escapedQuotedDb = this.databaseDropdown.value ? (<azdata.CategoryValue>this.databaseDropdown.value).name.replace(/]/g, ']]') : '';
const query = 'SELECT name FROM ${escapedQuotedDb}.sys.schemas';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The period should actually also be in the previous part (we don't want to include the period if there isn't a DB name selected)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry about that. I overlooked that. Updated.

@lgtm-com
Copy link

lgtm-com bot commented Oct 23, 2019

This pull request introduces 1 alert when merging ecf1d7e into 41f9f22 - view on LGTM.com

new alerts:

  • 1 for Unused variable, import, function or class

@@ -270,7 +270,8 @@ export class FileConfigPage extends ImportPage {
let connectionUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
let queryProvider = azdata.dataprotocol.getProvider<azdata.QueryProvider>(this.model.server.providerName, azdata.DataProviderType.QueryProvider);

let query = `SELECT name FROM sys.schemas`;
const escapedQuotedDb = this.databaseDropdown.value ? (<azdata.CategoryValue>this.databaseDropdown.value).name.replace(/]/g, ']]') + '.' : '';
const query = 'SELECT name FROM ${escapedQuotedDb}sys.schemas';
Copy link
Contributor

@Charles-Gagnon Charles-Gagnon Oct 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you're using single quotes ( ' ) here instead of backticks ( ` ). You need to use backticks in order for string interpolation to work correctly (otherwise you'll just end up with a string that has ${...} in it)

Also you dropped bracket-quoting the name at some point. I tested this locally and it should work :

		const escapedQuotedDb = this.databaseDropdown.value ? `[${(<azdata.CategoryValue>this.databaseDropdown.value).name.replace(/]/g, ']]')}].` : '';
		const query = `SELECT name FROM ${escapedQuotedDb}sys.schemas`;

Copy link
Contributor

@Charles-Gagnon Charles-Gagnon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thanks for taking the time to fix this and address all the feedback requests!

@Charles-Gagnon Charles-Gagnon merged commit e28ecf4 into microsoft:master Oct 24, 2019
aaomidi added a commit that referenced this pull request Oct 24, 2019
aaomidi pushed a commit that referenced this pull request Oct 25, 2019
* Fix for relative links not being resolved in notebook outputs (#7966)

* Fix for relative links not being resolved

* Add comment

* check for ownerDocument focus for focus (#7964)

* Update recommended package versions for ps (#7972)

* Notebooks: ensure python path dirs added to path on session start (#7968)

* ensure python path dirs add to path session start

* Change logic slightly

* PR feedback from Charles

* Fix node infinitely loading when a firewall dialog is cancelled (#7970)

* add back icons for azure actions

* fix firewall infinite loop

* formatting

* change message to firewall canceled

* fix tests

* remove insider build check (#7926)

* remove insider build check

* fix welcome page not load issue

* Fix troubleshoot URL lookup (#7978)

* Change BDC view errors to use modal dialog instead of error toast (#7985)

* Change BDC view errors to use modal dialog instead of error toast

* Move to common control

* revert the notebook background execution (#7984)

* hide save book action from command pallet (#7981)

* make the azdata install url configurable (#7989)

* make the azdata install url configurable

* use settings without reloading

* comments

* Use selected DB for import wizard schema list (#7878)

* Update fileConfigPage.ts

* Update fileConfigPage.ts

* Update fileConfigPage.ts

* Update fileConfigPage.ts

* Update fileConfigPage.ts

* Update fileConfigPage.ts

* Update fileConfigPage.ts

* Update fileConfigPage.ts

* Update fileConfigPage.ts

* Add SQL Managed Instance support and sorting (#7996)

- Add SQL Instances folder and support using existing SQLClient API
- Sort subscriptions in tree and quickpick for easier search
- Sort all resources (Databases, Servers, Instances) alphabetically too

Not in this PR:
- Will experiment with Graph API for faster perf & easier addition of other Azure resources such as PostgreSQL

* Fix starting and separators in a row (#7861)

* Fixes some code coverage issues (#7994)

* Fix code coverage issues

* Fix some code coverage stuff

* builtinExtension-insiders to builtinExtension (#7973)

* builtinExtension-insiders to builtinExtension

* maintain both insiders and stable.

* builtinExtension.js is for build time and skipping the check for dev.

* check quality and pick insider vs stable json

* Remove RC from strings (#8001)

* delete workflow (#8000)

* Always send \n instead of \r\n to Jupyter kernel (#7995)

* Always send \n instead of \r\n to kernel

* Use replace instead of split/join

* reclassified autoinstallrequired message to error (#7986)

* reclassified autoinstallrequired message to error

* Changed level to warning

* search book gone from command palette (#8002)

* Work with single ext loc file (#7894)

* try loc with single file model

* adding filter and languages

* add links in langpack json

* changing variable name and limiting the list to only tested extensions

* Fix column text overflow on BDC status pages (#7928)

* Fix column text overflow on status page

* Fix typo

* Fix another typo

* suppress the alert (#8007)

* Fix Issue when Saving Wrong Kernel (#7974)

* Only fire kernelChangeEmitter after lang set

* Fix unused import found by lgtm

* Fix comment

* Fix for Markdown File in Jupyter Books Viewlet not Opening After 2x (#8009)

* fix for markdown not opening after opened twice

* PR comment to add return type

* Adjusting context menu for SqlOnDemand (#8018)

* Testing out ci with workflows (#8005)

* add workflow for ci

* add another step

* remove more steps

* fix stdin cancel breaks notebook (#8012)

* serverManager to decide if server start needed (#8017)

* pass install paths to notebooks (#8008)

* pass install paths to notebooks

* onComplete

* discover and publish actual installation Path

* pass the path to notebook

* minor fixes needed post merge of code from remote

* fix some errors

* remove unused variable

* Don't pack the hgh level node_modules directory (#7998)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants