What validations should be done post canonicalize function in ColdFusion to avoid XSS attack? - coldfusion

We are working to avoid XSS attacks in a ColdFusion application. After adding <cfset this.scriptprotect=”all”> in our cfapplication tag, it worked only for the form input values which are now changed to InvalidTag. However it is not working for URL query string key values. Also I would like to know, why scriptprotect under the cfapplication tag is not working for URLs <script key insertion within the URL?
I come accross https://gist.github.com/learncfinaweek/4121370; I am including canonicalize in all pages for URL validations. I would like to know what are the validations that should be performed to avoid attacks post canonicalize function.

You cannot rely on CF exclusively for XSS (or sql injection) attacks. You could write your own code in application.cfc that will look for XSS/SQL Injection attacks in each of the scopes, and run that code in the onRequest() or onRequestStart() methods, depending on how your app is setup. Here's an example (please don't use this code without knowing exactly what it does and you've tested it extensively. This is some code I grabbed out of an app, but it's possible to get false positives and I'm not 100% confident with all the tests):
This code would be in application.cfc
public boolean function onRequestStart (
required string targetPage) {
try {
if (checkForAttack()) {
location url="/" addtoken=false;
return true;
}
... do other stuff ...
} catch (any e) {
onError(e, "onRequestStart");
}
return true;
} // onRequestStart()
private boolean function checkForAttack() {
// check for any kind of sql injection or xss attack
var attackFound = false;
// you could change these tests, or add more tests
var tests = ["4445434C415245", "cast(\s|%20)*(%28|\()", "(;|%3B)(\s|%20)*DECLARE", /*"exec(\s|%20)*\(",*/ "schema\.columns|table_name|column_name|drop(\s|%20)+table|insert(\s|%20)+into|\.tables", "\.\[sysobjects\]", "\.sysobjects"];
var ctTests = ArrayLen(tests);
var ix = 0;
var key = "";
if (isDefined("CGI.query_string") && CGI.query_string != "") {
for (ix = 1; ix <= ctTests; ix++) {
if (REFindNocase(tests[ix], CGI.query_string) > 0) {
CGI.query_string = "";
attackFound = true;
break;
}
}
}
if (isDefined("URL")) {
for (key in URL) {
for (ix = 1; ix <= ctTests; ix++) {
if (REFindNocase(tests[ix], URL[key]) > 0) {
attackFound = true;
URL[key] = "";
}
}
}
}
if (isDefined("Form")) {
for (key in Form) {
for (ix = 1; ix <= ctTests; ix++) {
if (reFindNocase(tests[ix], Form[key]) > 0) {
attackFound = true;
Form[key] = "";
}
}
}
}
if (IsDefined("Cookie")) {
for (key in Cookie) {
for (ix = 1; ix <= ctTests; ix++) {
if (REFindNocase(tests[ix], Cookie[key]) > 0) {
attackFound = true;
Cookie[key] = "";
}
}
}
}
return attackFound;
} // checkForAttack()

Related

CouchDB view reduce one doc per key

I'm trying to solve what seems like a fairly simple problem with a couchDb view, but I'm not even getting close to the target with my result set.
Rather than updating documents, I'm creating a new document every time as my versioning strategy, and tying those documents together with a versioning field called ver. The very first document in a version chain will see the ver field and the _id field having the same value. All subsequent documents in the chain will have the same ver field as previous docs in the chain, but will have a unique _id field. These documents also have a createdTime field which is my way of knowing which document is the latest.
Here's my documents:
{
"_id": "abcd-1234-efgh-9876",
"ver": "abcd-1234-efgh-9876",
"createdTime": "2020-01-12 01:15:00 PM -0600",
...
},
{
"_id": "uopa-3849-pmdi-1935",
"ver": "abcd-1234-efgh-9876",
"createdTime": "2020-02-16 02:39:00 PM -0600",
...
}
Here's my map function:
function (doc) {
emit(doc.ver, doc);
}
Here's my reduce function:
function(keys, values, rereduce) {
var latestVersions = {};
for (var i = 0; i < keys.length; i++) {
var found = latestVersions[keys[i][0]];
if (!found || found.createdTime < values[i].createdTime) {
latestVersions[keys[i][0]] = values[i];
}
}
return latestVersions;
}
And finally, here's my desired output from the view (just the doc that I want):
{
"_id": "uopa-3849-pmdi-1935",
"ver": "abcd-1234-efgh-9876",
"createdTime": "2020-02-16 02:39:00 PM -0600",
...
}
What am I missing here? The reduce function is returning both records, which is not what I want. Is what I'm trying to achieve possible or is there a better way to go about this?
Update
I was able to get this to work when a single key is used to access the view, which is one of my use cases.
function (keys, values, rereduce) {
var toReturn = values[0];
for (var i = 1; i < values.length; i++) {
if (values[i].createdTime > toReturn.createdTime) {
toReturn = values[i];
}
}
return toReturn;
}
I have another use case that will be returning all of the data in the view, however. The desired result there is the same as above, but the function I'm using for single keys will only ever return one result. How do I filter multiple values with a shared key such that 1 "shared" key:n values -> 1 key:1 value.
I was finally able to resolve this when I stumbled upon this couchbase article. It was much more articulate than some of the other dry computer-science documentation.
I still do not understand why certain items are grouped in a reduce method and other ones are not. For example, reduce was called 5 times for 6 items that shared an identical key; only one of the keys had actually grouped anything -- an array of two documents. It probably has something to do with those dry computer-science B-tree documents I glossed over.
Anyway, I was able to determine that all I needed to do was group the values by the ver field in both scenarios (the only difference being that rereduce had a 2 dimensional array). Here's what my reduce function ended up looking like:
function (keys, values, rereduce) {
var toValues = function(myMap) {
return Object.keys(myMap).map(function(key) {
return myMap[key];
});
}
if (rereduce) {
// values should look like [[{...}, {...}], [{...}]]
var outputMap = {};
for (var i = 0; i < values.length; i++) {
for (var j = 0; j < values[i].length; j++) {
var currentEl = values[i][j];
var found = outputMap[currentEl.ver];
if ((found && found.createdDate < currentEl.createdDate) || !found) {
outputMap[currentEl.ver] = currentEl;
}
}
}
return toValues(outputMap);
} else {
var outputMap = {};
for (var i = 0; i < values.length; i++) {
var found = outputMap[values[i].ver];
if ((found && found.createdDate < values[i].createdDate) || !found) {
outputMap[values[i].ver] = values[i];
}
}
return toValues(outputMap);
}
}

Domain switcher button for different languages

I want to create a dropdown menu With English or German as the options in Javascript / jQuery that checks that:
check if on a domain - say happy.com/pizza
if german is selected on dropdown
redirect user to
happy.de/pizza
and I could have a list
if happy.com/pizza got to happy.de/pizza
happy.com/coke got to happy.de/coke
happy.com/juice got to happy.de/juice
etc etc.
I have written the code yet but how would one go about this?
Thanks!
I have written some code but I just need a little help please:
In this scenario I am on the www.something.com/beer page and want it to go to the German Beer Page!
<select>
<option value="1">English</option>
<option value="2">German</option>
</select>
if(value == 2) && is current domain www.something.com/beer{
window.top.location.href = 'www.something.de/beer';
}else if(value == 2) && is current domain www.something.com/cheese{
window.top.location.href = 'www.something.de/cheese';
}else{
do nothing
}
How do I get this to check the value of the dropdown and the domain is currently on?
Here is my Jsfiddle
http://jsfiddle.net/msasz2an/
Thanks again!
function current(arr) {
// discuss at: http://phpjs.org/functions/current/
// original by: Brett Zamir (http://brett-zamir.me)
// note: Uses global: php_js to store the array pointer
// example 1: transport = ['foot', 'bike', 'car', 'plane'];
// example 1: current(transport);
// returns 1: 'foot'
this.php_js = this.php_js || {};
this.php_js.pointers = this.php_js.pointers || [];
var indexOf = function (value) {
for (var i = 0, length = this.length; i < length; i++) {
if (this[i] === value) {
return i;
}
}
return -1;
};
// END REDUNDANT
var pointers = this.php_js.pointers;
if (!pointers.indexOf) {
pointers.indexOf = indexOf;
}
if (pointers.indexOf(arr) === -1) {
pointers.push(arr, 0);
}
var arrpos = pointers.indexOf(arr);
var cursor = pointers[arrpos + 1];
if (Object.prototype.toString.call(arr) === '[object Array]') {
return arr[cursor] || false;
}
var ct = 0;
for (var k in arr) {
if (ct === cursor) {
return arr[k];
}
ct++;
}
// Empty
return false;
}

CouchDB list view error when no key requested

Having trouble with a list function I wrote using CouchApp to take items from a view that are name, followed by a hash list of id and a value to create a CSV file for the user.
function(head, req) {
// set headers
start({ "headers": { "Content-Type": "text/csv" }});
// set arrays
var snps = {};
var test = {};
var inds = [];
// get data to associative array
while(row = getRow()) {
for (var i in row.value) {
// add individual to list
if (!test[i]) {
test[i] = 1;
inds.push(i);
}
// add to snps hash
if (snps[row.key]) {
if (snps[row.key][i]) {
// multiple call
} else {
snps[row.key][i] = row.value[i];
}
} else {
snps[row.key] = {};
snps[row.key][i] = row.value[i];
}
//send(row.key+" => "+i+" => "+snps[row.key][i]+'\n');
}
}
// if there are individuals to write
if (inds.length > 0) {
// sort keys in array
inds.sort();
// print header if first
var header = "variant,"+inds.join(",")+"\n";
send(header);
// for each SNP requested
for (var j in snps) {
// build row
var row = j;
for (var k in inds) {
// if snp[rs_num][individual] is set, add to row string
// else add ?
if (snps[j][inds[k]]) {
row = row+","+snps[j][inds[k]];
} else {
row = row+",?";
}
}
// send row
send(row+'\n');
}
} else {
send('No results found.');
}
}
If I request _list/mylist/myview (where mylist is the list function above and the view returns as described above) with ?key="something" or ?keys=["something", "another] then it works, but remove the query string and I get the error below:
{"code":500,"error":"render_error","reason":"function raised error: (new SyntaxError(\"JSON.parse\", \"/usr/local/share/couchdb/server/main.js\", 865)) \nstacktrace: getRow()#/usr/local/share/couchdb/server/main.js:865\n([object Object],[object Object])#:14\nrunList(function (head, req) {var snps = {};var test = {};var inds = [];while ((row = getRow())) {for (var i in row.value) {if (!test[i]) {test[i] = 1;inds.push(i);}if (snps[row.key]) {if (snps[row.key][i]) {} else {snps[row.key][i] = row.value[i];}} else {snps[row.key] = {};snps[row.key][i] = row.value[i];}}}if (inds.length > 0) {inds.sort();var header = \"variant,\" + inds.join(\",\") + \"\\n\";send(header);for (var j in snps) {var row = j;for (var k in inds) {if (snps[j][inds[k]]) {row = row + \",\" + snps[j][inds[k]];} else {row = row + \",?\";}}send(row + \"\\n\");}} else {send(\"No results found.\");}},[object Object],[object Array])#/usr/local/share/couchdb/server/main.js:979\n(function (head, req) {var snps = {};var test = {};var inds = [];while ((row = getRow())) {for (var i in row.value) {if (!test[i]) {test[i] = 1;inds.push(i);}if (snps[row.key]) {if (snps[row.key][i]) {} else {snps[row.key][i] = row.value[i];}} else {snps[row.key] = {};snps[row.key][i] = row.value[i];}}}if (inds.length > 0) {inds.sort();var header = \"variant,\" + inds.join(\",\") + \"\\n\";send(header);for (var j in snps) {var row = j;for (var k in inds) {if (snps[j][inds[k]]) {row = row + \",\" + snps[j][inds[k]];} else {row = row + \",?\";}}send(row + \"\\n\");}} else {send(\"No results found.\");}},[object Object],[object Array])#/usr/local/share/couchdb/server/main.js:1024\n(\"_design/kbio\",[object Array],[object Array])#/usr/local/share/couchdb/server/main.js:1492\n()#/usr/local/share/couchdb/server/main.js:1535\n#/usr/local/share/couchdb/server/main.js:1546\n"}
Can't say for sure since you gave little detail, however, a probable source of problems, is the use of arrays to collect data from every row: it consumes an unpredictable amount of memory. This may explain why it works when you query for a few records, and fails when you query for all records.
You should try to arrange data in a way that eliminates the need to collect all values before sending output to the client. And keep in mind that while map and reduce results are saved on disk, list functions are executed on every single query. If you don't keep list function fast and lean, you'll have problems.

XSS Filter to enctype="multipart/form-data" forms

I found the next code that prevent xss atacks. But it has a problem. It works fine with forms that have enctype="application/x-www-form-urlencoded", but not with forms that have enctype="multipart/form-data". I observe that getParameterValues() and rest of methods are not called.
//--- XSS Filter ---//
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
/**
* Servlet Filter implementation class XSSFilter
*/
public class XSSFilter implements Filter {
#SuppressWarnings("unused")
private FilterConfig filterConfig;
/**
* Default constructor.
*/
public XSSFilter() {
}
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
public void destroy() {
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(new RequestWrapperXSS((HttpServletRequest) request), response);
}
}
//--- RequestWrapperXSS ---//
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public final class RequestWrapperXSS extends HttpServletRequestWrapper {
public RequestWrapperXSS(HttpServletRequest servletRequest) {
super(servletRequest);
}
public String[] getParameterValues(String parameter) {
System.out.println("entra parameterValues");
String[] values = super.getParameterValues(parameter);
if (values == null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = cleanXSS(values[i]);
}
return encodedValues;
}
public String getParameter(String parameter) {
System.out.println("entra getParameter");
String value = super.getParameter(parameter);
if (value == null) {
return null;
}
return cleanXSS(value);
}
public String getHeader(String name) {
System.out.println("entra header");
String value = super.getHeader(name);
if (value == null)
return null;
return cleanXSS(value);
}
private String cleanXSS(String cadena) {
System.out.println("entra claean XSS");
StringBuffer sb = new StringBuffer(cadena.length());
// true if last char was blank
boolean lastWasBlankChar = false;
int len = cadena.length();
char c;
for (int i = 0; i < len; i++)
{
c = cadena.charAt(i);
if (c == ' ') {
// blank gets extra work,
// this solves the problem you get if you replace all
// blanks with , if you do that you loss
// word breaking
if (lastWasBlankChar) {
lastWasBlankChar = false;
sb.append(" ");
}
else {
lastWasBlankChar = true;
sb.append(' ');
}
}
else {
lastWasBlankChar = false;
//
// HTML Special Chars
if (c == '"')
sb.append(""");
else if (c == '&')
sb.append("&");
else if (c == '<')
sb.append("<");
else if (c == '>')
sb.append(">");
else if (c == '\n')
// Handle Newline
sb.append("<br/>");
else {
int ci = 0xffff & c;
if (ci < 160 )
// nothing special only 7 Bit
sb.append(c);
else {
// Not 7 Bit use the unicode system
sb.append("&#");
sb.append(new Integer(ci).toString());
sb.append(';');
}
}
}
}
return sb.toString();
}
}
In case of multipart/form-data requests, the data is available by getPart() and getParts() methods, not by getParameter(), getParameterValues() and consorts.
Note that those methods are introduced in Servlet 3.0 and that in older versions there is not any standard API facility to extract data from multipart/form-data requests. The defacto API which is been used for that instead is the well known Apache Commons FileUpload.
Unrelated to the concrete problem, this is IMO a bad way to prevent XSS. XSS should be prevented in the view side during redisplaying the user-controlled input, right there where it can harm. Escaping before processing the user-controlled input will only risk in double escaping because it's not the "standard" way of XSS prevention. The developers should just ensure that they always escape user-controlled data in the view side using JSTL <c:out> or fn:escapeXml() or any other MVC framework supplied facilities (JSF for example escapes everything by default).
See also
XSS prevention in JSP/Servlet web application

Setting default Index for a Drop Down List in flex 4

I have a drop down list that gets its data from a php web service method.This response is smthing like :
array('id'=>integer,'name'=>'lin')
When the page loads, I want to set the selected index to "lin" initially. How do I do this ?
you just need to set selectedIndex property of dropdownlist control.
ex.
dwl.selectedIndex = 1; // "Index of "lin"
you should do this.
var iIndex:int;
for(var i:int = 0; i < arrResponse.length; i++)
{
// if(Array(arrResponse[i])[1] == "lin")
if(Array(arrResponse[i]).name == "lin") {
iIndex = i;
}
}
dwl.selectedIndex = iIndex;