Say that I have a web application that lets users to type in a SQL query (SQL Server 2008+). I want users to be able to run any SELECT query and read whatever is in the database, but I do not want them to be able to insert/update/drop/truncate/exec etc. (in short: only select). Please note that there are no data or even database metadata that are considered confidential in the entire database.
The rules currently in place:
- No ";" character. If it is there, it must be exactly one and at the end of the trimmed query string.
- Query must begin with select (case ignored, white-spaces are part of regex).
- All newlines are removed from the query.
Is this enough? Is there any way to do anything else than just select?
EDIT: Thank you Thomas Stringer for the note about SELECT ... INSERT. This is exactly the information I was after. I will remove all the newlines from the query string, which should help solve this problem. Is there any other way to get around this and be able to modify the data?
NOTE: CTE is not relevant for this case. Lets assume that query has to begin with SELECT.
2 Answers 2
Make sure the application connects to the server using a login that has been given only read permissions (give it the db_datareader role in the database to allow reading all tables), and you should be in good shape. The easiest way to prevent changing data is to ensure the user doesn't have permission to change anything.
Be careful about granting execute permissions, as you may inadvertently allow users to change data depending on what the procedures do.
-
This is certainly a good way to ensure the read-only access. However a] I have to stick with the full access user due to legacy reasons and b] I was wondering from a knowledge point of view if there is any "security hole" in my logic (1)+(2).NeverStopLearning– NeverStopLearning2013年10月09日 11:29:20 +00:00Commented Oct 9, 2013 at 11:29
-
1I'm sure you'll find loads of holes by attempting to build security into the parser. For example, you don't actually need a ; to terminate statements. Doing this all on one line is perfectly valid:
SELECT TOP 100 * FROM sys.databases UPDATE pubs..authors SET address = NULL
db2– db22013年10月09日 14:36:28 +00:00Commented Oct 9, 2013 at 14:36 -
Perfect! This is the information I was asking for. I did not know that you did not have to separate the two commands using semicolon or newline! Thanks. Anything else?NeverStopLearning– NeverStopLearning2013年10月09日 14:40:21 +00:00Commented Oct 9, 2013 at 14:40
-
If you must use the existing login/user for authenticating, then look into application roles. You can have your application switch to an application role after logging in, providing it with only read permissions.db2– db22013年10月09日 14:49:12 +00:00Commented Oct 9, 2013 at 14:49
-
1@NeverStopLearning: More to the point:
SELECT 1 DROP DATABASE MyProdDB
-- is the application user a member ofdb_owner
?Jon Seigel– Jon Seigel2013年10月09日 17:55:59 +00:00Commented Oct 9, 2013 at 17:55
If direct SQL is going to be allowed, you really have to use a separate login for it if the main application connection is read/write.
Not only should this login have restricted permissions as @db2 mentioned, but doing this also allows you to do things like better-manage the resources (Resource Governor) being used by this feature. Even if all that's allowed are SELECT
statements, there's nothing stopping a malicious user (or even a careless user!) from mounting a denial-of-service attack by executing an extremely expensive query. If you don't have the granularity to be able to separate application activity from this type of activity, you're pretty much out of luck. Don't wait until this happens to try to stop it. Put mechanisms in place to prevent it in the first place.
-
1That's a good point about denial-of-service.
SELECT * FROM hugetable h1 CROSS JOIN hugetable h2 WHERE dbo.expensivefunction(h1.bigcolumn, h2.bigcolumn) = 1 OPTION (MAXDOP 0)
Say goodbye to your buffer cache and CPU cycles.db2– db22013年10月09日 14:53:09 +00:00Commented Oct 9, 2013 at 14:53 -
In my case that would be considered as out of scope for the security setting. But a good point.NeverStopLearning– NeverStopLearning2013年10月10日 08:24:24 +00:00Commented Oct 10, 2013 at 8:24
SELECT
permissions, etc.select 1 </new line here> insert into .... blah blah blah
? It looks like that would fit your rules, but if you aren't enforcing permissions on the database you could have users doing things you don't want them to do.