Fetch POST to send DELETE query to MySQL - is it safe? - javascript

Since many web hosting websites (such as infinityfree and 000webhost) block HTTP DELETE requests I found a way how to send DELETE query to MySQL by adding a password to HTTP POST body which triggers PHP to send DELETE query to MySQL.
But is this safe since the password is visible in Front End and so visible to any site visitor? Can someone do harm to my database by using this password like making SQL injection?
In React JS:
async function sendDeleteRequest(i) {
const bodyWithPassword = {
...props.updatedProducts[i],
password: "kfI2KiIMOibKn0X98ufe$#!G^z78FNbbvI!fng0p*vk",
};
await fetch(Links["products"], {
method: "POST",
body: JSON.stringify(bodyWithPassword),
headers: {
"Content-Type": "application/json",
},
});
await props.refreshProductListContent();
}
In PHP:
//If HTTP body has password send DELETE query.
if ($json["password"] = "kfI2KiIMOibKn0X98ufe$#!G^z78FNbbvI!fng0p*vk") {
$deleteProduct = new $json["productType"]($json);
$deleteProduct->deleteProduct($json);
return;
}
//If password isn't added in the body add product to database
$newProduct = new $json["productType"]($json);
$newProduct->addProduct($json, $newProduct);

The short answer is - This is not safe
Having a hard-coded password in ReactJS, which is a client-based Javascript code, means that it's accessible to anyone who visits and loads the Javascript file. Anyone can read it, use it and abuse it.
There is not enough code provided to see if there is a SQL injection vulnerability as such. You should review deleteProduct and addProduct functions and see if you have parameterized all the parameters passed to a SQL query.
In a scenario where your code was vulnerable to a SQL injection, anyone can grab the client-side encoded password and abuse the SQL injection vulnerability.
Regarding the request type, there is no actual difference between a POST and a DELETE request (technically speaking), apart from how your server side code processes it, which is what you write and decide. Obviously the development world has agreed to common sense on which each of the methods does here https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods, which you should oblige by when doing development.

Related

"redirect_uri_mismatch" when sending authentication code to GoogleAPI

I am having trouble with the authentication process for the GoogleAPI. In the end I want to be able to read the users steps using the GoogleFit API and then store that value in a database. Currently I'm using restdb.io and executing javascript in codehooks.
The documentation from Google that I am following can be found here, clicking on the HTTP/REST option in the code examples. At the moment I am at step 5: I have gotten the users authentication code and stored it in the database. Now I have to POST the code along with some other parameters and get the access and refresh tokens.
If the POST is successful (from what I understand) I should get back a 200-OK message that the request was valid. Google will then POST a JSON body with the access and refresh token to the redirect_uri that I have specified in my GoogleAPI credentials page and the initial request. At redirect_uri I have to handle the request and save the two values.
The problem is that I receive a redirect_uri_mismatch - Bad Request message from Google as a response when executing the request. I get it at the log.debug("ERROR HERE: " + [...]); in the code below:
async function mainFunction(){
const authCode = THIS_IS_MY_AUTHENTICATION_CODE;
try {
var answer = await postRequestToGoogle(authCode);
//do stuff with response from Google
} catch (error) {
//do stuff
}
}
async function postRequestToGoogle(authCode){
//body for the request
const params = "code=" + authCode + "&" +
"client_id=THIS_IS_MY_CLIENT_ID" + "&" +
"client_secret=THIS_IS_MY_CLIENT_SECRET" + "&" +
"redirect_uri=THIS_IS_MY_REDIRECT_URI" + "&" +
"grant_type=authorization_code";
try{
const result = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: params})
.then(res => {
log.debug("ERROR HERE: " + JSON.stringify(res.json()));
return res.json();
})
//return JSON back main function
return result;
}catch(error){
//do stuff
}
}
I looked up the error message and tried some things:
Copy and pasted multiple different Authorized redirect URI from the GoogleAPI credentials page into the code to make sure that there is no problem with
http/https
www/no www
trailing slashes
typos or capitalization
Waited for changes to be processed by Google (read that it can more than 30min)
Changed all the other parameters to see if the redirect_uri is actually the problem
If code is changed the message is invalid_grant - Bad Request
If client_id is changed the message is invalid_client - The OAuth client was not found
If client_secret is changed the message is invalid_client - Unauthorized
If the grant_type is changed the message is unsupported_grant_type - Invalid grant_type
That's why I think the issue is the redirect_uri, but it's unclear to me how since I copy&pasted it. Something that came to mind was that maybe the value of redirect_uri gets changed when it's read by Google? Or maybe when the request is being put together? Do some characters have to be replaced?
I tried to analyze the request with Wireshark but didn't think about the fact that it's HTTPS so I would have I would have to decrypt it.. Is that something I should look into?
Thank you for taking the time to read all of this! If you have any advice please let me know :)
Update 16.11.20:
I have created a new OAuth 2.0 Client ID and used the new id/secret in my request. The resulting message the same as before. I will wait and try again tomorrow to see if maybe Google needs some more time. Then I'll try to delete all current IDs and start with a fresh GoogleAPI project.
Update 19.11.20:
Creating a new OAuth 2.0 Client ID did not resolve my problem, neither did creating a whole new GoogleAPI project and adding those credentials into the request. I am in contact with the developers of restdb.io and have asked them to add the Google Auth Library: Node.js Client to the list of supported Node.js packages. Hopefully that will help, I will give it a try as soon as it can be used :)
Update 02.12.20:
No progress so far, but I'm optimistic that the developers will add the package soon. I will post a final update as soon as I am done with this project.

Use git credential manager to fetch azure devops api instead of personal access token

I am trying to fetch git azure devops api to get information about repositories and branches in js.
In order to achieve that, I made a little application with the following code :
$(document).ready(function() {
var personalToken = btoa(':'+'<personnalAccessToken>');
fetch('https://dev.azure.com/<company>/<project>/_apis/git/repositories?api-version=5.1', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
'Authorization': 'Basic '+ personalToken
}
}).then(function(response) {
return response.json();
}).then(function(repositories) {
console.log("There are "+repositories.count+" repositories");
}).catch(function(error) {
console.log('Fetch error: ' + error.message);
});
This code is working great but as you can see there is my personnalAccessToken writen directly inside the code... which is really bad...
When I am using git in command line, I don't have to specify any credential information because I use git credential manager for windows. Which means my personnalAccessToken is already stored, cached and automatically used everytime I use a git command, like clone, etc.
So, I would like my js code to use the same thing, I would like it to use my stored credentials automatically to fetch the api without being required to set my personnalAccessToken in code.
I have already searched for hours but can't find out if it is possible.
I have already searched for hours but can't find out if it is
possible.
Sorry but as I know it's impossible. The way you're calling the Rest API is similar to use Invoke-RestMethod to call rest api in Powershell.
In both these two scenarios, the process will try to fetch PAT for authentication in current session/context and it won't even try to search the cache in Git Credential Manager.
You should distinguish the difference between accessing Azure Devops service via Rest API and by Code:
Rest API:
POST https://dev.azure.com/{organization}/{project}/{team}/_apis/wit/wiql?api-version=5.1
Request Body:
{
"query": "Select [System.Id], [System.Title], [System.State] From WorkItems Where [System.WorkItemType] = 'Task' AND [State] <> 'Closed' AND [State] <> 'Removed' order by [Microsoft.VSTS.Common.Priority] asc, [System.CreatedDate] desc"
}
Corresponding Code in C#:
VssConnection connection = new VssConnection(new Uri(azureDevOpsOrganizationUrl), new VssClientCredentials());
//create http client and query for resutls
WorkItemTrackingHttpClient witClient = connection.GetClient<WorkItemTrackingHttpClient>();
Wiql query = new Wiql() { Query = "SELECT [Id], [Title], [State] FROM workitems WHERE [Work Item Type] = 'Bug' AND [Assigned To] = #Me" };
WorkItemQueryResult queryResults = witClient.QueryByWiqlAsync(query).Result;
Maybe you can consider using a limited PAT, limit its scope to Code only:
I know there exists other Authentication mechanism
:
For Interactive JavaScript project: ADALJS and Microsoft-supported Client Libraries.
You can give it a try but I'm not sure if it works for you since you're not using real Code way to access the Azure Devops Service... Hope it makes some help :)
If you have the script set up in an Azure Runbook you can set it as an encrypted variable there and have it pull it from there before running rather than having it directly written into the code.
$encryptedPatVarName = "ADO_PAT"
$adoPat = Get-AutomationVariable -Name $encryptedPatVarName
$adoPatToken = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($adoPat)"))
$adoHeader = #{authorization = "Basic $adoPatToken"}
The above is the Powershell version of it. I have seen some people do it with other

Send email from React application

I have an application, built using React. If I want to send an email to a user after another user successfully completes an action, what are some technologies I need to or can use? To clarify, I have no backend server set up yet.
Check sendgrid! You can do in your backend(nodejs in this case):
const SGmail = require ('#sendgrid/mail')
SGmail.setApiKey(process.env.REACT_APP_SG_API)
app.post('/your/endpoint', (req,res) => {
const data = req.body
const mailOptions = {
from: data.email,
to:'email#example.com',
subject:'Subject',
html:`<p>${data.name}</p>
<p>${data.email}</p>
<p>${data.message}</p>`
}
SGmail.send(mailOptions).then((err,res)=>{res.redirect('/')})
})
Check out SendGrid, they offer a generous free tier.
If you're not expected to do the actual email sending, you could, in JS, build an .eml file and have the user "download" it. They would then send it in their client of choice.
Otherwise you will need, at the very least, access to a mail server, to send this multipart-mime to, or, a little safer, build the message on the server and send it internally.

Parse Server Node.js SDK: Alternative to Parse.User.become?

I want to completely dissociate my client app from Parse server, to ease the switch to other Baas/custom backend in the future. As such, all client request will point to a node.js server who will make the request to Parse on behalf of the user.
Client <--> Node.js Server <--> Parse Server
As such, I need the node.js server to be able to switch between users so I can keep the context of their authentification.
I know how to authentificate, then keep the sessionToken of the user, and I ve seen during my research than the "accepted" solution to this problem was to call Parse.User.disableUnsafeCurrentUser, then using Parse.User.become() to switch the current user to the one making a request.
But that feels hackish, and I m pretty sure it will, sooner or later, lead to a race condition where the current user is switched before the request is made to Parse.
Another solution I found was to not care about Parse.User, and use the masterKey to save everything by the server, but that would make the server responsible of the ACL.
Is there a way to make request from different user other than thoses two?
Any request to the backend (query.find(), object.save(), etc) takes an optional options parameter as the final argument. This lets you specify extra permissions levels, such as forcing the master key or using a specific session token.
If you have the session token, your server code can make a request on behalf of that user, preserving ACL permissions.
Let's assume you have a table of Item objects, where we rely on ACLs to ensure that a user can only retrieve his own Items. The following code would use an explicit session token and only return the Items the user can see:
// fetch items visible to the user associate with `token`
fetchItems(token) {
new Parse.Query('Item')
.find({ sessionToken: token })
.then((results) => {
// do something with the items
});
}
become() was really designed for the Parse Cloud Code environment, where each request lives in a sandbox, and you can rely on a global current user for each request. It doesn't really make sense in a Node.js app, and we'll probably deprecate it.
I recently wrote a NodeJS application and had the same problem. I found that the combination of Parse.User.disableUnsafeCurrentUser and Parse.User.become() was not only hackish, but also caused several other problems I wasn't able to anticipate.
So here's what I did: I used
Parse.Cloud.useMasterKey(); and then loaded the current user by session ID as if it was a regular user object. It looked something like this:
module.exports = function(req, res, next) {
var Parse = req.app.locals.parse, query;
res.locals.parse = Parse;
if (req.session.userid === undefined) {
res.locals.user = undefined;
return next();
}
Parse.Cloud.useMasterKey();
query = new Parse.Query(Parse.User);
query.equalTo("objectId", req.session.userid);
query.first().then(function(result) {
res.locals.user = result;
return next();
}, function(err) {
res.locals.user = undefined;
console.error("error recovering user " + req.session.userid);
return next();
});
};
This code can obviously be optimized, but you can see the general idea. Upside: It works! Downside: No more use of Parse.User.current(), and the need to take special care in the backend that no conditions occur where someone overwrites data without permission.

how to nest access tokens in javascript safely?

FB.api({user-id},
{
"fields":"context",
"access_token": anAccessToken
}, function (response) {
console.log(response);
})
I am currently getting mutual friends via the context object. But in order for that to happen, I need to pass both the app_scoped_userid and my accesstoken from Oauth.
I feel uneasy putting these two strings in my client, since together anyone can use them to query any information the user has allowed my app permission to use.
Is there a better solution? (I have been contemplating moving the graph call onto the server, but that works against the light server-heavy client structure I am trying to achieve.)
Am I right to be worried?
I don't think that it's correct how you're using this functionality. According to https://developers.facebook.com/docs/graph-api/reference/v2.2/user.context/mutual_friends you should be able to run the following request:
/{friend_id}?fields=context{mutual_friends}
The Access Token (from the currently logged-in User) should be handled transparently by the JS SDK. I see no need to specify it for the request:
FB.api('/{friend_id}?fields=context{mutual_friends}', function(response) {
console.log(response);
});
To the the {friend_id}, you'll need to query /me/friends first for the current User, and select a specific friend.

Categories

Resources