Best practices for HTTP 400 response security - api

For example we have REST endpoint (or even simple endpoint). Someone passes incorrect payload and receives 400 error code in response.
How detailed response should be in case of some field exceeded it’s expected length from the security point of view? Should we open validation details to user and return in a message field something like: “You exceeded length of zip code. Max value is 5. ” Or details should be hidden from user and HTTP status code should be enough?

On the client-side use handy validation messages such as "The ZIP Code must have 5 digits"
On the server-side respond with an empty 400
https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html#error-handling
For example:
const AuthError = 1
const ValidationError = 2
const isId = value =>
isString(value)
&& value.length === StandardIdCharLength
&& /^[\w-]*$/.test(value)
async function resetPasswordPost(request, response) {
try {
const body = await jsonBody(request) // throws ValidationError
if (!(
body
&& Object.keys(body).length === 3
&& isPassword(body.password)
&& isId(body.userId)
&& isId(body.token)
))
throw ValidationError
if (!await passwordResetTokenExists(body.token, body.userId))
throw AuthError
// …
sendOk(response)
}
catch (error) {
switch (error) {
case AuthError:
sendUnauthorized(response)
break
case ValidationError:
sendBadRequest(response)
break
default:
sendInternalServerError(response)
}
}
}
function sendBadRequest(response) {
response.statusCode = 400
response.end()
}

Related

How to check http status code in vuejs and return value

I need to check the status code in vuejs, whether is it 200 or else. Here is my code, but i have errors.
methods:{
userSearch(){
let searchUrl = dataUrl+this.usersearch;
fetch(searchUrl).then(statusCode => {
if(statusCode == 200){
message = "Not Available"
$("#availability").innerHTML = message
}
else {
message = "Available"
$("#availability").innerHTML = message
}})
this should return in my p element with id="availability" whether the user is available or not, depending on the status code. I am calling this method in the input field on enter.
As #deceze pointed out, the fetch function resolves to a Response Object.
You can see here how to properly handle the HTTP status of the response.
But, for your code, it should be something like this:
userSearch() {
let searchUrl = dataUrl+this.usersearch;
fetch(searchUrl).then(response => {
if(response.status == 200){
message = "Not Available"
$("#availability").innerHTML = message
}
else {
message = "Available"
$("#availability").innerHTML = message
}
})
}
As just part of the code was provided, there might be other causes for the error, that I cannot see with just this snippet.

Cloudflare Worker Breaks Redirects On Site

I have a cloudflare worker that will insert custom CSS into the page if the country is not U.S/Canada. This works perfectly, however - it will break all redirects when the CSS is inserted. Attached below is the worker scripts
addEventListener('fetch', event => {
event.passThroughOnException()
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
const country = request.cf.country
if (country != 'US' && country !='CA') {
const response = await fetch(request)
const type = response.headers.get("Content-Type") || "";
if (!type.startsWith("text/html")) {
return response;
}
var html = await response.text()
// Inject scripts
const customScripts = 'styling here'
html = html.replace( /<\/body>/ , customScripts)
// return modified response
return new Response(html, {
headers: response.headers
})
}
}
The redirects are broken because they use a special HTTP status code (usually 301 or 302), but your Worker code is not copying the status code over to the final response, so the final response ends up always having a 200 status code.
Try changing this:
return new Response(html, {
headers: response.headers
})
To this:
return new Response(html, response)
This way, the new response copies over all of the properties of the old response, except for the body. This includes the status property, so the status code will be copied over.
By the way, unrelated to this problem, I notice another issue with your code:
if (country != 'US' && country !='CA') {
It looks like if this condition evaluates to false (that is, if country is either 'US' or 'CA'), then your handleRequest() function doesn't return a response at all. In this case, an exception will be thrown, and the client will see an 1101 error page. I recommend adding an else clause that returns the response that you want users in the US and Canada to see.

Testcafe checking api response always passes

I have a testcafe test that checks API response JSON for a matching string and no matter what is in the response JSON, the test always passed.
I am running Gherkin/Testcafe integration. Last "Then" step is to check an API response JSON body.
logger = RequestLogger(config.serverUrl + '/api/v1/service', {
logResponseHeaders: true,
logResponseBody: true,
});
await t
.addRequestHooks(logger)
.navigateTo(config.serverUrl + '/admin/integrations')
.expect(logger.contains(record => record.response.statusCode === 200))
.ok();
await t
.expect(
logger.contains(async record => {
// console.log(record.response.headers);
const body =
record.response.headers['content-encoding'] === 'gzip'
? await getBody(record.response.body)
: record.response.body.toString();
const bodyJson = JSON.parse(body);
return bodyJson.filter(node => node.title === "Devtest").length == 1;
})
)
.ok();
In the end, the code should return true/false depending on finding/not finding at least one item containing "Devtest".
However, the test always passes no matter what is the number.
RequestLogger doesn't support the async function for the predicate parameter of the containsfunction.
So, this expectation always passes - await t.expect(logger.contains(async record => false)).ok().
To fix the problem I suggest you split your code into two pars:
const record = request.records.find(r => ...);
const body = record.response.headers['content-encoding'] === 'gzip'
? await getBody(record.response.body)
: record.response.body.toString();
const bodyJson = JSON.parse(body);
await t.expect(bodyJson.filter(node => node.title === "Devtest").length === 1).ok();
I also see that the capability to automatically unzip response bodies can simplify your test code. If you have time you can try to implement this feature and open a pull request in the TestCafe repository.

rxjs throwing an error once http request returns a specific value

I did write an Observable which is polling an URL which completes once a specific value is returned.
private checkPairingStatus(paringModel: any): Observable<ResponseObject> {
let data = { id: 1234 };
return Observable
.interval(2000)
.switchMap(() => this.get<ResponseObject>('http://api/getstatus', data))
.first(r => r.Status === 'success') // once our pairing is active we emit that
.timeout(90000, Observable.throw(new Error('Timeout ocurred')));
// todo: find a way to abort the interval once the PairingStatus hits the 'canceled' status.
}
This works pretty fine but I'm struggling on how to throw an exception once my respone for example hits the following status "r.Status === 'canceled'".
Thanks for any hint on that!
Regards
Lukas
You can just use do() and throw an Error with whatever condition you need:
return Observable
.interval(200)
.do(val => {
if (val == 5) {
throw new Error('everything is broken');
}
})
.subscribe(
val => console.log(val),
err => console.log('Error:', err.message)
);
This prints to console:
0
1
2
3
4
Error: everything is broken
In your case you'll want to test a condition such as r.Status === 'canceled' or whatever.

How can I see the HTTP status code from the request made by page.open?

I have a phantomJS script that contains the following:
page.open(url, function (status) {
if (status === "fail") { /* handle failure */ }
});
The status check works sometimes, but the status will still be "success" even if the request returns 500. How can I get the actual request status code?
You can do it something like this:
var page = require('webpage').create(),
system = require('system'),
resources = [];
page.open('http://google.com', function (status) {
console.log('Loaded with http status:', resources[0].status);
phantom.exit();
});
page.onResourceReceived = function(response) {
// check if the resource is done downloading
if (response.stage !== "end") return;
// apply resource filter if needed:
if (response.headers.filter(function(header) {
if (header.name == 'Content-Type' && header.value.indexOf('text/html') == 0) {
return true;
}
return false;
}).length > 0)
resources.push(response);
};
So, if you need to check the status of the first browser's request (in this case google's html page) you should see it as the first one returned in resources[0].status. In onResourceReceived handler you can add more filters for resources you try to get http code from.
UPDATE: thanks to #fotijr, added a check for completed responses
In
page.property('onResourceError', function(res) {
resources variable is undefined,
even if I set it with
var page = require('webpage').create(),
system = require('system'),
resources = [];