Detect form submission on a page - javascript

I have a vue app that sits behind a firewall, which controls user authentication. The only way that I have of detecting when the user needs to re-authenticate is when the axios requests sent by my app receive a 403 error. When this happens the server also returns a web page, which I see as, error.response.data. This page asks the user to re-authenticate via an embedded form that, when completed, authenticates the user and sends back the output from my app's original request.
My questions is how can I get the user to re-authenticate and then capture the data from my request that is returned? I can send the user the authentication page, for example by using:
var login_window = window.open('about:blank', '_blank');
login_window.document.write(error.response.data)
login_window.focus()
but then I don't see how to determine when the user has authenticated. When this happens, login_window.document.body.innerText contains the json data from my app's request, which my apps needs but which I don't want to show to the user. When doing this "by hand", I also have not succeeded in extracting the json from login_window.document.body.innerText as the json structure has been stripped and it now looks something like this:
JSON
Raw Data
Headers
Save
Copy
Collapse All
Expand All
status \"OK\"
message \"\"
user \"andrew\"
This question tries to reduce my previous question down to a javascript problem. There may be a better way to do what I want using axios; see Handling an authentication page returned by an axios request in vue for more details.

One solution is to override the <form>'s submit-event handler, and then use XMLHttpRequest to submit the form, which gives you access to the form's response data and status code. A status code of 200 implies that the user is authenticated, and the response data should contain the response of the original request before authentication.
Steps:
Query the form's container for the <form> element:
const form = document.querySelector('#container > form').querySelector('form')
Add a submit-event handler that calls Event.preventDefault() to stop the submission:
form.addEventListener('submit', e => {
e.preventDefault()
})
Use XHR to send the original request, adding your own response handler to get the resulting data:
form.addEventListener('submit', e => {
e.preventDefault()
const xhr = new XMLHttpRequest()
xhr.addEventListener('load', e => {
const { response } = e.target
const data = JSON.parse(response)
// data now contains the response of the original request before authentication
})
xhr.open(form.method, form.action)
xhr.send(new FormData(form))
})
demo

Related

How to retrieve the Request data from Post request that is triggered by Javascript

I am new to test Javascript. and the test is like this,
Load a page, then the Javascript is triggered, it fills the request payload data and then trigger the POST request with the generated payload data. My test need to validate the payload data are right.
My problem is in the Chrome developer tool, I can see the POST request with Request Payload data. But I don't know how to get the Request payload data with any automation test tool or any other way.
It's pretty simple with something like Cypress.
You can view the docs how to setup Cypress:
https://docs.cypress.io/guides/getting-started/installing-cypress
The test itself can be something like:
it('Should log the request body', () => {
// start by intercepting the request
cy.intercept('POST', '**/endpoint').as('interceptedRequest')
// visit your url, and do some actions to trigger the request
cy.visit('http://yoururl.com')
// wait for your request to trigger
cy.wait('#interceptedRequest')
.its('request.body')
.then((body) => {
console.log(body)
})
})

How can I make a request and NOT wait for response before redirecting?

I'm using Axios in a Vue app. I would like to send a request to my backend (to log the click of a button) but not wait for the response and then redirect the client to another page. Right now, the request is made, the redirect happens right away, and the initial request is 'cancelled' and my backend doesn't process the request.
I'd like to just fire off that request, then redirect AND NOT cancel the initial request. How can I do that?
Thanks all for the comments. Seems sendBeacon seems like it's been nerfed as you cannot send application/json for content type, and it this article says it is not reliable. So I used the following solution in my Vue component:
onClickLink: async function () {
var img = new Image()
img.src = `/my/path/to/controller/${this.$route.params.id}`
window.location.href = externalLinksFile.new_url
}

Insert data in response of Message class in c#

I need to insert in a response information in the body of this with c#.
Currently I have a function that inserts a custom message in an HttpResponseMessageProperty object which is validated from the web client observing response.statusText.
When accessing from https we discover that this data is not being sent since the requests are being made from http \ 2.
Instead of how we are sending it, I would like to know in what way I could send that data through the body.
The following code works with http 1.1. And response is of class Message
if (message.Length > 0) {
property.StatusDescription = message
}
response.Properties[HttpResponseMessageProperty.Name] = property;
Later that Message object is returned through RequestContext Reply.
How can I include data that I can later read from response.data in javascript?
Thank you all
EDIT:
I'm using Net Framework 3.5

How NOT to send back a response to ajax post call in node.js?

I have an ajax post call and I want to just send the form values without waiting for a response to come. I want to redirect from my express app and not form my client side. server-side:
router.post("/", (req, res)=>{
res.status(200).send(`signup/confirm-email?v=${req.body.email}`);
// i want to be able to rediect with res.redirect("signup/confirm-email?v=${req.body.email}")
};
});
client-side:
$.post('/signup', $('#signup-form-container form').serialize())
.done(lnk=>{
window.location.replace(`${window.location}${lnk}`); })
.fail(function(xhr){ //handle errors };
The code above works, it sends a response to ajax and then i redirect from client side.
I want to redirect from server-side.
I tried to redirect from my express app using res.redirect() but it doesn't work without logging any errors to the console and in the network tab in the dev tool, it shows that the request type is xhr. If there isn't a solution to this problem, than is there a way to hide the query in the route recieved. I don't want v=${req.body.email} to be displayed in the url bar. Thank you in advance.
The point of Ajax is that the request is made by JavaScript and the response is handled by JavaScript.
If you return a redirect response, then JavaScript will follow the redirect, make a new request, and handle the response to that.
If you don't want to handle the response with JavaScript: Don't use Ajax. Use a regular form submission instead.
Avoid using jQuery, it will almost always lead to bad practices and unmaintainable code.
You should use plain Javascript or React if you need a framework (which is mainly if you need to work on a big project, but may not be suited for total JS beginner). My solution here is in plain Javascript.
As a replacement for the jQuery request util ($.post(), etc ...), browsers have a very good HTTP request API named fetch (MDN). I use it in this solution.
If you don't want to show the email param in the URL, you can set it in the localStorage.
You cannot redirect directly from Express for a POST method. Only if you were trying to GET a page, Express could redirect to another GET (and so change the URL in your browser).
The only solution to your need is to use the window.location after receiving the response from your /signup endpoint.
Server-side:
router.post('/', function (req, res) {
const form = req.body.form
// your registration code here
// ...
res.json({
success: true,
email: form.email
})
})
Client-side:
signup.js
const form = {
email: document.getElementById('email').value
// add other fields you need
}
fetch('/signup', {
method: 'POST',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({ form })
})
.then(res => res.json())
.then(res => {
// Set the localStorage item so you can get it back
// in the JS script of /signup/confirm-email
localStorage.setItem('email', res.email)
// Redirect to the confirm email page
window.location = '/signup/confirm-email'
})
Client-side:
confirmEmail.js
const email = localStorage.getItem('email')
if (!email) window.location = '/signup'
// proceed with your code
Code for this answer

Stop Malicious POST requests

I have an AJAX function that makes call to a page on my website.
$(document).on('click', thisIdentity, function() {
var trigger = $(this);
var items = trigger.attr('data-values').split('_');
$.ajax({
type: "POST",
url: "/mod/mypage.php",
data : { pid : item[0], uid : item[1] },
dataType: "json",
success: function(data) {
if(data.job == 1) {
// do something
}
}
});
});
Now this works fine and do as intended. However, if I use any third-party app like POSTMAN and make a POST request to www.xyz.com/mod/mypage.php with parameters pid : 1 and uid : 2. It still goes through and make changes to my database.
Is there anyway to check that request is generated from my
domain/server only?
How to stop such POST requests outside from my domain?
One thing I thought was to generate a token and set in SESSION before this request and check in mypage.php that if token is set or not. Is this a feasible way?
This is exactly what a CSRF token is for. Users must navigate to the page first, which generates a token to submit, ergo without navigating to the page will render any POST requests invalid.
However, trying to stop someone from POST'ing a request to your endpoint from a utility like POSTman is an exercise in futility. You must authenticate every request to the endpoint, in this case just check the photo id is owned by the submitting client.
OWASP provides a decent description of what a CSRF is:
Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they're currently authenticated. CSRF attacks specifically target state-changing requests, not theft of data, since the attacker has no way to see the response to the forged request.
Example validation flow
Login.php
<?php
// Establish DB connection, validate
$_SESSION['id'] = $db->getUserId();
$_SESSION['admin'] = $db->getAdminStatus();
Delete.php
<?php
if (!$db->isPhotoOwner($_POST['pid'])) {
exit;
}
// Delete photo flow
Admin.php
<?php
if (!$_SESSION['admin']) {
die("Not admin.");
}
// Do admin action or whatever
You could have the calling page identify itself with $_SERVER['SCRIPT_NAME'] and write that value to a hidden input field or $_POST and check for it at the beginning of processing. Any confirmed value you choose might work.
If they are already imitating the data of your JSON, then maybe drop it into the javascript with PHP dynamically writing the code value on page serving.

Categories

Resources