保护 Excel 工作表 - 不可能?

Posted

技术标签:

【中文标题】保护 Excel 工作表 - 不可能?【英文标题】:Protecting Excel worksheets - Impossible? 【发布时间】:2020-04-12 00:38:55 【问题描述】:

我正在尝试共享 Excel 工作簿,但只能访问几个可见工作表。由于 Excel 的安全漏洞和工作表的密码保护,这已被证明比最初预期的要困难得多。

我的问题是由于一些隐藏的工作表需要保持隐藏并且内容无法访问,但计算需要,结果显示在可见工作表中。

到目前为止,我已经尝试在 VBA 窗口中“超级隐藏”工作表并锁定 VBA 项目。这个想法是用户不能在没有 VBA 项目密码的情况下取消隐藏“超级隐藏”工作表。 我试图添加额外的 VBA 代码来对抗某些“攻击”,但我不断回到一个已知的缺陷,它绕过了我所有的努力:

第 1 步: 保存或确保 Excel 工作簿保存为 .xlsx 或 .xlsm

第 2 步: 从其他工作簿或您的 personal.xlsb 中运行以下代码,从工作表和结构保护中删除密码 (我会链接到我找到代码的帖子,但我现在找不到它......)。

Sub RemoveProtection()

Dim dialogBox As FileDialog
Dim sourceFullName As String
Dim sourceFilePath As String
Dim SourceFileName As String
Dim sourceFileType As String
Dim newFileName As Variant
Dim tempFileName As String
Dim zipFilePath As Variant
Dim oApp As Object
Dim FSO As Object
Dim xmlSheetFile As String
Dim xmlFile As Integer
Dim xmlFileContent As String
Dim xmlStartProtectionCode As Double
Dim xmlEndProtectionCode As Double
Dim xmlProtectionString As String

'Open dialog box to select a file
Set dialogBox = Application.FileDialog(msoFileDialogFilePicker)
dialogBox.AllowMultiSelect = False
dialogBox.Title = "Select file to remove protection from"

If dialogBox.show = -1 Then
    sourceFullName = dialogBox.SelectedItems(1)
Else
    Exit Sub
End If

'Get folder path, file type and file name from the sourceFullName
sourceFilePath = Left(sourceFullName, InStrRev(sourceFullName, "\"))
sourceFileType = Mid(sourceFullName, InStrRev(sourceFullName, ".") + 1)
SourceFileName = Mid(sourceFullName, Len(sourceFilePath) + 1)
SourceFileName = Left(SourceFileName, InStrRev(SourceFileName, ".") - 1)

'Use the date and time to create a unique file name
tempFileName = "Temp" & Format(Now, " dd-mmm-yy h-mm-ss")

'Copy and rename original file to a zip file with a unique name
newFileName = sourceFilePath & tempFileName & ".zip"
On Error Resume Next
FileCopy sourceFullName, newFileName

If Err.Number <> 0 Then
    MsgBox "Unable to copy " & sourceFullName & vbNewLine _
        & "Check the file is closed and try again"
    Exit Sub
End If
On Error GoTo 0

'Create folder to unzip to
zipFilePath = sourceFilePath & tempFileName & "\"
MkDir zipFilePath

'Extract the files into the newly created folder
Set oApp = CreateObject("Shell.Application")
oApp.Namespace(zipFilePath).CopyHere oApp.Namespace(newFileName).Items

'loop through each file in the \xl\worksheets folder of the unzipped file
xmlSheetFile = Dir(zipFilePath & "\xl\worksheets\*.xml*")
Do While xmlSheetFile <> ""

    'Read text of the file to a variable
    xmlFile = FreeFile
    Open zipFilePath & "xl\worksheets\" & xmlSheetFile For Input As xmlFile
    xmlFileContent = Input(LOF(xmlFile), xmlFile)
    Close xmlFile

    'Manipulate the text in the file
    xmlStartProtectionCode = 0
    xmlStartProtectionCode = InStr(1, xmlFileContent, "<sheetProtection")

    If xmlStartProtectionCode > 0 Then

        xmlEndProtectionCode = InStr(xmlStartProtectionCode, _
            xmlFileContent, "/>") + 2 '"/>" is 2 characters long
        xmlProtectionString = Mid(xmlFileContent, xmlStartProtectionCode, _
            xmlEndProtectionCode - xmlStartProtectionCode)
        xmlFileContent = Replace(xmlFileContent, xmlProtectionString, "")

    End If

    'Output the text of the variable to the file
    xmlFile = FreeFile
    Open zipFilePath & "xl\worksheets\" & xmlSheetFile For Output As xmlFile
    Print #xmlFile, xmlFileContent
    Close xmlFile

    'Loop to next xmlFile in directory
    xmlSheetFile = Dir

Loop

'Read text of the xl\workbook.xml file to a variable
xmlFile = FreeFile
Open zipFilePath & "xl\workbook.xml" For Input As xmlFile
xmlFileContent = Input(LOF(xmlFile), xmlFile)
Close xmlFile

'Manipulate the text in the file to remove the workbook protection
xmlStartProtectionCode = 0
xmlStartProtectionCode = InStr(1, xmlFileContent, "<workbookProtection")
If xmlStartProtectionCode > 0 Then

    xmlEndProtectionCode = InStr(xmlStartProtectionCode, _
        xmlFileContent, "/>") + 2 ''"/>" is 2 characters long
    xmlProtectionString = Mid(xmlFileContent, xmlStartProtectionCode, _
        xmlEndProtectionCode - xmlStartProtectionCode)
    xmlFileContent = Replace(xmlFileContent, xmlProtectionString, "")

End If

'Manipulate the text in the file to remove the modify password
xmlStartProtectionCode = 0
xmlStartProtectionCode = InStr(1, xmlFileContent, "<fileSharing")
If xmlStartProtectionCode > 0 Then

    xmlEndProtectionCode = InStr(xmlStartProtectionCode, xmlFileContent, _
        "/>") + 2 ''"/>" is 2 characters long
    xmlProtectionString = Mid(xmlFileContent, xmlStartProtectionCode, _
        xmlEndProtectionCode - xmlStartProtectionCode)
    xmlFileContent = Replace(xmlFileContent, xmlProtectionString, "")

End If

'Output the text of the variable to the file
xmlFile = FreeFile
Open zipFilePath & "xl\workbook.xml" & xmlSheetFile For Output As xmlFile
Print #xmlFile, xmlFileContent
Close xmlFile

'Create empty Zip File
Open sourceFilePath & tempFileName & ".zip" For Output As #1
Print #1, Chr$(80) & Chr$(75) & Chr$(5) & Chr$(6) & String(18, 0)
Close #1

'Move files into the zip file
oApp.Namespace(sourceFilePath & tempFileName & ".zip").CopyHere _
oApp.Namespace(zipFilePath).Items
'Keep script waiting until Compressing is done
On Error Resume Next
Do Until oApp.Namespace(sourceFilePath & tempFileName & ".zip").Items.count = _
    oApp.Namespace(zipFilePath).Items.count
    Application.Wait (Now + TimeValue("0:00:01"))
Loop
On Error GoTo 0

'Delete the files & folders created during the sub
Set FSO = CreateObject("scripting.filesystemobject")
FSO.deletefolder sourceFilePath & tempFileName

'Rename the final file back to an xlsx file
Name sourceFilePath & tempFileName & ".zip" As sourceFilePath & SourceFileName _
& "_" & Format(Now, "dd-mmm-yy h-mm-ss") & "." & sourceFileType

'Show message box
MsgBox "The workbook and worksheet protection passwords have been removed.", _
vbInformation + vbOKOnly, Title:="Password protection"

End Sub

第 3 步: 运行以下代码以取消隐藏所有工作表

Sub UnhideAllSheets()

For Each Worksheet In ActiveWorkbook.Sheets
        Worksheet.Visible = -1
Next Worksheet

End Sub

工作簿现在没有工作表和结构保护上的密码,通过将工作簿保存为 .xlsx 文件,所有“计数器”VBA 代码都消失了。

我考虑过添加一个用户定义的函数来检查工作簿文件的扩展名是否为“.xlsb”。如果扩展名为“.xlsb”,则该函数将返回“1”,然后将其乘以重要的东西。如果将工作簿另存为其他内容,或者将 VBA 项目完全删除以另存为 .xlsx,这将导致计算失败。 但是,我不喜欢这种方法,因为我认为这不是一个长期的解决方案......

因此,我的问题是: 有没有一种方法可以安全地共享 Excel 工作簿,并且只能访问几张工作表,而不会冒用户访问隐藏工作表和/或不需要的内容的风险?

【问题讨论】:

AFAIK,没有绝对安全的方法来保护 Excel 工作簿/工作表。一种方法是对数据进行编码,这样即使内容未被隐藏,如果没有解码功能,它也将无法利用。 嗨 Vincent G,有趣的想法 - 你打算如何做到这一点?像 Excel 中的 SHA256 函数? 我认为这个问题的总体结论是您可以永远假设 Excel 是安全的。 这也是我目前得出的结论——可悲的是...... 【参考方案1】:

在 VBE 中,您可以将特定工作表的 Visible 属性更改为 xlSheetVeryHidden

这会将其从前端完全删除。

然后,您可以添加密码以保护 VBE 中的 VBA 项目,以防止用户更改该属性(如果他们知道的话)。

此外,您仍然可以使用您的 VBA 代码访问这些工作表。

编辑:

像往常一样,我还添加到特定工作表的密码。但如果他们必须取消隐藏,UserForm 也会在 Worksheet_Activate 事件上触发自定义 UserForm。如果他们输入了错误的密码或关闭了UserForm,则该表将再次被隐藏起来。您可以向此事件处理程序添加各种类型,例如重新保护工作表、重新保护项目、使用加密密码保护工作簿以及将工作簿作为“安全漏洞”关闭。

可能性无穷无尽。不是一个确切的预防措施,但希望这会有所帮助。

【讨论】:

我认为问题的第 3 段说明他已经这样做了。 @VincentG 我也添加了一些。感谢您指出。 嗨,Dean,我也试过这个,但是在将文件保存为 .xlsx 方面失败了(使用计数器代码删除到 VBA 项目)。如果您将工作簿保存为 .xlsx 文件并运行第 2 步和第 3 步,您的工作表将可见且不受密码保护,您的 VBA 将消失...

以上是关于保护 Excel 工作表 - 不可能?的主要内容,如果未能解决你的问题,请参考以下文章

excel如何撤销工作表保护

如何去除excel的宏保护?

Excel2013 破解(编辑工作表受保护)密码

Excel2013 破解(编辑工作表受保护)密码

在excel中如何取消工作表的保护命令

excel表格被保护该怎么取消不知道密码?