I'm not sure whether my SQL code and practise here is any good, so hopefully someone could enlighten me. In order to try and separate my DAL from the Business layer, I'm not using an SQLDataSource on the page. Instead, I've created a gridview to display the results and called an SQL command to retrieve results. I have the following SQL command:
string CommandText = "SELECT User.FName + User.Surname, Product.Name, Product.Quantity, Product.Price FROM User, Products WHERE Product.UserID = User.UserID";
The results are then loaded into a datareader and bound to the gridview control. This works fine. However, is the SQL statement inefficient? I've noticed some SQL statements have square brackets around each field, but when I try and put it around my fields, no results are displayed.
I'm also trying to merge the firstname and surname into one column, with a space between them, but the above doesn't put a space between them, and I can't seem to add a space in the SQL statement.
Finally, this all occurs in the code-behind of the shopping-cart page. However, is it insecure to have the connectionstring and above SQL statement in the codebehind? My connectionstring is encrypted within the web.config file and is called via the Configuration API.
Thanks for any help.
Firstly, using square brackets is optional in most cases (IIRC, there are very few instances where they are actually necessary, such as using keywords in the statement). Square brackets go around each identifier, for example,
SELECT [Server_Name].[Database_Name].[Table_Name].[Field_Name], ...
Secondly, to add a space, you can use SELECT User.FName + ' ' + User.Surname. You also might want to alias it - SELECT User.FName + ' ' + User.Surname AS [name]
Thirdly, keep the connection string in the web.config and encrypt it using a key.
Finally, you may want to consider introducing a data access layer into the project that can return objects from your datasource (might be worth having a look at NHibernate, LINQ to SQL or Entity Framework for this). You can then bind a collection of objects to your GridView.
Long time no SQL usage, but I don't see a problem with your query, as long as the database is designed well. To concatenate two string columns use something like this:
User.FName + ' ' + User.Surname AS UserName
Simply add a space between two strings.
As for security concerns: all other people can see is a rendered web page. If you don't expose connection string nor queries in the rendered HTML/JS code (like in comments etc.), you should not worry. The connection string stored in web.config and database structure visible in queries in server code are safe as long as the server is safe.
Try this:
string CommandText = "SELECT
User.FName + ' ' + User.Surname AS Fullname,
Product.Name,
Product.Quantity,
ProductDetail.Price
FROM
User, Products
WHERE
Product.UserID = User.UserID";
Best wishes,
Fabian
Related
I've been tasked with creating an application that allows users the ability to enter data into a web form that will be saved and then eventually used to populate pdf form fields.
I'm having trouble trying to think of a good way to store the field values in a database as the forms will be dynamic (based on pdf fields).
In the app itself I will pass data around in a hash table (fieldname, fieldvalue) but I don't know the best way to convert the hash to db values.
I'm using MS SQL server 2000 and asp.net webforms. Has anyone worked on something similar?
Have you considered using a document database here? This is just the sort of problem they solve alot better than traditional RDBMS solutions. Personally, I'm a big fan of RavenDb. Another pretty decent option is CouchDb. I'd avoid MongoDb as it really isn't a safe place for data in it's current implementation.
Even if you can't use a document database, you can make SQL pretend to be one by setting up your tables to have some metadata in traditional columns with a payload field that is serialized XML or json. This will let you search on metadata while staying out of EAV-land. EAV-land is a horrible place to be.
UPDATE
I'm not sure if a good guide exists, but the concept is pretty simple. The basic idea is to break out the parts you want to query on into "normal" columns in a table -- this lets you query in standard manners. When you find the record(s) you want, you can then grab the CLOB and deserialize it as appropriate. In your case you would have a table that looked something like:
SurveyAnswers
Id INT IDENTITY
FormId INT
SubmittedBy VARCHAR(255)
SubmittedAt DATETIME
FormData TEXT
A few protips:
a) use a text based serialization routine. Gives you a fighting chance to fix data errors and really helps debugging.
b) For SQL 2000, you might want to consider breaking the CLOB (TEXT field holding your payload data) into a separate table. Its been a long time since I used SQL 2000, but my recollection is using TEXT columns did bad things to tables.
The solution for what you're describing is called Entity Attribute Value (EAV) and this model can be a royal pain to deal with. So you should limit as much as possible your usage of this.
For example are there fields that are almost always in the forms (First Name, Last Name, Email etc) then you should put them in a table as fields.
The reason for this is because if you don't somebody sooner or later is going to realize that they have these names and emails and ask you to build this query
SELECT
Fname.value fname,
LName.Value lname,
email.Value email,
....
FROM
form f
INNER JOIN formFields fname
ON f.FormId = ff.FormID
and AttributeName = 'fname'
INNER JOIN formFields lname
ON f.FormId = ff.FormID
and AttributeName = 'lname'
INNER JOIN formFields email
ON f.FormId = ff.FormID
and AttributeName = 'email'
....
when you could have written this
SELECT
common.fname,
common.lname,
common.email,
....
FROM
form f
INNER JOIN common c
on f.FormId = c.FormId
Also get off of SQL 2000 as soon as you can because you're going to really miss the UNPIVOT clause
Its also probably not a bad idea to look at previous SO EAV questions to give you an idea of problems that people have encountered in the past
I'd suggest mirroring the same structure:
Form
-----
form_id
User
created
FormField
-------
formField_id
form_id
name
value
I've a textbox that I save to a SQL Database using ASP.NET C#.
The problem is using quotes, for instance with words like he's and it's. When you save it, I get an SQL error.
From experience to get around the issue, I use to use replace command to find all occurances of quotes and replace them with another character. Then if I was to read the database and the text that was previously saved, I'd replace again.
Is there a better of doing this? Or do you still have to use this 'old' way.
Use parametrized queries.
Using replace is dangerous and can lead to unintentional SQL injection vulnerabilities.
Always use parameterized queries. Never concatenate strings together (with un-sanitised input information) to create SQL on the fly. You run the risk of being vulnerable to SQL-injection attacks.
Read the following guide carefully:
http://www.csharp-station.com/Tutorials/AdoDotNet/Lesson06.aspx
And when you understand the following comic strip, you are ready to code:
http://xkcd.com/327/
As the other answers point out, the correct answer here is to use parameterized queries.
However, this is sometimes not possible. In these cases, you're better off doubling the quotes:
String str = "he's";
str = str.Replace("'", "''");
There's two ways to get around this issue:
Use a parameterised query, e.g. in http://www.csharp-station.com/Tutorials/AdoDotNet/Lesson06.aspx - this will also help avoid basic SQL injection if you're worried about that
Create 2 new functions, one to double up every apostrophe, so that it's saved into the database correctly, and another to remove extra apostrophes when retrieving data from the database.
I would recommend the first method as it's a lot cleaner (and safer) in my opinion. If you're using C# for your ASP.NET you can do things like in my below example:
string clientName = "Test client";
SqlCommand sqlCommand = new SqlCommand("SELECT COUNT(*) FROM Client WHERE UPPER(ClientName) = UPPER(#ClientName)", connection);
sqlCommand.Parameters.AddWithValue("#ClientName", clientName);
I have been given a small project by the company I have applied for. They want a small application using asp.net GridView, FormView and an ObjectDataSource with a DataSet (xsd) file. I have been doing 3-tier applications but in a different way, I have my DataAccess layer as a c sharp file with methods accepting params and returning datatables etc. My business layer is another class with static methods returning business objects and collections making use of the DAL class. Now this ObjectDataSource is sth i did not really like, its generating some code that i can't even see where?
I could make the application work upto some point(90%). The other 10% is what my question about. I need to make a search by name functionality. There are two ObjectDataSources 1 and 2. ObjectDatasource1 just gets every record from the table on the first load. When search button cliked I set the datasource of gridview to the second ObjectDataSource which has a method called GetDataByNameSearch that is supposed to accept a parameter (all defined by wizzzardz) and parameter source is control (TextBox.Text). While my FormView works fine where it gets its parameter from QueryString, this search returns nothing. Search statement is as follows:
SELECT Birthday, CreatedAt, ID, Name, Surname
FROM Users
WHERE (Name LIKE '%#name%') OR
(Surname LIKE '%#name%')
Any idea about how these ObjectDataSources are supposed to be used, and make life easier(!)
Without code samples its hard to tell, but I did notice that your use of SQL parameters is a bit unusual.
You have:
SELECT Birthday, CreatedAt, ID, Name, Surname
FROM Users
WHERE (Name LIKE '%#name%') OR (Surname LIKE '%#name%')
I'm not sure if SQL '#' parameters will work when there are speechmarks around them. I think the above example will just result in the literal string '%#name%' being used in the query, which is why you might be getting no results.
SQL Parameters are usually used like this:
SELECT Birthday, CreatedAt, ID, Name, Surname
FROM Users
WHERE (Name LIKE #name) OR (Surname LIKE #name)
... but of course then you will lose the '%' wildcards. You might be able to add them directly into the parameter strings before they are passed to the query. If that is not possible, maybe try this version:
SELECT Birthday, CreatedAt, ID, Name, Surname
FROM Users
WHERE (Name LIKE '%' + #name + '%') OR (Surname LIKE '%' + #name + '%')
I've got a search box that users can type terms into. I have a table setup with fulltext searching on a string column. Lets say a user types this: "word, office, microsoft" and clicks "search".
Is this the best way to deal with multiple search terms?
(pseudocode)
foreach (string searchWord in searchTerms){
select col1 from myTable where contains(fts_column, ‘searchWord’)
}
Is there a way of including the search terms in the sql and not iterating? I'm trying to reduce the amount of calls to the sql server.
FREETEXT might work for you. It will separate the string into individual words based on word boundaries (word-breaking). Then you'd only have a single SQL call.
MSDN -- FREETEXT
Well you could just build your SQL Query Dynamically...
string [] searchWords = searchTerm.Split(",");
string SQL = "SELECT col1 FROM myTable WHERE 1=2";
foreach (string word in searchWords)
{
SQL = string.Format("{0} OR contains(fts_column, '{1}')", SQL, word);
}
//EXEC SQL...
Obviously this comes with the usual warnings/disclaimers about SQL Injection etc... but the principal is that you would dynamically build up all your clauses and apply them in one query.
Depending on how your interacting with your DB, it might be feasible for you to pass the entire un-split search term into a SPROC and then split & build dynamic SQL inside the stored procedure.
You could do it similar to what you have there: just parse the search terms based on delimiter, and then make a call on each, joining the results together. Alternatively, you can do multiple CONTAINS:
SELECT Name FROM Products WHERE CONTAINS(Name, #Param1) OR CONTAINS(Name, #Param2) etc.
Maybe try both and see which is faster in your environment.
I use this class for Normalizing SQL Server Full-text Search Conditions
I've been preaching both to my colleagues and here on SO about the goodness of using parameters in SQL queries, especially in .NET applications. I've even gone so far as to promise them as giving immunity against SQL injection attacks.
But I'm starting to wonder if this really is true. Are there any known SQL injection attacks that will be successfull against a parameterized query? Can you for example send a string that causes a buffer overflow on the server?
There are of course other considerations to make to ensure that a web application is safe (like sanitizing user input and all that stuff) but now I am thinking of SQL injections. I'm especially interested in attacks against MsSQL 2005 and 2008 since they are my primary databases, but all databases are interesting.
Edit: To clarify what I mean by parameters and parameterized queries. By using parameters I mean using "variables" instead of building the sql query in a string.
So instead of doing this:
SELECT * FROM Table WHERE Name = 'a name'
We do this:
SELECT * FROM Table WHERE Name = #Name
and then set the value of the #Name parameter on the query / command object.
Placeholders are enough to prevent injections. You might still be open to buffer overflows, but that is a completely different flavor of attack from an SQL injection (the attack vector would not be SQL syntax but binary). Since the parameters passed will all be escaped properly, there isn't any way for an attacker to pass data that will be treated like "live" SQL.
You can't use functions inside placeholders, and you can't use placeholders as column or table names, because they are escaped and quoted as string literals.
However, if you use parameters as part of a string concatenation inside your dynamic query, you are still vulnerable to injection, because your strings will not be escaped but will be literal. Using other types for parameters (such as integer) is safe.
That said, if you're using use input to set the value of something like security_level, then someone could just make themselves administrators in your system and have a free-for-all. But that's just basic input validation, and has nothing to do with SQL injection.
No, there is still risk of SQL injection any time you interpolate unvalidated data into an SQL query.
Query parameters help to avoid this risk by separating literal values from the SQL syntax.
'SELECT * FROM mytable WHERE colname = ?'
That's fine, but there are other purposes of interpolating data into a dynamic SQL query that cannot use query parameters, because it's not an SQL value but instead a table name, column name, expression, or some other syntax.
'SELECT * FROM ' + #tablename + ' WHERE colname IN (' + #comma_list + ')'
' ORDER BY ' + #colname'
It doesn't matter whether you're using stored procedures or executing dynamic SQL queries directly from application code. The risk is still there.
The remedy in these cases is to employ FIEO as needed:
Filter Input: validate that the data look like legitimate integers, table names, column names, etc. before you interpolate them.
Escape Output: in this case "output" means putting data into a SQL query. We use functions to transform variables used as string literals in an SQL expression, so that quote marks and other special characters inside the string are escaped. We should also use functions to transform variables that would be used as table names, column names, etc. As for other syntax, like writing whole SQL expressions dynamically, that's a more complex problem.
There seems to be some confusion in this thread about the definition of a "parameterised query".
SQL such as a stored proc that accepts parameters.
SQL that is called using the DBMS Parameters collection.
Given the former definition, many of the links show working attacks.
But the "normal" definition is the latter one. Given that definition, I don't know of any SQL injection attack that will work. That doesn't mean that there isn't one, but I have yet to see it.
From the comments, I'm not expressing myself clearly enough, so here's an example that will hopefully be clearer:
This approach is open to SQL injection
exec dbo.MyStoredProc 'DodgyText'
This approach isn't open to SQL injection
using (SqlCommand cmd = new SqlCommand("dbo.MyStoredProc", testConnection))
{
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter newParam = new SqlParameter(paramName, SqlDbType.Varchar);
newParam.Value = "DodgyText";
.....
cmd.Parameters.Add(newParam);
.....
cmd.ExecuteNonQuery();
}
any sql parameter of string type (varchar, nvarchar, etc) that is used to construct a dynamic query is still vulnerable
otherwise the parameter type conversion (e.g. to int, decimal, date, etc.) should eliminate any attempt to inject sql via the parameter
EDIT: an example, where parameter #p1 is intended to be a table name
create procedure dbo.uspBeAfraidBeVeryAfraid ( #p1 varchar(64) )
AS
SET NOCOUNT ON
declare #sql varchar(512)
set #sql = 'select * from ' + #p1
exec(#sql)
GO
If #p1 is selected from a drop-down list it is a potential sql-injection attack vector;
If #p1 is formulated programmatically w/out the ability of the user to intervene then it is not a potential sql-injection attack vector
A buffer overflow is not SQL injection.
Parametrized queries guarantee you are safe against SQL injection. They don't guarantee there aren't possible exploits in the form of bugs in your SQL server, but nothing will guarantee that.
Your data is not safe if you use dynamic sql in any way shape or form because the permissions must be at the table level. Yes you have limited the type and amount of injection attack from that particular query, but not limited the access a user can get if he or she finds a way into the system and you are completely vunerable to internal users accessing what they shouldn't in order to commit fraud or steal personal information to sell. Dynamic SQL of any type is a dangerous practice. If you use non-dynamic stored procs, you can set permissions at the procesdure level and no user can do anything except what is defined by the procs (except system admins of course).
It is possible for a stored proc to be vulnerable to special types of SQL injection via overflow/truncation, see: Injection Enabled by Data Truncation here:
http://msdn.microsoft.com/en-us/library/ms161953.aspx
Just remember that with parameters you can easily store the string, or say username if you don't have any policies, "); drop table users; --"
This in itself won't cause any harm, but you better know where and how that date is used further on in your application (e.g. stored in a cookie, retrieved later on to do other stuff.
You can run dynamic sql as example
DECLARE #SQL NVARCHAR(4000);
DECLARE #ParameterDefinition NVARCHAR(4000);
SELECT #ParameterDefinition = '#date varchar(10)'
SET #SQL='Select CAST(#date AS DATETIME) Date'
EXEC sp_executeSQL #SQL,#ParameterDefinition,#date='04/15/2011'