Prevent Download Via URL - javascript

I currently have a PHP file asks you to login using a MySQL database. Once logged in, 3 links appear allowing me to download files. Although, if I access the file directly it will download without having to login. How would I prevent people from downloading via the URL bar, but still allow JavaScript to download the file?
If this isn't possible, is there something else I can do to allow download? For example, using PHP to download instead of JavaScript? I know JavaScript is client side, so I wonder if that will prevent it from accessing the download.
I can't really give much code, but here is the JavaScript that downloads it. The link basically calls the downloadLink function;
var downloadURL = function downloadURL(url) {
cLog("STDOUT: Attempting Download Of File: "+url);
var hiddenIFrameID = 'hiddenDownloader',
iframe = document.getElementById(hiddenIFrameID);
if (iframe === null) {
iframe = document.createElement('iframe');
iframe.id = hiddenIFrameID;
iframe.style.display = 'none';
document.body.appendChild(iframe);
}
iframe.src = url;
};
function downloadLink(fileLink) {
if (fileLink) {
cLog("STDOUT: File Link: "+fileLink);
downloadURL("/DownloadAssets/"+fileLink);
cLog("STDOUT: Function Finish, File Should Be Queded");
} else {
cLog("ERROR: No File Link");
}
}

Basically, you can't.
An HTTP server has absolutely no idea whether any given HTTP request is coming from the browser URL bar, an iframe in a page or from Javascript code. They are all just HTTP requests.
If you want to allow some types of access and prevent other types of access, then you have to implement access control on your server so that the HTTP request is not fulfilled unless the proper credentials are provided.
The challenge with the browser environment is that pretty much nothing in your client side code is secure (it is all available for inspection by anyone) so a determined hacker will be able to find any secret codes you put in your client-side javascript to be used as credentials and they can then use them whenever.
I can't tell exactly what you're really trying to do, but sites that want to provide downloads to only certain users, often do something like this:
Make the user login to your site
This provides a unique user ID in their cookie that comes with all HTTP requests from that user.
Then coin a unique download URL with some unique codes in it.
In your own database server-side, create a record that associates those download URL codes with the user ID that they belong to.
When an HTTP request comes in for that unique download URL, your server extracts the download codes from the URL, extracts the userID from the cookie with the request, looks the codes up in the database and check is this is the correct userID for those codes.
If they match, the server serves up the appropriate download file.
If they don't match, the server serves up a file advising the user that they are not authorized to download that file and instructs them what they have to do to obtain authorization.
A server will typically expire these download codes after some short period of time (e.g. a few days) so they can only be used in the short term.
This technique makes it so there is no universal download link that every one can use and it prevents one user from sharing the download link with other users.
This technique will not attempt to discern the difference between someone typing a request in a browser URL bar vs. one coming from an iframe or one coming from a Javascript request and generally, there should not be a need to know the difference. Any content that can be gotten any of these ways can be used the same so there is no real security benefit to allowing only one way and preventing the others.

This isn't really something you solve with javascript, since that is run client-side. When you have users login, you would need to place a cookie in their jar that signifies that they've logged in. On your webserver, only allow people to access that URL that have that auth cookie.

First you need some 'login system' to your site. Then you need Apache web server (or other that handle 'rewrite mod' rules, but in Apache configuration is super simple [just craete .htaccess file]).
All you need to do is to block access to files in folder with files (and give it only to logged users).
Create file .htaccess (hard to do on Windows [that name of file], try to download that file from internet) in folder with files to download with content:
http://paste.ots.me/562452/text
(this .htaccess file should redirect all HTTP requests to that folder to file download.php )
Create download.php file with content:
http://paste.ots.me/562451/text
// for unknown reason I cannot paste code in post.

Related

Protect your DOM's href safe from curious eyes [duplicate]

This question already has answers here:
How to disable View source and inspect element
(4 answers)
Closed 3 years ago.
I am having a display page where is shows all our reports like this,
On mouse over it shows the file url (where it is located in our server).
I want to protect this from users.
What is tried is this,
<li><a data-href="'.$value->uri.'">'.$value->filename.'</a></li>
and call script when click to download the file:
<script>
$("a").click(function(event){
var href = $(this).data("href");
window.location.href=href;
});
</script>
But still users can inspect and see url.
Is there any way to hide url from users?
Aside from the security implications of trying to enact a system like this (i.e. the level of security is hiding the href), as you've tagged PHP you could setup an endpoint in PHP that returns a 302 redirect for an href that redirects to the object on your server.
Use a DB to save the mapping of the 'public' href value that you see on mouseover and in the inspector, then when you hit this URI on your PHP server, look up the mapped resource and return it (if the user is authenticated).
First, never show server path in the URL.
Second, make these links href as /download_file.php?file_name=your_current_file_name.
Third is to have a script on server side, like download_file.php which gets the file name, searches in it's directory for the file and downloads them on the client browser.
Fourth is to hide this behind the authentication that only logged in users could see it.
Fifth, you could have a database table of each file against a user to make sure that other users don't get access to someone's file. As an alternative, you could also make folders based on user_id to make it easier to get the parent directory to search through, as you could get current logged user from session.
Always store uploaded files outside of your public_html so that they aren't accessible from the web, except from your server scripts.
Side note: Storing user ID in session is fine with regards to security. See here: php storing user id in session?
Note: Disabling inspect element is really not the right way to handle this.

Set cookie while loading remote js in the domain where js is hosted

Below is the scenario am looking at:
I am remotely loading a js file to the site hello.com.
The js is loaded from jsfoo.com.
I want to set a cookie for the domain jsfoo.com in the users browser when the user the is visiting hello.com?
Is it something possible from within the js file that is loaded or do I have to write a server side logic when loading the js?
The objective is to retarget the user who visited hello.com when the user vists jsfoo.com later.
Update based on the comment below:
Would it possible if js is loaded dynamically? For example if we load the js via a dynamic url like jsfoo.com/getjs.php?js=sample.js. Wouldn't it be possible for the code to set and get the cookies for jsfoo.com via php code?
The JS code is executed under your domain, so you can not set that cookie client-side. This is only possible if the script resource loaded from the other domain sets a cookie for that domain via the HTTP response header.
And you won’t be able to access the cookie of jsfoo.com in hello.com. If you need the existing value, then your script on jsfoo needs to read it when the request to its domain happens, and return the value in a way that JS can read it (f.e. by outputting it as a JS variable.)

Acrobat Javascript: passing a UTM parameter from URL into a PDF button

I have a PDF that has a button with field name ctaButton.
ctaButton currently has a url pointing to https://mywebsite.com.
I want to host the PDF on my server at https://mywebsite.com/hosted.pdf.
And when I send someone a link to the PDF, I want to attach a UTM_term parameter ?utm_term=customer1 and then have the PDF read this parameter and update the ctaButton url to https://mywebsite.com/?utm_term=customer1.
I've been messing around with the Javascript actions in Acrobat for a couple of hours trying to make this happen. Any help greatly appreciated.
You can get the full url to the document using...
var myURL = this.url;
"this" in Acrobat JavaScript is the document context.
I did hours of research and came to this conclusion – Javascript in Acrobat is like trying to code in 1985 AND browsers will not execute whatever code you come up with.
So I used this workaround:
When I send the PDF to someone, I send it as a link with a base64
encoded stringified JSON package that contains a bunch of tracking
data but importantly, the name of the file to access as well as utm
parameters specific to the recipient
The link hits a server handler (NodeJS) that extracts the encoded
JSON package, and uses the data in the package to serve up an HTML
redirect page pointing to the right PDF file
Importantly, the HTML page also saves the JSON package to the
browser's localStorage . . . this comes in handy in subsequent
steps
The PDF file opens in browser (it doesn't have to, could be opened on
desktop) and the call to action link has a link to a get request
handler
The get request handler serves up ANOTHER redirect page
This second redirect page accesses the browser's local storage, looks
for the utm parameters I set for that user, and then redirects to the
sale page, with nice utm parameters attached
So to sum up, you don't add the utm parameters to the call to action link in the PDF (because that would make the world too easy to live in) and instead you do all these acrobatics (no pun intended) to attach utm parameters in the link clicks (via JSON strings saved in localStorage) during the process (i.e. when user opens email to extract file via link, and then when user clicks call to action in the PDF).
Any questions or clarifications please let me know in the comments and I will do my best to address.
Caveats
Only works if user uses same browser in all steps (i.e. if Susan opens the email in Safari, saves the PDF, then clicks the call to action in the PDF, and the link opens in Chrome, utm parameters will not be passed).
Assumes browser is modern and has localStorage
UPDATE: I came across another solution. It's a bit more convoluted. Diagram below.
Porky.io is a Javascript extension for Adobe Indesign. So flow is:
send Porky.io the customer data you need (e.g. utm's for links)
Porky.io generates PDF from a template you provide with the customer data you provided
Listen for a new file save from Porky
Do something with the file (e.g. email it to customer)
I believe you need to run an instance of Windows somewhere in the cloud (e.g. on Azure) to run Indesign with the Porky.io. Unless you want to rely on your laptop.
My project's not big enough yet to warrant setting this up . . . but good alternative if I need to make my current solution more robust.

How to collect client data when we redirect using 301 redirect?

There is a system like Clickmeter that allows people to create a smart link for their banner ads. Here is a short explanation of the system. You can enter a URL as the landing page and system gives you back a special URL to put instead of the original. Now if someone clicks on the special link, he will be redirected to the landing page that you wanted to.
I am developing something like that but here is the trouble. I must use 301 redirect because of some SEO things, and 301 redirect is only available in server side as I know. But I want to get some client data such as browser name, operating system model and browser language before redirecting the client. And I am doing this part in javascript, absolutely client side.
I dont know what to do or if I am wrong about something else. But I know that Clickmeter is doing exactly the thing that I want to. They get some client data and then do 301 redirect. Here is a sample link of CLickmeter: http://9nl.it/vz0d
You don't get the client's data in the client's side. You do it in the server side by reading and processing the Request.UserAgent before doing the 301 redirection:
// get the User Agent
string userAgentText = HttpContext.Current.Request.UserAgent;
// Process the User Agent, and extract the information you want: browser, OS, version...
...
// Make the 301 redirection to the target URL programmatically
HttpContext.Current.Response.Status = "301 Moved Permanently";
HttpContext.Current.Response.AddHeader("Location", TARGET_URL);
You could get similar information in JavaScript by using window.navigator.userAgent (and AJAX to send the data on click), but I would not recommend this solution for two reasons reasons:
If you are providing just a URL (your service sounds like a URL shortener), you cannot inject the JavaScript code.
If the user has JavaScript disabled, this solution will not work at all.
To find more information on how this could be done, read these questions:
How do I get just the OS from Request.UserAgent?
What is the difference between Request.UserAgent and Request.Browser?
301 redirect in asp.net 4.0
How can you detect the version of a browser? (if you still decide to go with a JS approach)

How can PHP driven API authenticate genuine client (referer) cross-domain (knowing that headers can be spoofed)?

Using PHP, how do you securely authenticate an API call, cross-domain, with the following criteria:
Must be called from a given domain.com/page (no other domain)
must have a given key
Some background: Please read carefully before answering...
My web application will display a javascript widget on a client's website via a call like the one below. So we're talking about cross-domain authentication for a script to be served but only to genuine client and for a given URL only!
At the moment the widget can be included by the CLIENT's website, by a single-line of javascript.
Example client-website.com/page/with/my-widget
<head>
...
<script src="//ws.my-webappserver.com/little-widget/?key=api_key"></script>
...
</head>
Now, in reality this does not call javascript directly but a PHP script on my remote server which sits in front of the actual javascript for the purpose of doing some authentication.
The PHP script behind the above call does this first:
checks that API key ($_REQUEST["key"]) matches the user's record in the database.
checks the referrer's URL ($_SERVER['HTTP_REFERER']) against the a record in the database***.
This is simplified, but in essence the server looks like:
if ($_SERVER['HTTP_REFERER'] !== "http://client-website.com/page/with/my-widget")
&& $_REQUEST["Key"] == "the_long_api_key") {
header("Content-type: application/x-javascript");
echo file_get_contents($thewidgetJS_in_secret_location_on_server);
} else {
//pretend to be a 404 page not found or some funky thing like that
}
***The widget is only allowed to run on CERTAIN websites/pages
Now, here's the problem:
the key is on the client side so anyone can view source and get the key
referrers can be spoofed (by cURL) for example
And a little snag:
I can't tell the clients to stick the key inside a php script on their server because they could be running any server side language!
So how can I make my web service secure and only accessible by a given domain/page?
Any help would be really appreciated!
ps: The widget does some uploading to a kind of drop box - so security is key here!
id recommend using a whitelist approach to this issue, i am not entirely sure this will solve the problem however i have used a similar technique for a payment processor which requires you to whitelist server-ips.

Categories