in standard Ajax, where
and order by
SQL clauses are provided by the program (not user), eg
var url = ".select?dd=emp&where="+escape("emp_tp='abc' and hire_dt<current_date-'2 years' and super_emp_id is distinct from emp_id")
answered on the server by
$where = (isset($_GET['where'])) ? pureClause($_GET['where']) : null;
$order = (isset($_GET['order'])) ? pureClause($_GET['order']) : null;
...
$query = $query.(($where)?" where $where":'').(($order)?" order by $order":'');
the question is what should function pureClause
look like?
right now pureClause
simply raises error if any of the following exist:
; select insert update delete drop create truncate
if other injection causes query failure, that's fine, as long as data undamaged.
to me this seems adequate, but in my heart, I know I'm wrong.
Clarifications:
Lastly, consider the where clause
emp_tp='abc' and hire_dt=current_dt-'2 years' and super_emp_id is distinct from emp_id
how many placeholders here? this needs to be parsed correctly before being fed into a prepared statement with placeholders, right? or am I completely missing the boat?
Primary facts:
Solution:
for SELECTS, where the random SQL can be a problem: since it's too hard to protect the database, let the database protect itself! have different users have different roles / permissions. use a read-only user for selects. for normal SQL, this guarantees no DML from these statements.
best practices: four db user accesses
developer
, do everything (never use as connection in web app)dml
- can select / dml on almost everything (must use for dml)read
- can select (use for all selects, whether prepared or text)login
- can only execute login/password functions (used in login process)password protection:
dml
and read
may not access password data, either through select or dmllogin
should access password data only through protected functions, eg,function login( username, password ) - returns user_id function set_password( usr_id, password ) - sets password
login
may run the login()
and set_password()
functionslogin
may need sql access to password columnspassword
column may be protected itself; if not, then should be moved out of the user
table into its own secure tablesetting this up in mysql
, using the administrator tool, took about 30 minutes, including time to write the login functions and split out the password column.
The only sure way to prevent SQL Injection attacks is input validation and parametrized queries including prepared statements. The application code should never use the input directly. The developer must sanitize all input, not only web form inputs such as login forms.
Wikipedia says: Prepared statements are resilient against SQL injection, because parameter values, which are transmitted later using a different protocol, need not be correctly escaped. If the original statement template is not derived from external input, SQL injection cannot occur.
Data sanitization means that you remove all dangerous characters from an input string before passing it to the SQL engine. This is not the best defense against SQL injection, it is better to use prepared statements and never create SQL statements but string + operations.
What you are doing is the very definition of sql injection and cannot be sanitized. You cannot pass in a WHERE
clause in a safe fashion period end of story. You must build this part of the query on the server side. The fact that you didn't recognize this means you MUST read more about sql injection, clearly asking StackOverflow is an insecure approach to this problem. The fear is that you may never learn the fundamentals of this vulnerability.
$order
can be done in a secure way with a white list. For example:
if(in_array($_GET['order'],$list_of_rows)){
$order=$_GET['order'];
}
If you are passing in a table name or column name make sure you check it against a white list, or this will be sql injection.
Got it! Routing all of these queries through a database user (connection) who has only been granted SELECT privileges on the database!
Attempted DML will choke. This does not prevent DoS attacks (lots of ways to do that!), but does protect the data. Nor does the make for secure queries, like login. But for client generated WHERE and ORDER, with the goal of preventing DML, this should work just fine.
Ten/fifteen years ago always set up different users for different roles, but with app layer etc etc got out of the habit. It's probably a good idea to re-invest in those principles.
Unless hear differently will mark this as correct answer - it satisfies all criteria, howbeit it dodges the theoretically impossible challenge fo writing a sanitizer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With