how do I use a XMLHttpRequest to send a request safely to a server - security

I have written some JavaScript to send a request to a php file which can query or post to a database. I have tried using GET and POST.
function action(theAction) {
const xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "queryDB.php", true);
xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlhttp.onreadystatechange = function () {
// The variable xmlhttp not available here. But since this function is a member of xmlhttp, this=xmlhttp
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
document.getElementById("result").innerHTML =
document.getElementById("result").innerHTML + " " + this.responseText;
}
}
xmlhttp.send("p1=post&p2=" + theAction);
}
function showActivity () {
const xmlhttp = new XMLHttpRequest();
xmlhttp.onload = function () {
document.getElementById("result").innerHTML = this.responseText;
}
xmlhttp.open("GET", "queryDB.php?p1=list");
xmlhttp.send();
}
Both methods work fine but they both can be imitated by simply writing the URL of my php file followed by suitable parameters into a browser address bar. So for the GET example I could write in
https://patience5games.com/php/queryDB.php?p1=list
and I get a little report in the browser window.
This means that it is quite easy for hackers to post fake data to my database. How can I prevent that?
I want to send a message in not such an obvious way. One bodge solution using the POST method would be to have xmlhttp.setRequestHeader("Content-Type", "my message"); which I could decode at the other end. I think. But surely there must be a better way than that?

Related

How can I intercept a single XHR/fetch request, without affecting requests afterwards?

I am building a React/Typescript app, running completely client-side in browser. In componentDidMount(), I make a fetch request which I intercept successfully, to change the URL, and then make that request.
For reference, the API object is also from a third party library, loaded in via an HTML script tag, so I don't have access to the inner workings of the object. That's why I'm attempting to intercept the call instead to point the URL at a different endpoint.
async function makeRequest() {
let originalFetch = redefineFetch();
let data;
try {
data = await API.fetchData();
} catch (error) {
resetFetch(originalFetch);
return;
}
resetFetch(originalFetch);
return data;
}
const redefineFetch = () => {
const { fetch: originalFetch } = window;
let originalWindowFetch = window.fetch;
window.fetch = async (...args) => {
let [resource, config] = args;
resource = NEW_URL;
const response = await originalFetch(resource, config);
return response;
};
return originalWindowFetch;
};
const resetFetch = (
originalFetch: ((input: RequestInfo | URL, init?: RequestInit | undefined) => Promise<Response>) &
((input: RequestInfo | URL, init?: RequestInit | undefined) => Promise<Response>)
) => {
console.log("Resetting fetch");
window.fetch = originalFetch;
};
How I'm currently doing it:
I copied how it was done in this blog post. https://blog.logrocket.com/intercepting-javascript-fetch-api-requests-responses/.
As you can see, makeRequest() calls redefineFetch(), which redefines window.fetch to point to the NEW_URL instead.
redefineFetch() returns the original implementation of fetch as originalFetch.
After making the request, I call resetFetch() and pass originalFetch.
I then set window.fetch = originalFetch.
What I think is the issue
Every request including and after API.fetchData() now point to the NEW_URL.
These requests are out of my control in timing as they are made by 3rd party portions of my code.
I think I'm either not setting window.fetch back to its original value correctly, OR there's a race condition in which these mistakenly intercepted requests are being made before resetFetch() is called.
My Questions
How can I redefine fetch only for the API.fetchData() call without risking affecting any other calls made in my app?
Is there a better way to accomplish what I'm doing?

HTTP GET response says missing field Node XmlHttpRequest

I'm trying to make a get call to Dynamics CRM via the WebApi with the code below
However I get the "Required Field "EntityName" is missing" response. How can I add it correctly? if I include it in the send() as a parameter it gets wiped and won't be sent with it.
I'm relatively new to this so I don't know what I'm doing wrong.
Code:
let url = this._data.OrgInfo.CrmUrl + "/api/data/v" + this._data.OrgInfo.ApiVersion + "/RetrieveEntityRibbon?EntityName=account";
var xmlHttpRequest = require('xhr2');
var req = new xmlHttpRequest();
req.open("GET", url, true);
setRequestHeaders()
req.addEventListener("load", function() {
let result = JSON.parse(req.response);
}, false);
req.send();
});
This should work, but verify it on your end pls.
let url = this._data.OrgInfo.CrmUrl + "/api/data/v" + this._data.OrgInfo.ApiVersion + "/RetrieveEntityRibbon(EntityName='account',RibbonLocationFilter='All')";

How to set columns via AJAX in Tabulator 4.1

I am trying to create a tabulator 4.1 table with columns that will load via AJAX. Preferably without jQuery, although it could be used if it makes a large difference. I have tried the following to no avail:
table.setColumns("ajaxr.php?act=GetTabuColumns&vals=data");
and
$("#display").tabulator("setColumns", "ajax.php?act=GetTabuColumns&vals=data");
I've also tried doing separate ajax request with plain Javascript as well as a jQuery ajax request. The date would load as a json encoded array, but it would throw the following error.
Uncaught TypeError: t.forEach is not a function
at t.setColumns (tabulator.min.js:2)
at t.c.setColumns (tabulator.min.js:4)
at XMLHttpRequest.xmlhttp.onreadystatechange ((index):71)
I'm fairly new to javascript so it could me I'm making a basic mistake. How should this be done?
My basic setup is as follows:
function datatablemaker(table){
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else {
// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var newcolumns = this.responseText;
var table = new Tabulator("#display", {
columns:[
{title:'ID', field:'ID', sorter:'number'},...
{title:'Create Time', field:'Create Time', sorter:'string'}
],
});
table.setData("ajax.php?act=GetTabuData&vals=data");
table.setColumns(newcolumns);
}
};
xmlhttp.open("GET",'ajax.php?act=GetTabuColumns&vals=data',true);
xmlhttp.send();
};
document.getElementById("View").addEventListener("click", datatablemaker);
EDIT:
I got it to work if I used JSON.parse, but I know that there should be a better way to do this. i.e.
var newcolumns = JSON.parse(this.responseText);
There is no build in way to do this at the moment, that will be coming in the 4.2 release later in the month.
in the mean time making an ajax request and passing the column array into the setColumns function is the best approach.

Node js, Request body empty for certain websites

I'm experimenting with Node.js and web scraping. In this case, I'm trying to scrape the most recent songs from a local radio station for display. With this particular website, body returns nothing. When I try using google or any other website, body has a value.
Is this a feature of the website I'm trying to scrape?
Here's my code:
var request = require('request');
var url = "http://www.radiomilwaukee.org";
request(url, function(err,resp,body) {
if (!err && resp.statusCode == 200) {
console.log(body);
}
else
{
console.log(err);
}
});
That's weird, the website you're requesting doesn't seem to return anything unless the accept-encoding header is set to gzip. With that in mind, using this gist will work: https://gist.github.com/nickfishman/5515364
I ran the code within that gist, replacing the URL with "http://www.radiomilwaukee.org" and see the content within the sample.html file once the code has completed.
If you'd rather have access to the web page's content within the code, you could do something like this:
// ...
req.on('response', function(res) {
var body, encoding, unzipped;
if (res.statusCode !== 200) throw new Error('Status not 200');
encoding = res.headers['content-encoding'];
if (encoding == 'gzip') {
unzipped = res.pipe(zlib.createGunzip());
unzipped.on("readable", function() {
// collect the content in the body variable
body += unzipped.read().toString();
});
}
// ...

What is the correct syntax for winjs.xhr data

I tried to use winjs.xhr to POST some data to a URL with no success. I got it working by essentially doing the same thing with XMLHttpRequest. This just doesn't feel right, as winjs.xhr, I thought, wraps XMLHttpRequest anyway. Can anyone explain how I do this in winjs.xhr?
Not working winjs.xhr code
Passing everything in as a URL encoded string
var url = "http://localhost/paramecho.php";
var targetUri = "http://localhost/paramecho.php";
var formParams = "username=foo&password=bar" //prefixing with a '?' makes no difference
//ends up with same response passing an object(below) or string (above)
//var formObj = {username: "foo", password: "bar"}
WinJS.xhr({
type: "post",
url: targetUri,
data: formParams
}).then(function (xhr) {
console.log(xhr.responseText);
});
I end up with my receiving PHP file getting none of the parameters, as though I'd sent no data in the first place.
I tried a few things but the code above is the simplest example. If I was to pass an object into the data parameter it behaves the same way (commented out). I've used a FormData object as well as a plain JSON object.
I changed my app manifest to have the correct network capabilities - and the working example below was done in the same app, so I'm confident it's not capability-related.
Working version using XMLHttpRequest
var username = "foo";
var password = "bar";
var request = new XMLHttpRequest();
try {
request.open("POST", "http://localhost/paramecho.php", false);
request.setRequestHeader('Content-type', "application/x-www-form-urlencoded");
request.send("username=" + encodeURIComponent(username) + "&password=" + encodeURIComponent(password));
console.log(request.responseText);
} catch (e) {
console.log("networkError " + e.message + " " + e.description);
}
And this successfully calls my PHP server-side function, with the parameters I expected.
So, the question is...how do I achieve what I have working in XMLHttpRequest with winjs.xhr? It feels like winjs.xhr the way this is supposed to work (I'm a newbie at Windows 8 app development so I'm happy to be corrected)
You're completely right WiredPrairie. Passing in the header is all that is needed - I think I'd assumed that was the default for a post.
Working version:
WinJS.xhr({
type: "post",
url: targetUri,
data: formParams,
headers: {"Content-type": "application/x-www-form-urlencoded"}
}).then(function (xhr) {
console.log(xhr.responseText);
});

Resources