Protection from SQL injection in ColdFusion - sql

I am trying to improve my application's security. Whenever I receive data from the user (whether through POST or GET) that is supposed to be an integer, I validate that appropriately. But often the data is VARCHAR, and sometimes can contain HTML.
How do I protect my DB from SQL injection in that case?
Does <cfqueryparam value="#form.textInput#" cfsqltype="cf_sql_varchar"> protect the query from sending a malicious SQL statement inside a VARCHAR value?

The short answer is yes.
cfqueryparam will stop some sql injection attacks from occuring.
There are other attack variables that can be used, so be careful, but well written coldfusion can be very safe.
Be wary of Cross site scripting attacks if you are storing and later displaying input html, be especially careful of javascript tags.

The short answer to your question is 'yes'.
I block hacking attempts using three methods.
I use cfqueryparam in all my database queries. I will use cfparam at the top of the template/cfm files for url scope variables.
I have used Portcullis or variants of it. You can get it from http://portcullis.riaforge.org/. Portcullis will also defend against some cross site scripting attacks.
I use Windows IIS 7.5 (Windows Server 2008 R2). I use the URL Rewrite feature to block the bulk of URL based attacks. You can do similar things with Apache and the rewrite that it supports. Here are my IIS URL Rewrite rules:
<?xml version="1.0" encoding="UTF-8"?>
<appcmd>
<CONFIG CONFIG.SECTION="system.webServer/rewrite/globalRules" path="MACHINE/WEBROOT/APPHOST" overrideMode="Inherit" locked="false">
<system.webServer-rewrite-globalRules>
<rule name="SQL Injection - EXEC - SCRIPT_NAME" stopProcessing="true">
<match url="^.*EXEC\s*[\(|%28].*$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
</conditions>
<serverVariables>
</serverVariables>
<action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Forbidden" />
</rule>
<rule name="SQL Injection - EXEC - QS" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{QUERY_STRING}" pattern="^.*EXEC\s*[\(|%28].*$" />
</conditions>
<serverVariables>
</serverVariables>
<action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Forbidden" />
</rule>
<rule name="SQL Injection - CAST - SCRIPT_NAME" stopProcessing="true">
<match url="^.*CAST\s*[\(|%28].*$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
</conditions>
<serverVariables>
</serverVariables>
<action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Forbidden" />
</rule>
<rule name="SQL Injection - CAST - QS" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{QUERY_STRING}" pattern="^.*CAST\s*[\(|%28].*$" />
</conditions>
<serverVariables>
</serverVariables>
<action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Forbidden" />
</rule>
<rule name="SQL Injection - DECLARE - SCRIPT_NAME" stopProcessing="true">
<match url="^.*DECLARE.*$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
</conditions>
<serverVariables>
</serverVariables>
<action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Forbidden" />
</rule>
<rule name="SQL Injection - DECLARE - QS" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{QUERY_STRING}" pattern="^.*DECLARE.*$" />
</conditions>
<serverVariables>
</serverVariables>
<action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Forbidden" />
</rule>
<rule name="SQL Injection - NVARCHAR - SCRIPT_NAME" stopProcessing="true">
<match url="^.*CHAR\s*[\(|%28].*$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
</conditions>
<serverVariables>
</serverVariables>
<action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Forbidden" />
</rule>
<rule name="SQL Injection - NVARCHAR - QS" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{QUERY_STRING}" pattern="^.*CHAR\s*[\(|%28].*$" />
</conditions>
<serverVariables>
</serverVariables>
<action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Forbidden" />
</rule>
<rule name="SQL Injection - sp_password - SCRIPT_NAME" stopProcessing="true">
<match url="^.*sp_password.*$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
</conditions>
<serverVariables>
</serverVariables>
<action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Forbidden" />
</rule>
<rule name="SQL Injection - sp_password - QS" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{QUERY_STRING}" pattern="^.*sp_password.*$" />
</conditions>
<serverVariables>
</serverVariables>
<action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Forbidden" />
</rule>
<rule name="SQL Injection - xp - SCRIPT_NAME" stopProcessing="true">
<match url="^.*%20xp_.*$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
</conditions>
<serverVariables>
</serverVariables>
<action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Forbidden" />
</rule>
<rule name="SQL Injection - xp - QS" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{QUERY_STRING}" pattern="^.*%20xp_.*$" />
</conditions>
<serverVariables>
</serverVariables>
<action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Forbidden" />
</rule>
</system.webServer-rewrite-globalRules>
</CONFIG>
</appcmd>
These rules are added to the C:\Windows\System32\inetsrv\config\applicationHost.config file for IIS. However I do ****NOT**** recommend that you directly edit this file. One mistake and IIS will not load. Instead copy & paste the rules above and save them as "iis-global-rewrite.xml". Then run the following batch file to add the rules to your IIS server:
C:\Windows\System32\inetsrv\appcmd.exe set config -in < iis-global-rewrite.xml
The IIS rewrite rules should work with IIS 7.0 (Windows Server 2008) but I have not tested it.
These rules could also be applied to a single site using the web.config file if you do not have access to the server.
Why do I use three different methods for protection? Because none of them cover all the bases. The IIS rewrite rules only protect against URL based attacks. Hackers can also use form submission attacks that do the same thing. I prefer the IIS rules as a first line of protection because it will work with all sites on the server including PHP, ASP, etc. Portcullis is a good second line of defense for ColdFusion because it will catch form based attacks and some cross site scripting attacks. The last line of defense is the cfqueryparam/cfparam code which protects against URL/form based SQL injection attacks.
If all three of these methods are used the server/site should be very secure. I would still advise reviewing server logs from time to time as attacks do evolve and improve.

Related

URL Rewriting in IIS with Express

I want to rewrite all images to a different folder. I'm using IIS and have configured a rule in the web.config to redirect all requests to a node.js file as follows:
<rewrite>
<rules>
<rule name="img">
<match url="\/(.*).img" />
<action type="Rewrite" url="/handlers/img.js" />
</rule>
</rules>
</rewrite>
All requests are now being sent to the img.js file, where based on a condition, I want to redirect to another image file. But IIS now sends that file to the img.js and it ends up as a loop. Is there any way out of this loop?
You could try the below thing to resolve the issue:
set the condition to do not match the pattern:
<conditions>
<add input="{REQUEST_URI}" pattern="\/(.*).img.js" negate="true" />
</conditions>
or set <rule name="img" stopProcessing="true">
<rule name="img" stopProcessing="true">
<match url="\/(.*).img" />
<conditions>
<add input="{REQUEST_URI}" pattern="\/(.*).img.js" negate="true" />
</conditions>
<serverVariables />
<action type="Rewrite" url="/handlers/img.js" logRewrittenUrl="true" />
</rule>

URL Rewrite Force to https except one domain

First of all, I need to say that after hours googling, I could not find a way to to get the result I need.
Here's the problem:
I have 2 domains for my website, for example: (foo.com) and
(bar.com)
I need foo.com domain to be redirected to HTTPS
I need bar.com to remain on its HTTP and do NOT redirect to HTTPS
I have tried many rules, but none of them did the job. for example:
<rule name="Force HTTPS" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
<add input="{REQUEST_URI}" negate="true" pattern="^(www.)?bar.com$$" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
This should redirect foo.com to HTTPS:
<rule name="Add WWW prefix to foo.com and use HTTPS" stopProcessing="true">
<match url="(.*)" ignoreCase="true" />
<conditions>
<add input="{HTTP_HOST}" pattern="^foo\.com" />
</conditions>
<action type="Redirect" url="https://www.foo.com/{R:1}" redirectType="Permanent" />
</rule>
And for bar.com:
<rule name="Force NonHTTPS" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="on" />
</conditions>
<action type="Redirect" url="http://{HTTP_HOST}/{REQUEST_URI}" />
</rule>
Take a look at stopProcessing attribute in the first rule. It should stop processing of next rules when the foo.com will be matched. This won't allow "Force NonHTTPS" rule to trigger.

IIS rewrite rule Redirect Non-www to dynamic Domain Equivalent and always https

What I want is that all requests that are non-https or don't have www prepended are redirected to: "https://www." + domain name + possible query string parameters.
I have this rewrite rule (found here):
<rule name="non-www to www https" enabled="true" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_HOST}" pattern="^[^\.]+\.[^\.]+$" />
<add input="{HTTPS}" pattern="on" />
</conditions>
<action type="Redirect" url="https://www.{HTTP_HOST}/{R:0}" />
</rule>
However, when typing the following domains in the browser address bar no redirect takes place (and I get a security certificate error since I don't have a wildcard DNS SSL certificate):
https://example.com/
http://example.com/
But example.com (without protocol), redirects correctly to https://www.example.com/
Also notice in the above rule that I'm matching the hostname dynamically and not just on "example.com" since I want this rule to work for multiple domain names.
I then also checked this post, which has a neat rule:
<rule name="Force WWW and SSL" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_HOST}" pattern="^[^www]" />
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://www.zzz.com/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
I think this does exactly what I want, but how would I make the domain name in this example dynamic and preserve that in the redirect (like the first code sample does)? (the original poster has not logged in in the last 6 months so that's why I am asking here)
Furthermore I also checked this post, which also seems a good candidate:
<rule name="Redirect top domains with non-www to www" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_HOST}" pattern=".*localhost.*" negate="true" />
<add input="{HTTP_HOST}" pattern=".*stage\..*" negate="true" />
<add input="{HTTP_HOST}" pattern=".*dev\..*" negate="true" />
<add input="{HTTP_HOST}" pattern="^([^\.]+)\.([^\.]+)$" />
</conditions>
<action type="Redirect" url="https://www.{HTTP_HOST}/{R:1}" redirectType="Permanent" />
<serverVariables>
<set name="Redirect" value="false" />
</serverVariables>
</rule>
<rule name="Force HTTPS" enabled="true" stopProcessing="true">
<match url="(.*)" ignoreCase="false" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_HOST}" pattern=".*localhost.*" negate="true" />
<add input="{HTTP_HOST}" pattern=".*stage\..*" negate="true" />
<add input="{HTTP_HOST}" pattern=".*dev\..*" negate="true" />
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
But then http://example.com redirects to https://example.com and I still get the security exception.
First, I strongly recommend you to obtain a new SSL certificate that supports both example.com and www.example.com. That kind of certificates are actually pretty standard with most SSL providers, it does not have to be a wildcard certificate. Otherwise you will not be able to handle requests to https://example.com as it is now, and that's a problem I think.
Your top two rules should be like the ones below.
P.S. 301 redirects are cached for a while by the browsers. Google clear 301 redirect cache for your browser before testing the new rules.
<rule name="All HTTP to HTTPS+WWW" stopProcessing="true">
<match url=".*" />
<conditions trackAllCaptures="true">
<add input="{SERVER_PORT_SECURE}" pattern="0" />
<add input="{HTTP_HOST}" pattern="(?:localhost|stage\.|dev\.)" negate="true" />
<!-- here with this 3rd condition we capture the host name without "www." prefix into {C:1} variable to use in redirect action -->
<add input="{HTTP_HOST}" pattern="^(?:www\.)?(.+)" />
</conditions>
<action type="Redirect" url="https://www.{C:1}/{R:0}" appendQueryString="true" redirectType="Permanent" />
</rule>
<rule name="All HTTPS With No WWW to HTTPS+WWW" stopProcessing="true">
<match url=".*" />
<conditions trackAllCaptures="false">
<add input="{SERVER_PORT_SECURE}" pattern="1" />
<add input="{HTTP_HOST}" pattern="(?:localhost|stage\.|dev\.)" negate="true" />
<add input="{HTTP_HOST}" pattern="^www\." negate="true" />
</conditions>
<action type="Redirect" url="https://www.{HTTP_HOST}/{R:0}" appendQueryString="true" redirectType="Permanent" />
</rule>

IIS URL Rewrite

I have the following rewrite rule:
<rewrite>
<rules>
<rule name="FrontController" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="wcf/api.svc/auth/home" />
</rule>
</rules>
</rewrite>
This basically rewrites all non-file urls to web service api calls that returns index.html in an SPA backed by WCF.
The above rewrite ends up including all the query string parameters that were included with the original URL. What I need to do is also include the original URL, such as, 'wcf/api.svc/auth/products', as a query string parameter in the rewritten URL, such as 'https://domain.com/wcf/api.svc/auth/products?enc=lkjewro8xlkz' being transformed into 'https://domain.com/wcf/api.svc/auth/home?enc=lkjewro8xlkz&orig=wcf/api.svc/auth/products'.
Is this possible, and if so, what changes would I need to make to achieve it? I would like for my WCF application to know about the original URL so that it can configure the SPA to initialize to a particular view on load.
Thanks
It's quite possible.
You need to add the URL Encoded value of the {REQUEST_URI} to the Rewrite URL.
<rewrite>
<rules>
<rule name="FrontController" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="wcf/api.svc/auth/home?orig={UrlEncode:{REQUEST_URI}}" />
</rule>
</rules>
</rewrite>
With this rule, in your WCF endpoint orig parameter would be:
/wcf/api.svc/auth/products?enc=lkjewro8xlkz
If you don't want the query string part (?enc=lkjewro8xlkz), you'll need an extra condition to match the URI without query string.
<rewrite>
<rules>
<rule name="FrontController" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<!-- match any character up to a question mark -->
<add input="{REQUEST_URI}" pattern="^[^\?]+" />
</conditions>
<!-- {C:0} means the first match in conditions -->
<action type="Rewrite" url="wcf/api.svc/auth/home?orig={UrlEncode:{C:0}}" />
</rule>
</rules>
</rewrite>
Now, orig will be /wcf/api.svc/auth/products in the WCF endpoint.
Hope it helps.

Preserving URL when using SSL Redirect for multiple websites pointing to same folder

I have multiple websites pointing to a central folder (IIS 7.5)
company1.domain.com/wo pointing to D:\inetpub\wo
company2.domain.com/wo pointing to D:\inetpub\wo
company3.domain.com/wo pointing to D:\inetpub\wo
All the websites work for both HTTP and HTTPS (if typed manually). However, the sites have to connect via HTTPS. I want to setup automatic SSL redirect to but am having issues. I created URL Rewrite rule but since this is only one webconfig file the URL redirects to only one website (not maintaining the URL).
How do I setup SSL redirect so that the URLs are preserved and all websites point to the same folder?
Any assistance will be greatly appreciated.
Thanks
You should include the host header when checking if HTTPS is enabled and then redirect to the https URL for the appropriate domain.
Here's an example:
<rewrite>
<rules>
<clear />
<rule name="Force HTTPS - www.domain1.com" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{HTTPS}" negate="true" pattern="^ON$" />
<add input="{HTTP_HOST}" pattern="\.domain1\.com$" />
</conditions>
<action type="Redirect" url="https://www.domain1.com{REQUEST_URI}" appendQueryString="false" redirectType="Permanent" />
</rule>
<rule name="Force HTTPS - www.domain2.com" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{HTTPS}" negate="true" pattern="^ON$" />
<add input="{HTTP_HOST}" pattern="\.domain2\.com$" />
</conditions>
<action type="Redirect" url="https://www.domain2.com{REQUEST_URI}" appendQueryString="false" redirectType="Permanent" />
</rule>
<!-- add more rules for other domains if needed -->
</rule>
</rules>
</rewrite>
You can add as many rules for domain names as you want.
EDIT: Sorry, I misread your question. In that case it's even simpler:
<rewrite>
<rules>
<clear />
<rule name="Force HTTPS" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{HTTPS}" negate="true" pattern="^ON$" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" appendQueryString="false" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
No need to check for the host header, just include the host name in the redirect. You only have to make sure that you have SSL certificates for all domain names.