I have sensitive files to download to users, and each user is permitted to download a given file exactly once. If the download fails, I want to permit the re-download, but not otherwise.
It's not sufficient to rely on logging/processing the file download request at the server - I need to know deterministically when the file is complete and in place at the client, since many of my users work in an environment with frequent connectivity drops.
The most straightforward way for this to work would be if the browser exposed a "file saved" event from the Save As... dialog that could be wired to a JavaScript function on the download page (which could post back to the server). But, intuition suggests there might be security holes if browsers exposed this functionality, as it sneaks somewhat outside the sandbox. I'm not sure this is even possible.
I found several other questions in this area, but nothing about this problem specifically.
Any ideas?
Edit: I should not have used the word "security" in the original question, sorry for triggering the red herrings.
Edit 2: My "security" phrasing misled folks into offtopic technical security issues, but both of you confirmed my suspicion that "no, there's no browser support for that." I'm marking the first commenter with the answer since his first sentence had what I was looking for. Thanks all.
This is a good solution:
http://gruffcode.com/2010/10/28/detecting-the-file-download-dialog-in-the-browser/
It basically works by setting a cookie in the reponse header of the downloaded file, so javascript periodically can check for the existence of this cookie...
There's no such browser event in JavaScript and even if there was you can not trust the user's browser to provide security for you.
You're better off using a GUID to generate a unique URL for each download. You can then for example:
let the URL be valid only for a specific time period
allow transfers only from a specific IP address associated with the unique URL
let your server-side code detect when the content for a unique URL has been fully transferred and then invalidate the URL.
Let me clarify the last bullet. Say you're using Java - you will in.read(buffer) and out.write(buffer) in a loop until EOF. If the client disconnects you will receive an IOException during out.write() and will be able to tell a successful download from an interrupted one. On other platforms, I'm sure there are ways to tell whether the connection was lost or not.
EDIT: You could actually fire a browser event using the trick outlined in the accepted answer of one of the questions you linked to. That would however not be a reliable solution to limit the number of downloads.
Why is it important that the file can be downloaded "exactly once"? Once the file is downloaded it could be copied, so is there really a security issue with letting the same user download the file more than once?
If not, could you do something like this:
Generate a unique URL to download a given file. (Use a GUID to obsfucate if necessary)
Associate that URL with USER INFO (browser type, IP address, etc) AND A TIME WINDOW. Only allow downloads from that user and during the window.
The window should be long enough for the user to notice the transfer failed and to re-try once or twice, but no longer.
The end result is:
You can be reasonably sure the file is only being downloaded by the intended recipient.
You can be sure that recipient can only download the file during a short window.
The same user could download the file more than once, but who cares? It's no different than making a local copy of the first file.
If you're really worried about it, log each download request and run a scheduled report for files that were downloaded more than once. If anything looks fishy you can then examine security logs, talk to the user, etc.
Related
I have a program where the user does some actions (i.e. clicking on several buttons). I want to record their clicks and the buttons that they click to allow the user to then download a text file with a record of their clicks when they click a separate "download" button. I looked at the File-system APIs for HTML 5, but they seemed to not have cross-browser support. I would ideally like to have this entire file generation and download scheme be entirely client-side, but I am open to server-side ideas as well.
TL;DR: Essentially I'm looking for an equivalent to Java's FileWriter, FileReader, ObjectOutputStream, and ObjectInputStream within Vanilla JS or jQuery (would like to stay away from php, but I'll use it as a last option).
Also, why don't all browsers support the filesystem api? (I'm guessing that it would make MSWord and Pages go out of business with all the open source clientside text editors that could come out.)
Unfortunately the HTML5-File-system is no longer a part of the spec, long story short FF refused to implement because they claimed everything you could do in the File-System API was doable in the HTML5 Indexeddb (which was mostly true). Please see this blog post for more on why FF didn't implement. I do not know IE's story. (I may have exagerated why FireFox didn't implement, I'm still bummed because you cannot actually do everything in indexeddb that you can do in the noew "Chrome File-system API")
Typically if two of those three browsers implement a spec, it stays in the spec. Otherwise that spec gets orphaned. However, I'm fairly certain a large reason the file-system api didn't take off is because of the IndexedDB API (caniuse IndexedDB) really took off when both specs were introduced. If you want cross browser support, check this api out.
That all said if you are still set on the file-system api some developers wrote a nice wrapper around the IndexedDB, the File-system api wouldn't actually supply you with a stream anyway. You would have to keep appending events to a given file given a fileWriter object. you'd then have to read the entire file and send to the server via an ajax request and then downloaded from the server once successfully uploaded.
The better route would be to use the IndexedDB apiwhich as stated on developer.mozilla
Open a database.
Create an object store in upgrading database.
Start a transaction and make a request to do some database operation, like adding or retrieving data.
Wait for the operation to complete by listening to the right kind of DOM event.
Do something
with the results (which can be found on the request object).
Here are a couple tutorials on the IndexedDB.
https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB
http://www.html5rocks.com/en/tutorials/indexeddb/todo/
As for giving the user that file, as mentioned briefly before you would have to upload the file to the server and download upon the "download" request. Unfortunately you have to trick the user into giving them the data already on their machine. Anyway, hope this all helps.
The Context:
You have a web server which has to provide an exclusive content only if your client has your specific Chrome extension installed.
You have two possibilities to provide the Chrome extension package:
From the Chrome Web Store
From your own server
The problem:
There is a plethora of solutions allowing to know that a Chrome extension is installed:
Inserting an element when a web page is loaded by using Content Scripts.
Sending specific headers to the server by using Web Requests.
Etc.
But there seems to be no solution to check if the Chrome extension which is interacting with your web page is genuine.
Indeed, as the source code of the Chrome extension can be viewed and copied by anyone who want to, there seems to be no way to know if the current Chrome extension interacting with your web page is the one you have published or a cloned version (and maybe somewhat altered) by another person.
It seems that you are only able to know that some Chrome extension is interacting with your web page in an "expected way" but you cannot verify its authenticity.
The solution?
One solution may consist in using information contained in the Chrome extension package and which cannot be altered or copied by anyone else:
Sending the Chrome extension's ID to the server? But how?
The ID has to be sent by you and your JavaScript code and there seems to be no way to do it with an "internal" Chrome function.
So if someone else just send the same ID to your server (some kind of Chrome extension's ID spoofing) then your server will consider his Chrome extension as a genuine one!
Using the private key which served when you packaged the application? But how?
There seems to be no way to access or use in any way this key programmatically!
One other solution my consist in using NPAPI Plugins and embed authentication methods like GPG, etc. But this solution is not desirable mostly because of the big "Warning" section of its API's doc.
Is there any other solution?
Notes
This question attempts to raise a real security problem in the Chrome extension's API: How to check the authenticity of your Chrome extension when it comes to interact with your services.
If there are any missing possibilities, or any misunderstandings please feel free to ask me in comments.
I'm sorry to say but this problem as posed by you is in essence unsolvable because of one simple problem: You can't trust the client. And since the client can see the code then you can't solve the problem.
Any information coming from the client side can be replicated by other means. It is essentially the same problem as trying to prove that when a user logs into their account it is actually the user not somebody else who found out or was given their username and password.
The internet security models are built around 2 parties trying to communicate without a third party being able to imitate one, modify or listen the conversation. Without hiding the source code of the extension the client becomes indistinguishable from the third party (A file among copies - no way to determine which is which).
If the source code is hidden it becomes a whole other story. Now the user or malicious party doesn't have access to the secrets the real client knows and all the regular security models apply. However it is doubtful that Chrome will allow hidden source code in extensions, because it would produce other security issues.
Some source code can be hidden using NPAPI Plugins as you stated, but it comes with a price as you already know.
Coming back to the current state of things:
Now it becomes a question of what is meant by interaction.
If interaction means that while the user is on the page you want to know if it is your extension or some other then the closest you can get is to list your page in the extensions manifest under app section as documented here
This will allow you to ask on the page if the app is installed by using
chrome.app.isInstalled
This will return boolean showing wether your app is installed or not. The command is documented here
However this does not really solve the problem, since the extension may be installed, but not enabled and there is another extension mocking the communication with your site.
Furthermore the validation is on the client side so any function that uses that validation can be overwritten to ignore the result of this variable.
If however the interaction means making XMLHttpRequests then you are out of luck. Can't be done using current methods because of the visibility of source code as discussed above.
However if it is limiting your sites usability to authorized entities I suggest using regular means of authentication: having the user log in will allow you to create a session. This session will be propagated to all requests made by the extension so you are down to regular client log in trust issues like account sharing etc. These can of course be managed by making the user log in say via their Google account, which most are reluctant to share and further mitigated by blocking accounts that seem to be misused.
I would suggest to do something similar to what Git utilises(have a look at http://git-scm.com/book/en/Git-Internals-Git-Objects to understand how git implements it), i.e.
Creating SHA1 values of the content of every file in your
chrome-extension and then re-create another SHA1 value of the
concatenated SHA1 values obtained earlier.
In this way, you can share the SHA1 value with your server and authenticate your extension, as the SHA1 value will change just in case any person, changes any of your file.
Explaining it in more detail with some pseudo code:
function get_authentication_key(){
var files = get_all_files_in_extension,
concatenated_sha_values = '',
authentication_key;
for(file in files){
concatenated_sha_values += Digest::SHA1.hexdigest(get_file_content(file));
}
$.ajax({
url: 'http://example.com/getauthkey',
type: 'post'
async: false,
success:function(data){
authentication_key = data;
}
})
//You may return either SHA value of concatenated values or return the concatenated SHA values
return authentication_key;
}
// Server side code
get('/getauthkey') do
// One can apply several type of encryption algos on the string passed, to make it unbreakable
authentication_key = Digest::<encryption>.hexdigest($_GET['string']);
return authentication_key;
end
This method allows you to check if any kind of file has been changed maybe an image file or a video file or any other file. Would be glad to know if this thing can be broken as well.
I have to upload one file from client using Button.I have to get the full client path.for example,
suppose, user uploaded a file from this local machines "d:\my files\docs\test.xml".So, now i want to get the same path("d:\my files\docs\test.xml") to proceed further.how do i get it?
i have used FileUpload1.PostedFile.FileName...But it is worked fine with IE and but not in Firefox...
So, Can you help me with this for Firefox and chrome...
Good Source:
http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx
Checkout the "File Upload Control" section near the bottom. quoted:
Additionally, the “Include local directory path when uploading files”
URLAction has been set to "Disable" for the Internet Zone. This change
prevents leakage of potentially sensitive local file-system
information to the Internet. For instance, rather than submitting the
full path C:\users\ericlaw\documents\secret\image.png, Internet
Explorer 8 will now submit only the filename image.png.
This would suggest it is possible if the site is trusted (in IE) / older browsers
No, it is not possible. Browsers do not allow that due to security restrictions.
If i could set which file I wanted from javascript, a hacker could take a lot of files from your PC.
So, asp.net or otherwise, getting the full client path in a browser is not possible.
http://www.ietf.org/rfc/rfc2184.txt and http://www.ietf.org/rfc/rfc2388.txt seem to be the relevant RFCs that discuss this. They are quite lengthy but what it boils down to is that you do indeed get a filename but not a path.
Browsers will follow these standards so through the standard browser interface there will be no way to get the information you want.
This leaves other techniques such as javascript, flash, silverlight, etc.
Javascript does all of its work through the browser object model so again by default won't help. Anything to do with playing with the file system is considered a security risk (do you want random pages looking through your file system?).
It is possible that you could create your own flash or sliverlight upload tool (or find one) that will allow you to collect richer information, I don't know much about those technologies. At the end of the day though I would expect them to follow similar rules about access to the client computer.
So the RFCs and there spirit which are likely followed everywhere says that no, you can't do this.
You could always ask the user for a path in a textbox though if it is important and just have them copy it in...
There seems to be ways to do it but at the same time it looks like it will only work if it is your machine. Here is a link that explains it.
http://www.codingforums.com/showthread.php?t=72288
The problem occurs because it is seen as a malicious script trying to access information that is not under its control giving the user a prompt. So unless this is for machines under your control or users who trust you then it isn't the best of ideas. Most users who see security risk alerts will always block them.
This has been asked a lot of times already: I need to get the full file path via a web-page. The use case is an application running on the same machine as the browser (i.e. the application starts a local HTTP server and fires up the browser.) File-paths are of course valid and the same for both client/server now. The use case it that the user selects a file and then the server process does some computation on it, and the input files are typically large (read: several GiB in size.)
The easiest thing would be to directly access the path using , but for security reasons, this is disabled. I'm looking now for the least intrusive workaround to this problem. The target browser in question is Chrome. I'm fine if the user has to click "accept" once on some security warning, as long as I can ensure that it won't appear again.
Do I have to write an extension, NSPlugin, can I use some special header magic to mark my page as "local", is there some security setting I can set? The less the client has to do the better, and I would prefer some "click here to allow access ..." solution above everything else. Can I directly install an extension from the server process that would do this (after the user clicks accept?)
Is it possible to do this with a Java applet/Flash? That would be the easiest solution, and clients are guaranteed to have Flash installed (as it is bundled in Chrome...)
You can create Java applet for tasks like this and self-sign it. User will have to allow it to run, but then you will be able to access applet's function that will return file path string via Javascript.
Clearly file io on the client's system is forbidden from JavaScript. If this wasn't the case it would be absolutely trivial to hack every web browser that visits your website.
Battlefiled 3 is controlled though the browser. To do this EA wrote a browser extension for the top three browsers. But that's resource intensive. If you just care about chrome you can use an addon, and for that i suggest using the NPAPI.
And as MOleYArd said, Java is a good solution and probably more common than an extension or addon.
I need to update a pair of old classic asp pages— a search.asp page that provides a simple form which is then posted to a results.asp page. One of the form options on the search page is a drop down list (<select) for the "format". If the user chooses the excel format the results page just sets the Response.ContentType to application/vnd.ms-excel and adds a content-disposition header to set the file name and make it an attachment. That's it: it's up to excel to then correctly render the html, and it generally does a pretty good job.
All that works pretty well, except for one thing. The reason for the Excel option is that in this case the users really do want to see as many as 10,000 items or even more for a single search. They'll use Excel to do some additional analysis on the results. So the search operation typically takes just over a minute and I can't change that.
The user experience during that minute is less than ideal. Not only is the user just sitting there with little to no feedback, but there are often enough results that the page overflows the response buffer. This means the page has to flush periodically, and therefore the file starts downloading right away but the download manager isn't able to provide meaningful feedback by itself. My mission is to improve the situation.
The first step is to just show a simple processing... message on the search page when the form submits, and I can do that easily enough. In fact, it's been doing this already for the "HTML" format option. The problem is that when downloading the Excel file I don't know how to tell anything about the download so I can hide the message again, and the existing implementation doesn't provide any feedback on download progress at all. Any ideas? If I can just get a javascript function to fire when the download completes I can hook just about anything to that, but I can't even do that yet.
Update:
I re-worded the question to try to present the problem more clearly.
As far as I know, browsers don't offer you any hooks as to how far a download has progressed. In theory, you could do something on the server side and use AJAX to query the server to see how much of the download has been sent, but I don't know how to do it.
hmm, would it be possible to do this via ajax maybe? ie, user selects the format, query is sent via ajax, and the appropriate document is loaded into an iframe on search.asp for example. you could then pick up the succesful event in your ajax call and appropriately deal with the messages.
I would recommend looking into modifying your upload method to use something like SWFUpload which allows for JavaScript callback on the code. Once the file is uploaded (assuming you are storing it), I would look into passing the filename and type to your Results.asp page where it would then retrieve it form the file store. It's not as secure as keeping it in memory which you elude to in your question; however, would provide a better user experience and may provide the callback solution you need.
http://swfupload.org/
Here's a jQuery plug in example that makes the upload process and SWFUpload integration easy:
http://blog.codeville.net/2008/11/24/jquery-ajax-uploader-plugin-with-progress-bar/
You could have the file download as an attachment by adding a header, so that the user's browser remains operational. I realize this isn't exactly what you're asking for; but if you combine this with the interstitial page you are using for the HTML version, it might be an improvement for user experience.
Response.AddHeader "Content-Disposition", "attachment; filename=report.xls"
The user would see the interstitial page with the processing graphic which would then re-post the search form. This would allow the "Processing..." graphic to display until the page popped up with a download prompt for the Excel file.
Update: I tried using an iframe, having the page periodically check the document object and trapping the "interface does not exist" error for when it switches to Excel, but it still locks the browser while the Excel document is downloading in the iframe... I don't think a pure js solution is going to work. After that I think the next best avenue to pursue is (unfortunately) Flash. Good luck.