I'm currently making a website using PHP and MYSQLi. And I've been read a lot about SQL injection. As answered on other questions from StackExchange, 2 ways of prevent it is by using prepared statement and escaping string. Since I'm not able to do prepared statement (I've tried to make it based on tutorials and videos but can't make it work) so I chose another way(escaping string). My question is, if I change permission for user at my SQL login page, to only able to do 'SELECT' query. Will it able to give me extra security measure to prevent user from DROP, ALTER, etc on my database. Because my website :-
Not require any user to register.
The only text field link to my query is for full text search function (which only use SELECT for the query and I have mysqli escape string on this text field).
It's always a good idea to give your application's database login only the permissions it needs. If it doesn't need to do inserts or updates, don't give it insert or update permission.
However, attackers may still be able to exploit SQL injection vulnerabilities to read unauthorized data using select statements, so you still need to protect your queries against that.
Unfortunately, you get it all wrong (which is no wonder, given all the tons of rubbish posted in Stack Overflow).
prevent it by escaping string.
It doesn't prevent injections
Will it able to give me extra security measure
No.
I'm not able to do prepared statement
Consider hiring a programmer then. Think of your customers. And your business, after all. If you, say, want to be a bus driver, you have to buy a bus - not making it out of wood logs and clay, endangering your passengers. Exactly the same thing here - if you need a site to sell your goods - buy a site, instead of making it yourself
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!
I have an application in which I'd like to accept a user supplied SQL query from a front-end query builder (http://querybuilder.js.org/). That query eventually needs to make it's way to running in a postgres database to return a subset of data.
The query builder linked above can export SQL or a mongo query. I imagine using the mongo query is relatively safe, since I can add to it simply on the server:
query.owner_of_document = userId
to limit results (to documents owned by the user).
Whereas the SQL statement could potentially be hijacked in an injection attack if someone attempts to store a malicious string of SQL for execution.
Is directly accepting SQL from a client bad practice? How can I ensure the supplied SQL is safe?
Thanks!
Why do you need to accept an entire SQL statement?
Can you accept only parameters and then run a pre defined query?
There are loads of questions/answers on SO relating to SQL injection and using parameters is a first step in avoiding injection attacks, such as "Are Parameters really enough to prevent Sql injections?"
But I think this answer to a different question sums things up well:
Don't try to do security yourself. Use whatever trusted, industry
standard library there is available for what you're trying to do,
rather than trying to do it yourself. Whatever assumptions you make
about security, might be incorrect. As secure as your own approach may
look ... there's a risk you're overlooking something and do you
really want to take that chance when it comes to security?
Perhaps it may sound strange but I was told that SQL injection attacks
can be classified as:
passive and active
Passive SQLi:
it is related to SQL statement such:
SELECT,UNION,GROUP BY,LOAD,HAVING EXECUTE, BEGIN, DECLARE...etc
Active SQLi:
it is supposed to be more dangerous since it involves modifying the DBMS through statements like: UPDATE,DELETE,INSERT ..etc so
I haven't yet found anything about it in terms of white papers, study material and so on.
OWASP defines passive and active sql injections here
SQL Injection is classified in the following two categories, depending
on the exposure of database information (passive) or the alteration of
database information (active).
Both are problematic, and if you have one you probably have the other. The problem with active is fairly obvious (someone is updating/creating/deleting your data in ways you didn't plan). Passive is just as dangerous though for you and your users though. Imagine if they get a list of usernames and passwords. These could be used to login legitamently to your website, or to other websites as most users reuse passwords on multiple sites.
SQL injection is simply adding undesired text to your queries.
You can group it as you wish, but it doesn't really matter, the simple thing is, your query doesn't do what you want or does not only what you want.
I've never heard of sql injection attacks being broken down into categories. As gdoron so eloquently put it, it doesn't matter.
However, looking at how you broke it down it almost makes sense. I'd change that classification slightly to be:
Passive:
Attack involving overriding the expected input in such a way as to bypass normal security controls. For example, let's say you have a page with a query string such as:
/accounts/edit.php?id=50
In this case, manually changing the id to 1 or 10 could potentially pull up a record the user does not have access to. Provided that the edit page doesn't perform additional checks to ensure the user has access.
Active:
Attack whereby sql statements are passed into input fields in order to cause the application to execute the new statement.
For example, putting ' or (1=1);drop table users;' into a login field. Some applications simply concatenate sql with unsanitized user input. This could allow an attacker to bypass security controls or even send DDL statements to the database server.
I wouldn't say that SQL injection involving DELETE is necessarily "worse" than SQL injection involving SELECT. It's true one can modify data and the other doesn't.
But a lot of scary SQL injection is perpetrated solely to read data that is supposed to be restricted, e.g. stealing credit card numbers.
Usually the terminology around SQL injection has to do with the methods of attack, such as "blind SQL injection," "union-based SQL injection," etc.
If you want to read a mighty book that covers the subject very well, try SQL Injection Attacks and Defense by Justin Clarke et. al.
Because SQL Injection is a technique used to ATTACK a website, wether it is passive or active is of inconsequence as many of the others members have said already.
No the TERMS you use in the first paragraph are PASSIVE is incorrect,
Execute is not passive, its active... its Executing (something or other)
And even a passive term such as SELECT when used with DropTable can cause you to lose data too!
So you would still insist on calling it passive?
When its ACTIVELY dropping a table?
A good source of further information is wikipedia.
http://en.wikipedia.org/wiki/SQL_injection
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'm exposing a more or less public API that allows the user to query datasets from a database. Since the user will need to filter out specific datasets I'm tempted to accept the WHERE-part of the SELECT statement as an API parameter. Thus the user could perform queries as complex as she'd like without worrying about a cluttered API interface.
I'm aware of the fact that I would have to catch SQL-injection attempts.
Do you think that this would circumvent the purpose of an API wrapping a database too much or would you consider this a sane approach?
In general, I'd recommend against letting them embed actual sql in their requests
You can allow them to submit where conditions in their request pretty easily:
<where>
<condition "field"="name" "operator"="equal" "value"="Fred"/>
</where>
or something similar.
The value of doing this is muli-fold:
You parse each condition and make sure they're correct before running them
You can create 'fake' fields, such as "full_name" that may not exist.
You can limit the columns they can put conditions on
You can isolate the users from actual changes in your underlying database.
I think the last point is actually most important. The day will come when you'll need to make changes to the underlying schema of the database. Eventually, it will happen. At that point you'll appreciate having some 'translation' layer between what the users send in and the queries. It will allow you to isolate the users from actual changes in the underlying database.
The API should present an 'abstracted' version of the actual tables themselves that meet the users needs and isolate them from changes to the actual underlying database.
I would recommend limitting your users account by modifying the permissions to only allow the user to SELECT from tables. Don't allow updating, inserting, or deleting recordsets. Lock down the user as much as possibile, possibly at a table level.
If the WHERE clause is limited to only a few columns and the comparator is limited to >, = or < then perhaps you could just have the user pass in some extra parameters to represent columns and comparators. You then build the WHERE safely on your server side.
If this is too messy then by all means let them pass a full WHERE clause - it's not too hard to sanitise and if you combine that with running the query under a locked-down account (SELECT only), then any potential damage is limited.
Personally I would not want to allow users to be able to pass in SQL directly to my database, the risks are too great.
If you fail to catch all injection attempts you risk either data theft, someone just destroying your database or hijacking it for some other use that you really dont want.