views:

211

answers:

5

I am using php, mysql with smarty and I places where users can put comments and etc. I've already escaped characters before inserting into database for SQL Injection. What else do I need to do?

A: 

The best way to prevent SQL injection is simply not to use dynamic SQL that accepts user input. Instead, pass the input in as parameters; that way it will be strongly typed and can't inject code.

tloflin
Not relevant to the question
Joe Philllips
I consider it entirely relevant, since shahinkian is looking to make their code more secure but admits to using a method that, to be polite, is not a best practice.
Steven Sudit
Ok, I misread his question. Edit your answer so I can change my downvote.
Joe Philllips
@d03boy, heh, don't worry about it. It really was only a tangent remark, anyway.
tloflin
+1  A: 

In regards to SQL Injection, escaping is not enough - you should use data access libraries where possible and parameterized queries.

For XSS (cross site scripting), start with html encoding outputted data. Again, anti XSS libraries are your friend.

One current approach is to only allow a very limited number of tags in and sanitize those in the process (whitelist + cleanup).

Oded
Would http://www.ricocheting.com/code/php/mysql-database-class-wrapper work?
jsd911
@shahinkian - Looks like a good one to use for SQL injection protection.
Oded
@Oded: I would suggest using a whitelist strategy and non-HTML, such as BBCode.
Steven Sudit
Don't scare people unnecessarily. When done consistently, escaping is definitely *enough* to prevent SQL injection. It's just ugly.
Thorarin
@Thorarin - So, building a SQL string from user input is not a problem, so long as you escape it?
Oded
@Oded: normally the user input goes into parts of the query that expect a constant of some kind, surrounded by single quotes. In that case, escaping is technically enough. If you were planning any "enter your SQL statement here" type forms, then no :)
Thorarin
@Thorarin: I would strongly recommend that we not depend upon escaping. You can argue that "when done consistently", it's enough, but it's not always done consistently, and even then, it's not always enough. (For example, you can't escape out ostensibly numeric values, nor can you reliably avoid all edge cases, such as embedded NULs.)
Steven Sudit
@Steven: Supposedly numeric variables can be put in quotes and escaped (yes, ugly). Edge cases are handled fine by `mysql_real_escape_string`. As it is, all the usual MySQL APIs commonly available in PHP suck bigtime. There are libraries that help with that, but most of them do exactly what you're telling people not to do :)
Thorarin
I think there may be some issue with converting numeric values to character values. At least with MSSQL, it can effect if an index can be used (now wrong type) or give cast exceptions in some cases. Personally, I'd always prefer to put the responsibility of parametrization on a library (such as a db access library) which _many_ people use compared to something that I'm just coming up with .
Eric Tuttleman
@Steven Sudit: Can you explain this more perhaps with examples: "you can't escape out ostensibly numeric values, nor can you reliably avoid all edge cases, such as embedded NULs.) ">
jsd911
@Shahin: I'd rather not write a manual for how to exploit the weaknesses of escaping, so I'm going to stick to generalizations that will befuddle script kiddies. Consider that a string that you think contains only a numeric value could also have SQL code mixed in. Consider also that the different systems handle null termination of string differently, so some will stop at the NUL and others will not. If this doesn't make the problem immediately obvious, all the more reason to stick to parameter binding instead of escaping.
Steven Sudit
@Thorarin: I won't speak of PHP, but languages generally have a DB API that binds directly to variables and avoids all encoding. I would recommend using those instead. And if PHP lacks them, all the more reason not to use PHP.
Steven Sudit
@Steven: Tell me about it. PHP does support them, more or less. It only supports *named* parameters using PDO, but anyway... I don't use PHP if I can avoid it :)
Thorarin
@Thorarin: PHP is very quick and dirty, but especially the latter, so I concur. It's possible to write good PHP code, but not common.
Steven Sudit
+1  A: 

You'll want to make sure people can't post JavaScript code or scary HTML in their comments. I suggest you disallow anything but very basic markup.

If comments are not supposed to contain any markup, doing a

echo htmlspecialchars($commentText);

should suffice, but it's very crude. Better would be to sanitize all input before even putting it in your database. The PHP strip_tags() function could get you started.

If you want to allow HTML comments, but be safe, you could give HTML Purifier a go.

Thorarin
I don't think you should ever remove user data without notifying them. Just error and say it's not allowed
Joe Philllips
@d03boy: I partially agree, but you can use those same functions to do that. Sanitize the input and compare to the original input. If it's different, show an error message.
Thorarin
+5  A: 

XSS is mostly about the HTML-escaping(*). Any time you take a string of plain text and put it into an HTML page, whether that text is from the database, directly from user input, from a file, or from somewhere else entirely, you need to escape it.

The minimal HTML escape is to convert all the & symbols to &amp; and all the < symbols to &lt;. When you're putting something into an attribute value you would also need to escape the quote character being used to delimit the attribute, usually " to &quot;. It does no harm to always escape both quotes (&quot; and the single quote apostrophe &#39;), and some people also escape > to &gt;, though this is only necessary for one corner case in XHTML.

Any good web-oriented language should provide a function to do this for you. For example in PHP it's htmlspecialchars():

<p> Hello, <?php htmlspecialchars($name); ?>! </p>

and in Smarty templates it's the escape modifier:

<p> Hello, {$name|escape:'html'}! </p>

really since HTML-escaping is what you want 95% of the time (it's relatively rare to want to allow raw HTML markup to be included), this should have been the default. Newer templating languages have learned that making HTML-escaping opt-in is a huge mistake that causes endless XSS holes, so HTML-escape by default.

You can make Smarty behave like this by changing the default modifiers to html. (Don't use htmlall as they suggest there unless you really know what you're doing, or it'll likely screw up all your non-ASCII characters.)

Whatever you do, don't fall into the common PHP mistake of HTML-escaping or “sanitising” for HTML on the input, before it gets processed or put in the database. This is the wrong place to be performing an output-stage encoding and will give you all sort of problems. If you want to validate your input to make sure it's what the particular application expects, then fine, but weeding out or escaping “special” characters at this stage is inappropriate.

*: Other aspects of XSS are present when (a) you actually want to allow users to post HTML, in which case you have to whittle it down to acceptable elements and attributes, which is a complicated process usually done by a library like HTML Purifier, and even then there have been holes. Alternative, simpler markup schemes may help. And (b) when you allow users to upload files, which is something very difficult to make secure.

bobince
+1 for including the Smarty way of escaping strings
Thorarin
+1  A: 

You should not modify data that is entered by the user before putting it into the database. The modification should take place as you're outputting it to the website. You don't want to lose the original data.

As you're spitting it out to the website, you want to escape the special characters into HTML codes using something like htmlspecialchars("my output & stuff", ENT_QUOTES, 'UTF-8') -- make sure to specify the charset you are using. This string will be translated into my output &amp; stuff for the browser to read.

Joe Philllips
@d03boy obviously you're tthinking of XSS only and not SQL injection!
jsd911
@jsd911 It's a question about XSS so I've limited my information to XSS... SQL injection is another topic
Joe Philllips