Reputation: 13
I am working on a website, which allows users to upload different file formats. We need to restrict the user from uploading password protected files.
Is there a way to determine if a Microsoft Office file (Word, Powerpoint & Excel) is password protected before uploading the file? As per http://social.msdn.microsoft.com/Forums/en/oxmlsdk/thread/34701a34-f1d4-4802-9ce4-133f15039c69, I have implemented the following, but it throws an error saying "File contains corrupted data", while trying to open a password protected file.
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(mem, false))
{
DocumentProtection dp =
wordDoc.MainDocumentPart.DocumentSettingsPart.Settings.GetFirstChild<DocumentProtection>();
if (dp != null && dp.Enforcement == DocumentFormat.OpenXml.OnOffValue.FromBoolean(true))
{
return true;
}
}
Are there any other ways to determine this?
Upvotes: 1
Views: 9002
Reputation:
Sorry I'm a bit late to the party here. As I don't yet have 50 reputation I can't comment on Tomasso Belluzo's answer, but as I implemented it I found the following:
Upvotes: 1
Reputation: 893
Like notme I am unaware of a way to tell if a file is password protected prior to getting even part of a file uploaded, but the accepted answer to this question, while technically great, is a bit of overkill.
See Detect password protected word file for a much simpler and faster method to test whether a file is password protected.
Also, for those finding this question looking for the solution in VBA/S, the following is the version in the former, which is easily adaptable to the latter. www.ozgrid.com/forum/showthread.php?t=148962 . Though I would suggest checking for err.number = 5408 (what gets thrown with a wrong password, when protected), rather than using any err.number to determine that file is password protected.
Upvotes: -1
Reputation: 23675
Give this code a try:
public static Boolean IsProtected(String file)
{
Byte[] bytes = File.ReadAllBytes(file);
String prefix = Encoding.Default.GetString(bytes.Take(2).ToArray());
// Zip and not password protected.
if (prefix == "PK")
return false;
// Office format.
if (prefix == "ÐÏ")
{
// XLS 2003
if (bytes.Skip(0x208).Take(1).ToArray()[0] == 0xFE)
return true;
// XLS 2005
if (bytes.Skip(0x214).Take(1).ToArray()[0] == 0x2F)
return true;
// DOC 2005
if (bytes.Skip(0x20B).Take(1).ToArray()[0] == 0x13)
return true;
// Guessing
if (bytes.Length < 2000)
return false;
// DOC/XLS 2007+
String start = Encoding.Default.GetString(bytes.Take(2000).ToArray()).Replace("\0", " ");
if (start.Contains("E n c r y p t e d P a c k a g e"))
return true;
return false;
}
// Unknown format.
return false;
}
Upvotes: 5
Reputation: 508
The Following Is In The .aspx Source File
Page Language="C#" AutoEventWireup="true" CodeBehind="TestForm.aspx.cs" Inherits="TestApp.TestForm"
!DOCTYPE html PUBLIC
Reference Page ="~/TestForm.aspx" // Note: Removed all HTML tags
protected void Upload_Click(object sender, EventArgs e) { String noPW = "C:\\Users\\David\\Desktop\\Doc1.docx"; String pwProtected = "C:\\Users\\David\\Desktop\\Test.docx"; // if (isProtected(pwProtected)) // outcome.Text = ("Document Is Password Protected"); // else // outcome.Text = ("Document Is NOT Password Protected"); if (isProtected(noPW)) outcome.Text = ("Document Is Password Protected"); else outcome.Text = ("Document Is NOT Password Protected"); }
The Following Is In The .aspx.cs Code Behind File
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using Microsoft.Office.Interop.Word; using System.Runtime.InteropServices; using Microsoft.Office.Interop.Word; namespace TestApp { public partial class TestForm : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } public static bool isProtected(object filePath) { Application myapp = new Application(); object pw = "thispassword"; try { // Trying this for Word document myapp.Documents.Open(ref filePath, PasswordDocument: ref pw); // try open myapp.Documents[ref filePath].Close(); // close it if it does open } catch (COMException ex) { if (ex.HResult == -2146822880) // Can't Open Doc Caused By Invalid Password return true; else Console.WriteLine(ex.Message + " " + ex.HResult); // For debugging, have only tested this one document. } return false; } } }
At least on my computer, I get the expected output for both files, but this is not exactly what you call an exhaustive test of the code. In addition, I tried to upload a file using a FileUpload Control, and I got the COM error "Cannot Find C:\Windows\System\fileName.docx" which confused me just because the the file uploaded came from my desktop, but you probably know why that occurs as you are more familiar with ASP.NET than I am. Either way, this code is just something to try, hope that helps.
Upvotes: 0
Reputation: 88044
To answer the question:
In order to tell if a file is password protected you would need to open that file in the browser and process it. Currently the only mechanism for opening files client side is through the FileAPI of HTML5 which isn't universally supported. Which means there is no reliable way of doing this.
Now, you can test the file on the server to determine if it is password protected or not and either throw it away or save it depending upon your rules.
Incidentally, the code you provided is server side code. Just modify it to catch the corrupted exception and display a message to the user about how the file is either corrupt or password protected with a note on how you don't allow password protected files to be uploaded.
Upvotes: 0