check that requests come the web and not manual - javascript

I have a simple autocomplete script in js that takes what the user type, send it to the server and the server checks for data that resembles it. working great.
$(".name_autocomplete").autocomplete({
serviceUrl: '/names',
onSelect: function (suggestion) {
$(this).value = suggestion;
}
});
But since that server endpoint is public, I don't want users to abuse it and have it spit out everything by bruteforce
Is there a way (in clientside or server side) to limit the requests for that url only from the website on that specific page and not from things like curl?

Simplest option would be to drop connections without a user-agent string (similarly with user agent strings that belong to known bots). Of course, if your users are clever enough to use curl, they probably know how to use a fake user agent with it (by default curl won't send a user agent string), so this will only thwart the casual busybody.
For nginx:
if ($http_user_agent ~ (agent1|agent2) ) {
return 444;
}

Maybe HTTP-Access-control can help you in combination with a well set user-agent:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
You can control the origin domain and decide, which domain is allowed to access and which not.

Related

Restrict PHP API for specific domains which are saved in my database

I have created an API which takes the hostkey or API_KEY and then it validates and gives back JWT token. Everything is working fine, I can't access the restricted routes without Hostkey.
ISSUE
The major issue is that what will happen if someone gives this hostkey to others as it will no longer be protected or it will be misused. So what I want to do is not only validate the hostkey but also validate the domain from which request came from. It is kind of paid service and I really want to restrict is to specific domains. Just like google does with MAP Api as if we add that map key to other domain it throws an error.
The only way to do this is to check the origin and referrer headers.
Unfortunately, server to server this can't be done reliably as the referrer and origin headers would be set by the coder and so can be spoofed easily. For server to server calls you would be better off whitelisting IP addresses that are allowed to make calls to your APIS. In this case use something like How to get Real IP from Visitor? to get the real IP of the server and verify it against whitelisted IPs.
Assuming this is a JS call in browser and not server to server, and that you trust the browser, the only way this can really be done is by verifying the referrer and origin headers. This can still be spoofed with a browser plugin or even with a tool like Postman so I don't recommend it for high security. Here is a PHP example for verifying the origin or referrer.
$origin_url = $_SERVER['HTTP_ORIGIN'] ?? $_SERVER['HTTP_REFERER'];
$allowed_origins = ['example.com', 'gagh.biz']; // replace with query for domains.
$request_host = parse_url($origin_url, PHP_URL_HOST);
$host_domain = implode('.', array_slice(explode('.', $request_host), -2));
if (! in_array($host_domain, $allowed_origins, false)) {
header('HTTP/1.0 403 Forbidden');
die('You are not allowed to access this.');
}
Optionally also CORS headers are good as commented by #ADyson Cross-Origin Request Headers(CORS) with PHP headers
I would like to suggest making a quote or limit for the number of request, so when the paid API reach for 100 request the key will stop working, then the person who paid will not give the key for others. This is not perfect solution, but I would suggest it cause most API services uses it.

How do I limit access to my Netlify Serverless function

I've searched the netlify docs and I can't figure this out.
I have a serverless function located here
/.netlify/functions/orderCreate
But I can hit this in my browser or with curl and it tries to create an order. If an attacker finds out about this function they could create thousands fake orders in my db.
I know I can do some simple checks like make sure it is a HTTP post, or make sure it has some valid session ID but I would really like some type of auth or better security.
Because all requests should come from the a client side react app via an ajax request can I limit it to the same domain or something ?
As Netlify doesn't provide a way to check and specific requests based on origin, you could do it manually from inside your function's code and send a 403 response if the Origin isn't your client-side domain:
exports.handler = function(event, context, callback) {
if (event.headers["Origin"] !== "https://whateverisyourdomainname.netlify.com")
return callback(null, { status: 403 })
// else, do whatever your function does
}
Recent browsers do prevent a user from setting the Origin header himself. However, nothing prevents anyone to craft a curl request and to spoof the Origin header to hit your function. If you wish to really prevent it, you should set-up a proper authentication process to your application.

How to restrict API's to run only in the browser?

I am using node js and i put polices to restrict the api's accurance otherthan in browser.For that i put the following condition
app.route('/students').all(policy.checkHeader).get(courses.list)
exports.checkHeader = function(req, res, next) {
var headers = req.headers;
if ( headers['upgrade-insecure-requests'] || headers['postman-token']) {
res.status(401).json('Page not found');
} else {
return next();
}
}
I am not sure whether my process is correct.I am searching for the common parameter(header-parameter) that exists only for the browser.Can anyone please help me.Thanks.
This is impossible.
You can't control what types of clients make HTTP requests to your HTTP server.
You can't reliably identify what type of client has made a request you receive.
An upgrade-insecure-requests header can be sent (or not sent) with any value by any custom client. Ditto postman-token. Ditto user-agent. Ditto everything else.
The only way to restrict it would be to require some kind of secret in the request. If you want regular web browsers to access it, then the secret will leak through the browser developer tools.
I don't think it's possible to really block the requests without Authentication / Authorization. However, you can use the HTTP Header's User-Agent field
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

uploading images - do they have domain name in them - chrome not sending session id

For testing I downloaded images from the net and uploaded using valum file upload in chrome...chrome is not sending session cookie along with these request header( I dont see that in the server side/though I see it on developer tool)...does chrome know that these images are from different domain . what is happening...Is there work around for this to pass the session id (as cookie). It is also happening in IE10 which makes me belive it is some standard. and not just a chrome issue. This problem is not there with firefox/safari/opera
It is fine when uploading to localhost. only when uploading to different server with domain name there is this problem leading to creating a new session for this.
Update:
I have added xhr.withCredentials = true still no use.
Also added on the server side to the upload url...
res.setHeader 'Access-Control-Allow-Origin', '*'
res.setHeader 'Access-Control-Allow-Credentials', true
I dont know how helpful this would be, because I would have already sent the upload file and response header will not of much help.
basically the problem is I don't have access to the session variable at the server side, since the session id/sid cookie is not coming back /I am not able to save some of this upload details into the current session(because this is a new session) .
Update:
I tried creating an image in teh desktop using paint..even then chrome would not sent the cookies. Really drives me crazy...
First of all, to get the basics out of the way, this is unrelated to the origin of the image. Chrome or other browsers don't care where you get your images.
It's rather difficult to guess exactly what's going on, would have helped to see a jsfiddle or some more setup explanation, but based on what I'm guessing, you might be using different domains for the page where the upload button is hosted and the target url where you're sending your files (even using ssl for one and http for the other makes it different). Even different subdomains will not allow cookies to be passed if the cookies were not set with a base domain (yourdomain.com)
So, if sub-domains are the problem, you know what to do - set a base domain so you get your cookies to go on any sub domain.
If it's http vs. https you need to always use https (or http) because you can't switch cookies between those two.
If that's not it, or if you're using completely different domains, you can access your cookies locally via script (if they're not marked as http only) and add them to the upload request. Valum 2.0 (don't know about v1.0) lets you add parameters to the request like so:
var uploader = new qq.FileUploader({
element: document.getElementById('file-uploader'),
action: '/server-side.upload',
// additional data to send, name-value pairs
params: {
param1: 'value1',
param2: 'value2'
}
});
You can't set cookies on a domain which is not the page's domain via script so for using completely different domains your only choice is using request params.
It is possible that the uploader is using Flash under some circumstances to do the upload. There is a bug in Flash which prevents cookies being sent for these types of requests. This would explain the behaviour you are seeing. The workaround is to pass in the sessionId and transmit it in a different way eg. querystring.

How to do cross domain ajax in jQuery with dataType 'text'?

In my javacript function I call this ajax. It works fine but only when I access the web page from firebird server. I have the same code on my testing server. The ajax asks to download some files but only firebird server has its ip registers with our clients to be able to scp there. I need to do the same if I access the php files from testing server. All the servers are inside intranet.
is it possbile to use dataType text to do so?
do I need to do any changes on the server side?
ajax call:
url = "https://firebird"+path+"/tools.php?";
jQuery.ajax({
type: 'get',
dataType: 'text',
url: url,
data: {database: database_name, what: 'download', files: files, t: Math.random() },
success: function(data, textStatus){
document.getElementById("downloading").innerHTML+=data;
}
});
Update 1
My little web application restores databases so I can do my testing on them. Now I want to enhance it so I can connect to our customers and download a particular backup. Our customer allowed only firebird server to connect to their networks. But I have my own server dedicated to testing. So every time I want to download a database I need to connect firebird. The source of my web application and the folder with all backups are mounted into the same location on both servers firebird and testing. Right now my solution (for downloading) works but only from firebird. I work basically only testing server though.
Update 2
I make two ajax calls. One is pure jQuery call (I guess I can apply any solution to this one) and the other one is ajax call from jsTree. I created new question for that one. I seems to me that I have to go for #zzzz's option b).
To do cross domain requests, your options are fairly limited. As #Mrchief mentioned, you could do server side proxy and jsonp.
Another option is Cross-Origin Resource Sharing (CORS), a W3C working draft. Quoting from this blog post:
The basic idea behind CORS is to use custom HTTP headers to allow both
the browser and the server to know enough about each other to
determine if the request or response should succeed or fail.
For a simple request, one that uses either GET or POST with no custom
headers and whose body is text/plain, the request is sent with an
extra header called Origin. The Origin header contains the origin
(protocol, domain name, and port) of the requesting page so that the
server can easily determine whether or not it should serve a response.
You can find some live examples on this site.
You will need to make changes to the server side, to accept the CORS requests. Since you have control over the server, this shouldn't be a problem. Another downside with CORS is that, it might not be compatible with older browsers. So, if some of your essential audiences use incompatible browsers, the server side proxy may actually be a better option for you.
I just want to offer an alternative.
I am not too sure regarding your network setup, but if you have access to the DNS, maybe it would be easiest if you just give your servers some arbitrary subdomain of the same domain. Something like www.foo.com for the webfront and firebird.private.foo.com for the firebird server. This way, it becomes cross subdomain instead of cross domain. Then somewhere in your JavaScript on both pages,
document.domain = "foo.com";
This gentleman achieved this solution here.
You have the following options with you
a) You use jsonp type as your datatype but this involves making changes on the server side to pass the data back as json and not as txt.. this change might be as simple as
{
"text":<your current text json encoded>
}
and on your js side you use this as response.text; Having said that if you are getting the textis for you file from sm other domain I am not sure how easy it is for you to change the code.
b) The other option is you write a handler/end point on your server i.e within your domain that will make an HTTP request to this third domain gets the file and you send the file back to your client and effectively now your client talks to your domain only and you have control over everything. as most of yoyr questions are based on ruby here is an example:
req = Net::HTTP.get_response(URI.parse('http://www.domain.com/coupons.txt'))
#play = req.body
you can find more details about the same here.
Hope this helps.
Another idea is to use you web server as a proxy. You will need to consider the security implications for this route.

Categories

Resources