Here's an example of the sort of query I would like to prevent from running on my server:
begin
While True
LOOP
dbms_output.put_line('tst');
END LOOP;
end
This query (or others like it) may be hitting my Oracle server via the Oracle JDBC thin driver. I would be open to preventing this query from running either at the JDBC configuration level, the database server configuration level, or via user permissions within the schema. I would like the user to continue to be able to run normal select/insert/update/delete queries. Honestly I'd be quite happy if none of the PL/SQL type commands were available, and instead only standard SQL.
Update
I should also mention that I want users to continue to be able to use standard functions in their SQL queries. I just really don't want them doing anything that looks like procedural programming (and having to worry about the pitfalls of such things, as seen above).
You can't prevent people from writing procedural PL/SQL code against your server. Depending on the exact nature of the problem you're trying to solve, however, you may have other options. Two options that spring to mind...
You can create a profile associated with the database user that enforces various resource limits. So you can limit the amount of CPU a single call can consume or the number of reads it can do. That lets you automatically kill sessions that do something like coding an infinite loop. Note that the RESOURCE_LIMIT initialization parameter needs to be set to TRUE in order for Oracle to enforce resource limits in profiles.
You can use Oracle Resource Manager to prioritize access to resources to reduce the risk that a developer's mistake will take all the resources available on the server and starve the important production processes.
Related
I have a Java application that does a POST with the sql query that is typed in the UI and is executed using JDBC. Since the query is user defined, I'm unable to find a way to prevent the SQL injection issue. For instance if this is the query the user issues :
select * from test_table where id=123
a POST is done with this string to the servlet and this is executed as a query. Is there anyway to get around this since there is no restriction on what user can send in?
Thanks
Technically if the user is allowed to write the entire query, it's not an injection attack risk, it's simply an attack risk
Run the query using a database user that has permission only to carry out the types of operations you deem acceptable on the tables you're willing to give access to.
For example, only permit SELECT on tableX, tableY and tableZ. No DML, no DDL and no selecting from any other table
If your dbms of choice doesn't allow fine grained control in this way then instead execute a regular batch script that creates another database containing only a few tables. Permit your users to query this new db. If it does get wrecked it will soon be dropped and replaced by a working one with updated data, by the script. This is also beneficial if placed on another server, it stops your live system from being innocently DOSed by a user executing a duff query that takes up all resource on the server
SQL injection would be passing select * from test_table where id=123 in place of a parameter.
Not sure exactly what information you are letting the application use, but I would suggest granting access only to a specific schema. That would provide a consistent security model.
As others have suggested, this is not SQL injection - I call this a "designed in" SQL injection. How you deal with it depends on the use case:
Design a separate interface that does not require the full SQL statement
As Caius suggested, if you can limit the privs in the DB account to only do what the user can do, that would limit the damage
If this is an administrative interface, you may want to limit the usage of this interface to "trusted" users. If you go that route, you want to be very careful to document that users with this privilege have full access to the database, and provide an auditing mechanism to make sure that that list of users is well known.
It is not realistically possible to limit the SQL statement through validation - its a powerful language, especially in the context of modern databases.
See also this related question
Is there anyway to get around this since there is no restriction on what user can send in?
I'm not sure what you mean by "get around." Is it not the design of this application to allow users to run any query?
If you want to prevent them from running unauthorized queries, then you'll have to implement some Java code in the servlet to check the query and decide whether it's one they're authorized to run.
Some people do this by whitelisting a specific set of known queries. Just match the user's input query against the whitelist.
If they can run a given query with a variety of different constant values, then replace constant values with a ? in both the whitelisted form and in a copy of the user's input SQL query.
If they can run a variety of different queries, like with optional clauses and stuff, so that it's impossible to make a whitelist of finite length, then you'll have to implement a SQL parser in your Java servlet and some kind of business rule engine to decide if their query is authorized before you run it against the real database.
At this point, it seems easier to change the application front-end so that users are not allowed to submit arbitrary SQL queries!
When developing an application where users connect with their native database logins, I don't need to care about SQL injection right? The reason being the users can execute any SQL they want anyway. (There are places where admins execute CREATE LOGIN and CREATE USER statements and these have to be dynamically built.) I'm talking about a native Windows application on the LAN.
Well, SQL injection is a possibility to execute SQL, so with the SQL shell access, everything required for "SQL injection" is already authorized. However you still need to care if users run as non administrators, probably being restricted which tables they can access, and your system sends some additional SQL commands while logged in with higher rights (create user, etc). Use prepared statements for such a code.
If you mean that you are building a web application, and using users' database credentials to connect to the database, yes, you do need to worry about SQL injection.
Most databases restrict permissions based on objects - tables, views, stored procedures etc. So, a user logged in as "Bob" might have access to table "sales", but not table "payments".
The database does not restrict access to rows in tables (for instance). So, a user connected as "Bob" who can exploit a SQL injection bug in your code can delete every record in the "sales" table. You probably don't want that.
If user "Bob" also has direct SQL access, they could, of course, simply run that statement at a SQL command line - but usually, web applications are available where direct SQL access is not. Your web app may be put on the intranet to begin with, but you can't guarantee that won't be opened up in the future.
Given how easy it is to prevent SQL injection attacks when you're building the app, and what a pain it is to fix them later on, I see no real reason not to prevent them in the first place.
As a matter of fact, "SQL injection" is a common misconception.
Being unable to properly format their queries, folks invented an "sql injection" thing as an excuse.
While properly formatted query will serve 2 purposes at once:
it will always be syntactically correct, no matter what data sent in.
as a side effect it would be invulnerable to that notorious "SQL injection" thing.
I doubt you want your queries to fail because of some unexpected symbol. So, no matter of some "injection", you have to properly format it. But once formatted, there will be no injection anyway. So, you have to concern about format, not injections.
I also have a feeling that letting users to login with database credentials is not quite a good idea.
I've just started looking at a system that implements security a little differently to the norm.
They create a new SQL user for each user of the system (of which there are about 32K now). Each query is sent via a connection that is initially using the SA account (lets not get bogged down on this), then after we know who the user is, the EXECUTE AS USER is used each query.
Now that there are so many users, creating new users and switching has a noticeable performance hit and the company is looking at improving the situation.
A few points:
- SQL Code is dynamic sql (not stored procedures)
- The original idea was to alleviate the need for the developers of the company to worry about writing SQL worrying about permissions - and let another layer worry about it.
How does one try and improve the query execution time and avoid the EXECUTE AS USER code and still get the same security scrutiny?
Does SQL Server support session variables to store a user account?
It's difficult to know whether this is helpful without a bit more detail on how your application security model and how it controls and/or pools database connections. Is it a fat client, n-tier or something else?
SQL connections can support a single "session variable" using CONTEXT_INFO - a user-configurable binary(128) field which persists for the duration of the connection. This may meet your requirements, but you need to beware that if you use it to store security information it will be accessible to the end user - you should therefore probably encrypt or salt and hash any security information in the CONTEXT_INFO to prevent users tampering with their permissions; this may have performance implications.
It may not be applicable depending on your application architecture, but have you considered switching to Windows authorisation and organising permissions though Active Directory users and groups?
It seems that one could stop all threat of Sql injection once and for all by simply rejecting all queries that don't use named parameters. Any way to configure Sql server to do that? Or else any way to enforce that at the application level by inspecting each query without writing an entire SQL parser? Thanks.
Remove the grants for a role to be able to SELECT/UPDATE/INSERT/DELETE against the table(s) involved
Grant EXECUTE on the role for stored procedures/functions/etc
Associate the role to database user(s) you want to secure
It won't stop an account that also has the ability to GRANT access, but it will stop the users associated to the role (assuming no other grants on a per user basis) from being able to execute queries outside of the stored procedure/functions/etc that exist.
There are only a couple ways to do this. OMG Ponies has the best answer: don't allow direct sql statements against your database and instead leverage the tools and security sql server can provide.
An alternative way would be to add an additional tier which all queries would have to go through. In short you'd pass all queries (SOA architecture) to a new app which would evaluate the query for passing on to sql server. I've seen exactly one company do this in reaction to sql injection issues their site had.
Of course, this is a horrible way of doing things because SQL injection is only one potential problem.
Beyond SQL Injection, you also have issues of what happens when the site itself is cracked. Once you can write a new page to a web server it becomes trivial to pass any query you want to the associated database server. This would easily bypass any code level thing you could put in place. And it would allow the attacker to just write select * from ... or truncate table ... Heck, an internal person could potentially just directly connect to the sql server using the sites credentials and run any query they wanted.
The point is, if you leverage the security built into sql server to prevent direct table access then you can control through stored procedures the full range of actions availble to anyone attempting to connect to the server.
And how do you want to check for that? Queries sometimes have constant values that would just as easy be added to the query. For instance, I have a database that is prepared to be multi lingual, but not all code is, so my query looks like this:
SELECT NAME FROM SOMETABLE WHERE ID = :ID AND LANGUAGEID = 1
The ID is a parameter, but the language id isn't. Should this query be blocked?
You ask to block queries that don't use named parameters. That can be easily enforced. Just block any query that doesn't specify any parameters. You can do this in your application layer. But it will be hard to block queries like the one above, where one value is a parameter and the other one isn't. You'll need to parse that query to detect it, and it will be hard too.
I don't think sql server has any built in features to do this.
I often find myself writing one off queries to either answer someone's question or trouble shoot something and I would like to be able to quickly expose the on demand refreshable results of the query graphically so that I can share these results to others without having to go through the process of creating an SSRS report and publishing it to a reporting services server.
I have thought about using excel to do this or maybe running a local SSRS server but both of these options are still labor intensive and I cannot justify the time it would take to do these since no one has officially requested that I turn this data into a report.
The way I see it the business I work for has invested money in me creating these queries that often return potentially useful data that other people in the organization might want but since it isn't exposed in any way and I don't know that this data is something they want and they may not even realize they want this data, the potential value of the query is not realized. I want to increase the company's return on investment on all these one off queries that I and other developers write by exposing their results graphically so that they can be browsed by others and then potentially turned into more formalized SSRS reports if they provide enough value to justify the development of the report.
What is the fastest way for me to take a query and turn it into a refreshable graph of the results set?
Why dont you simply use what you may already have. Excel...you can import data via an ODBC / Oracle / SQL Connection. Get Data..and bam you can run the query and format it right in the spreadsheet and provide sorting etc. All you need to supply is the database name and user name and password to connect to the db.
JonH is right regarding Excel's built in ODBC support, but I have had tons of trouble with this. In my case, the ODBC connection required the client software to be installed so that it could use the encryption methods, etc. Also, even if that were not the case, the user (I believe) would still have to manually install and set up an ODBC connection.
Now if you just want something on your machine to do the queries and refresh them, JohH's solution is great and my caveats are probably irrelavent. But if you want other users to have access, you should consider having a middle-man app (basically a PHP script, assuming a web server is an option for you), that does a query, transforms the results into XML, and outputs it as "report-xyz.xml". You can then point anybody running a newer version of Excel to that address and they can very easily import the data into Excel with no overhead. (basically a kind of web service).
Keep in mind, I don't think you should have a web script that will allow users to make queries to your Database server! You would have some admin page where you make pass the query in and a new xml file with the results gets made. So my idea is also based on the idea that you want to run the same queries over and over without any specifics passed in. (if that were the case, I'd look into just finding a pre-built web services bridge for your database that already has security features built in. Then you could have users make the limited changes allowed.)