ColdFusion Sanatize SQL - sql

I'm trying to loop over tableList and run a query for each table getting the count from each. Not all of the code is included but the problem is the cfqueryparam. When I run this code right now the error says "INVALID TABLE NAME". Here is what I am trying right now:
<cfloop list="#tableList#" index="t">
<cfquery name="getcount" datasource="erisnetselect">
SELECT COUNT(*) FROM <cfqueryparam value='AUDITOR.#t#' sqltype="VARCHAR">
</cfquery>
The problem is specifically this line:
SELECT COUNT(*) FROM <cfqueryparam value='AUDITOR.#t#' sqltype="VARCHAR">
I have also tried:
SELECT COUNT(*) FROM AUDITOR.<cfqueryparam value='#t#' sqltype="VARCHAR">
But I get the same error.
I think there might be a way to sanitize these table names before they hit the query but I'm not sure how to do it. If you need all of the code I can provide more but this is a huge page.

cfqueryparam is a value placeholder for a prepared statement. You cannot use value placeholders for table or column names because a prepared statement requires the query to be complete and valid before any values are put in. One of the design goals of prepared statements is to prevent malicious injection by separating query and values. The separation is achieved by sending the query without actual values first (value placeholders are usually indicated with a question mark ?), have the SQL server parse and understand it (query interpreter) and then wait for data to place into the prepared value slots. This also comes with a performance benefit, because the SQL server can reuse already interpreted queries while sending a plain string statement with query and values would always require parsing it again.
To solve your problem, you will have to sanitize the table names either by using the appropriate command builder/quoter (depends on the SQL vendor, check your JDBC driver) or validate the name manually.
If you have to go with the manual way, you should be conservative and only allow foolproof characters, such as alphabetic letters, digits, underscores and hyphens. Consider this:
<cfloop list="#tableList#" index="t">
<!--- make sure the table name only consists of alphabetic letters, digits, underscores and hyphens --->
<cfif not reFind("^[a-zA-Z0-9_-]+$", t)>
<cfthrow message='The specified table name, which is "#t#", contains illegal characters.'>
</cfif>
<cfquery name="getcount" datasource="erisnetselect">
SELECT COUNT(*) FROM AUDITOR.#t#
</cfquery>
...

Related

how to separate the parameters in the sql query and push it in to array to avoid sql injection

SELECT * FROM table1 WHERE year_month BETWEEN '2021-08' AND '2022-01';
update table2 set note_description = 'test #8:57am', patient_id = '5840', note_updated_by = '10000019', note_update_date = '2022-07-13 09:45:49' where note_id = '639'
now my backend queries can be attacked by sql injection so i want to avoid the sql injection
in the above queries I want to separate the parameters from queries and replace it with special characters so that I can avoid sql injection is there any package or anything to do it.
If you have received the SQL statement with the parameters already concatenated in, then this is the wrong place to fix your issue - there’s no way to safely parse the statement and separate out the parameters from the query.
You should find the place in the code where the parameters are concatenated into the Statement and leveraging Prepared Statements/Parameterized Queries to safely pass/bind the parameters.
If that’s not possible (for example because the code is structured to only pass along the statement) a less desirable alternative is to encode/enquote the parameters before concatenating them in, while ensuring they are all quoted in the statement. How you do that part will depend on the database / language being used.
I've seen one product that does this: pt-query-digest. It's a free tool that parses the MySQL query log, and produces reports of aggregate time spent running each query. To do this, it must establish a query "fingerprint" which allows it to group queries that are the same except for constant values. Like SELECT * FROM mytable WHERE id = 123 has the same fingerprint as SELECT * FROM mytable WHERE id = 456.
This means it must parse the queries and replace each constant value, like a numeric or string literal, with a placeholder ?. In cases of IN() predicates, it replaces the list of values with ?+. Also it reduces whitespace and removes comments.
It's a non-trivial amount of code, about 100 lines of Perl: https://github.com/percona/percona-toolkit/blob/3.x/lib/QueryRewriter.pm#L139-L248
In spite of this, the function is preceded by a comment that the developers acknowledge it is not perfect, and may miss some cases. Implementing a recursive-descent parser using regular expressions is not efficient or correct.
But this is probably not what you want to do anyway. You shouldn't be starting from a query with constant values and making them into a parameterized query. You should design parameterized queries yourself, as needed.
Not every constant value in an SQL query necessarily must be parameterized. Only the ones that aren't fixed values. That is, if you need to combine a variable from your client code into the SQL query string, and you can't guarantee that the variable is safe, then use a parameter. If a query has a constant value that is fixed (not interpolated from a variable), then it can remain in the query. If a query has a value that comes from a variable, but that variable is known to be safe, and never can be tainted by untrusted input, then it can remain in the query.
It's more reliable and economical for you to make these judgments. You know the code and the context much better than any automated system can.

Coldfusion query caching with arguments [duplicate]

When you use the cachedwithin attribute in a cfquery how does it store the query in memory. Does it store it by only the name you assign to the query? For example, if on my index page I cache a query for an hour and name it getPeople will a query with the same name on a different page (or the same page for that matter) use the cached results or does it use some better logic to decide if it is the same query?
Also, if there is a variable in your query does the cache take into account the value of the variable?
It's not only the name -- it's the exact query you're running.
<cfquery name="getPeople" cachedwithin=".5" ...>
select name from employee order by name
</cfquery>
If you invoke this same query anywhere else in your app, you'll get the cached version if it's within half a day of the first query. But these will hit the database for fresh data:
<!--- Different name, same SQL: A new cached query --->
<cfquery name="getEmployees" cachedwithin=".5" ...>
select name from employee order by name
</cfquery>
<!--- Different SQL, same name: Redefining the cached query --->
<!--- Note: As pointed out in comments, it's not really overwriting the old query
of the same name, but making a new one in the cache. The first one by the
same name is still in the cache, waiting for eviction. --->
<cfquery name="getPeople" cachedwithin=".5" ...>
select name from employee order by name desc
</cfquery>
And yes, it does take a variable into account. If you use cfqueryparam -- which you should be doing -- your database will cache the query plan, but even using cachedwithin, each query with a changed parameter will be treated as different from a query caching perspective. Note that this means if you use cachedwithin on a query that runs many times with different parameters, you'll be flooding your query cache with queries that have low cache hit rates.
From http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7fae.html
To use cached data, current query
must use same SQL statement, data
source, query name, user name,
password.
So those are the 'keys' that "decide if it is the same query"
variable? yes, as long as you use <cfqueryparam>

ColdFusion Query - Injection Protection

I ask this question with a bit of sheepishness because I should know the answer. Could someone be kind and explain if and how injection could occur in the following code?
<cfquery>
select * from tableName
where fieldName = '#value#'
</cfquery>
I'm specifically curious about injection attempts and other malicious input, not about best practices or input validation for handling "normal" user input. I see folks strongly advocating use of CFQueryParam, but don't think I see the point. If user input has been validated for consistency to the database schema (e.g. so that input must be numeric for numerical database fields), is there anything else gained by using CFQueryParam? What does <cfqueryparam CFSQLType = "CF_SQL_VARCHAR"> do that '#value#' doesn't do?
Update:
While this answers part of your question, Peter's response is better, in that it directly addresses your question of "Why use cfqueryparam, when CF automatically adds protection by escaping single quotes?". Answer: In short, because the latter does not always work. Bind variables do.
It says in the docs "escapes string variables in single-quotation
marks" but doesn't CF already "magically" do this in CF query tag when
you wrap evaluated variables in single quotes?
Yes, most versions automatically escape single quotes as a protection measure for those not using cfqueryparam. However, as Scott noted above, it is better to use cfqueryparam (ie bind variables) because they ensure parameters are not executed as sql commands. Bind variables work, even in cases where the automatic escaping does not, as Peter's answer demonstrates.
That said, sql injection protection is really just a side effect of using bind variables. The primary reason to use bind variables is performance. Bind variables encourage databases to re-use query plans, instead of creating a new plan every time your #parameters# change. That cuts down on compilation time, improving performance.
Cfqueryparam also has a number of other benefits:
Provides data type checking (length, value, type, ...)
Provides attributes that simplify handling of "lists" and null values
Performs data type checking before any sql is sent to the database, preventing wasted database calls
While it does not really apply to string columns, IMO another big reason to use it is accuracy. When you pass a quoted string to the database, you are relying on implicit conversion. Essentially you are leaving it up to the database to figure out how to best perform the comparison, and the results are not always what you were expecting. (Date strings are a prime example). You may end with inaccurate results, or sometimes slower queries, depending on how the database decides to execute the sql. Using cfqueryparam avoids those issues by eliminating the ambiguity.
doesn't CF already "magically" do this in CF query tag when you wrap evaluated variables in single quotes?
Yep, it'll convert ' to '' for you.
Now guess what SQL you get from this code:
<cfset value = "\'; DROP TABLE tableName -- " />
<cfquery>
select * from tableName
where fieldName = '#value#'
</cfquery>
The cfqueryparam tag works; using query params solves SQL injection.
Any custom written attempts at validating, sanitizing, or escaping (all separate things, btw) are, at best, only as good as the developer's knowledge of the database system the code is running against.
If the developer is unaware of other escape methods, or if the values are modified between validation/escaping and them being rendered into SQL, or even if the codebase is ported to another database system and seems to be fine, there's a chance of custom code breaking down.
When it comes to security, you don't want chances like that. So use cfqueryparam.
To answer the first part of your question, setting your #value# variable to the following:
someValue'; DELETE FROM tableName WHERE '1' = '1
would result in this query being executed:
<cfquery>
select * from tableName
where fieldName = 'someValue'; DELETE FROM tableName WHERE '1' = '1'
</cfquery>

SQL wildcard issue

I have a database which can be modified by our users through an interface. For one field (companyID) they should have the ability to place an asterisk in the string as a wildcard character.
For example, they can put in G378* to stand for any companyID starting with G378.
Now on my client program I'm providing a "full" companyID as a parameter:
SELECT * FROM table WHERE companyID = '" + myCompanyID + "'
But I have to check for the wildcard, is there anything I can add to my query to check for this. I'm not sure how to explain it but it's kinda backwards from what I'm used to. Can I modify the value I provide (the full companyID) to match the wildcard value from in the query itself??
I hope this maked sense.
Thanks!
EDIT: The user is not using SELECT. The user is only using INSERT or UPDATE and THEY are the ones placing the * in the field. My program is using SELECT and I only have the full companyID (no asterisk).
This is a classic SQL Injection target! You should be glad that you found it now.
Back to your problem, when users enter '*', replace it with '%', and use LIKE instead of = in your query.
For example, when end-users enter "US*123", run this query:
SELECT * FROM table WHERE companyID LIKE #companyIdTemplate
set #companyIdTemplate parameter to "US%123", and run the query.
I used .NET's # in the example, but query parameters are denoted in ways specific to your hosting language. For example, they become ? in Java. Check any DB programming tutorial on use of parameterized queries to find out how it's done in your system.
EDIT : If you would like to perform an insert based on a wildcard that specifies records in another table, you can do an insert-from-select, like this:
INSERT INTO CompanyNotes (CompanyId, Note)
SELECT c.companyId, #NoteText
FROM Company c
WHERE c.companyId LIKE 'G378%'
This will insert a record with the value of the #NoteText parameter into CompanyNotes table for each company with the ID matching "G378%".
in TSQL I would use replace and like. ie:
select * from table where companyid like replace(mycompanyid,'*','%');
This is somewhat implementation dependant and you did not mention which type of SQL you are dealing with. However, looking at MS SQL Server wildcards include % (for any number of characters) or _ (for a single character). Wildcards are only evaluated as wildcards when used with "like" and not an = comparison. But you can pass in a paramater that includes a wildcard and have it evaluated as a wildcard as long as you are using "like"

Why does a LIKE query in Access not return any records?

Is there any reason why
SELECT * FROM MyTable WHERE [_Items] LIKE '*SPI*'
does not return any records with OleDbAdapter.Fill(DataSet) or OleDbCommand.ExecuteReader()?
When I run the same SQL in MS Access directly, it returns the expected records. Also, in the same code, if I change the SQL to
SELECT * FROM MyTable
all records are returned.
Try changing LIKE to ALIKE and your wildcard characters from * to %.
The Access Database Engine (Jet, ACE, whatever) has two ANSI Query Modes which each use different wildcard characters for LIKE:
ANSI-89 Query Mode uses *
ANSI-92 Query Mode uses %
OLE DB always uses ANSI-92 Query Mode.
DAO always uses ANSI-89 Query Mode.
The Access UI can be set to use one or the other.
However, when using ALIKE keyword the wildcard character is always % regardless of ANSI Query Mode.
Consider a business rule that states a data element must consist of exactly eight numeric characters. Say I implemented the rule as follows:
CREATE TABLE MyStuff
(
ID CHAR(8) NOT NULL,
CHECK (ID NOT LIKE '%[!0-9]%')
);
It is inevitable that I would use % as the wildcard character because Access's CHAR data type and CHECK constraints can only be created in ANSI-92 Query Mode.
However, someone could access the database using DAO, which always uses ANS-89 Query Mode, and the % character would be considered a literal rather than a 'special' character, and the following code could be executed:
INSERT INTO MyStuff (ID) VALUES ('%[!0-9]%');
the insert would succeed and my data integrity would be shot :(
The same could be said by using LIKE and * in a Validation Rule created in ANSI-89 Query Mode and someone who connects using ADO, which always uses ANSI-92 Query Mode, and INSERTs a * character where a * character ought not to be.
As far as I know, there is no way of mandating which ANSI Query Mode is used to access one's Access database. Therefore, I think that all SQL should be coded to behave consistently regardless of ANSI Query Mode chosen by the user.
Note it is not too difficult to code for both using LIKE with the above example e.g.
CHECK (
ID NOT LIKE '%[!0-9]%'
AND ID NOT LIKE '*[!0-9]*'
)
...or indeed avoid wildcards completely e.g.
CHECK (ID LIKE '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]')
However, using ALIKE will result in less verbose code i.e. easier for the human reader and therefore easier to maintain.
Also, when the time comes to port to a SQL product that is compliant with SQL Standards, ALIKE ports well too i.e. transforming the ALIKE keyword to LIKE is all that is required. When parsing a given SQL predicate, it is far, far easier to locate the one LIKE keyword in than it is to find all the multiple instances of the * character in text literals. Remember that "portable" does not mean "code will run 'as is'"; rather, it is a measure of how easy it is to move code between platforms (and bear in mind that moving between versions of the same product is a port e.g. Jet 4.0 to ACE is a port because user level security no longer functions, DECIMAL values sort differently, etc).
Change your * to % as % is the wildcard search when using OLE DB.
SELECT * FROM MyTable WHERE [_Items] LIKE '%SPI%'
Try converting your wildcard chars (*) to %
This should sort the issue out.
Jeez, this works!
Thanks a lot.
I just had to replace not like criteria to not alike criteria.
I'm sharing my "story" to help others find this post easier and save them from a two hours search.
Although I've linked the Excel 95-97 xls files to the Access 2010 database, and ran create table and insert into queries to import all data into a database, for some strange reason, the select query couldn't find the strings I've typed.
I tried not like "something" and not like "%something%" with no success - simply didn't work.
L