Windows 窗体中更加安全的文件和数据访问

更新:2007 年 11 月

.NET Framework 使用权限来帮助保护资源和数据。应用程序可以读取或写入数据的位置取决于为应用程序授予的权限。当应用程序在部分信任环境中运行时,您可能不具有对数据的访问权限,或者必须更改访问数据的方式。

遇到安全限制时,您有两个选择:断言权限(假定已授权给应用程序),或者使用为用于部分信任环境而编写的功能的版本。以下各节讨论如何从部分信任的环境运行的应用程序处理文件、数据库和注册表访问。

3wtbwh77.alert_note(zh-cn,VS.90).gif说明:

默认情况下,生成 ClickOnce 部署的工具将这些部署默认为向它们运行计算机请求“完全信任”。如果您决定要获得部分信任环境中运行的附加安全性优点,则必须在 Visual Studio 或 Windows 软件开发工具包 (SDK) 工具(Mage.exe 或 MageUI.exe)之一中更改此默认设置。有关 Windows 窗体安全性的更多信息,以及如何确定适当的应用程序信任级别,请参见 Windows 窗体中的安全性概述

文件访问

在 .NET Framework 中,FileIOPermission 类控制对文件和文件夹的访问。默认情况下,安全系统不会将 FileIOPermission 授予部分信任环境(例如,本地 Intranet 和 Internet 区域)。不过,如果修改应用程序的设计或使用不同的方法访问文件,则要求访问文件的应用程序仍可以在这些环境中工作。默认情况下,本地 Intranet 区域将被授予相同的站点访问权限和相同的目录访问权限,以便连接回其原始站点,并从其安装目录读取数据。默认情况下,Internet 区域仅被授予连接回其原始站点的权限。

用户指定的文件

处理不具有文件访问权限的一种方法是,提示用户使用 OpenFileDialogSaveFileDialog 类提供特定的文件信息。这种用户交互有助于在一定程度上保证,应用程序无法恶意加载私有文件或改写重要的文件。OpenFileOpenFile 方法通过打开用户指定文件的文件流,来提供读写文件的访问权限。这些方法还可以隐藏文件的路径,从而有助于保护用户的文件。

3wtbwh77.alert_note(zh-cn,VS.90).gif说明:

根据应用程序是位于 Internet 区域还是在 Intranet 区域,这些权限会有所不同。Internet 区域中的应用程序只能使用 OpenFileDialog,而 Intranet 应用程序具有无限制的文件对话框权限。

FileDialogPermission 类指定应用程序可以使用的文件对话框的类型。下表显示使用每个 FileDialog 类时必须提供的值。

必需的访问值

OpenFileDialog

Open

SaveFileDialog

Save

3wtbwh77.alert_note(zh-cn,VS.90).gif说明:

只有在实际调用 OpenFile 方法时才会请求特定权限。

用于显示文件对话框的权限并不会向应用程序授予对 FileDialogOpenFileDialogSaveFileDialog 类的所有成员的完全访问权。有关调用每个方法时所需的确切权限,请参见 .NET Framework 类库文档中该方法的参考主题。

下面的代码示例使用 OpenFile 方法,在 RichTextBox 控件中打开用户指定的文件。此示例要求提供 FileDialogPermission 和关联的 Open 枚举值。此示例演示如何处理 SecurityException,以确定是否应禁用保存功能。此示例要求 Form 具有一个名为 ButtonOpen 的 Button 控件,以及一个名为 RtfBoxMain 的 RichTextBox 控件。

3wtbwh77.alert_note(zh-cn,VS.90).gif说明:

此示例中未显示保存功能的编程逻辑。

 [Visual Basic]
Private Sub ButtonOpen_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles ButtonOpen.Click 

    Dim editingFileName as String = ""
    Dim saveAllowed As Boolean = True

    ' Displays the OpenFileDialog.
    If (OpenFileDialog1.ShowDialog() = DialogResult.OK) Then
        Dim userStream as System.IO.Stream
        Try 
            ' Opens the file stream for the file selected by the user.
            userStream =OpenFileDialog1.OpenFile() 
            Me.RtfBoxMain.LoadFile(userStream, _
                RichTextBoxStreamType.PlainText)
        Finally
            userStream.Close()
        End Try

        ' Tries to get the file name selected by the user.
        ' Failure means that the application does not have
        ' unrestricted permission to the file.
        Try 
            editingFileName = OpenFileDialog1.FileName
        Catch ex As Exception
            If TypeOf ex Is System.Security.SecurityException Then 
                ' The application does not have unrestricted permission 
                ' to the file so the save feature will be disabled.
                saveAllowed = False 
            Else 
                Throw ex
            End If
        End Try
    End If
End Sub
private void ButtonOpen_Click(object sender, System.EventArgs e) 
{
    String editingFileName = "";
    Boolean saveAllowed = true;

    // Displays the OpenFileDialog.
    if (openFileDialog1.ShowDialog() == DialogResult.OK) 
    {
        // Opens the file stream for the file selected by the user.
        using (System.IO.Stream userStream = openFileDialog1.OpenFile()) 
        {
            this.RtfBoxMain.LoadFile(userStream,
                RichTextBoxStreamType.PlainText);
            userStream.Close();
        }

        // Tries to get the file name selected by the user.
        // Failure means that the application does not have
        // unrestricted permission to the file.
        try 
        {
            editingFileName = openFileDialog1.FileName;
        } 
        catch (Exception ex) 
        {
            if (ex is System.Security.SecurityException) 
            {
                // The application does not have unrestricted permission 
                // to the file so the save feature will be disabled.
                saveAllowed = false; 
            } 
            else 
            {
                throw ex;
            }
        }
    }
}
3wtbwh77.alert_note(zh-cn,VS.90).gif说明:

在 Visual C# 中,请确保添加启用事件处理程序的代码。以下代码使用上一示例中的代码,演示如何启用事件处理程序。this.ButtonOpen.Click += newSystem.Windows.Forms.EventHandler(this.ButtonOpen_Click);

其他文件

有时,您需要向用户未指定的文件读取或写入数据,如当您必须保持应用程序设置时。在本地 Intranet 区域和 Internet 区域中,应用程序无权在本地文件中存储数据。但是,应用程序可以在独立存储中存储数据。独立存储是一个抽象的数据舱而非特定的存储位置,它含有一个或多个独立存储文件,这些文件称为存储区,其中包含存储数据的实际目录位置。独立存储的权限由 IsolatedStoragePermission 类进行控制,而不需要类似于 FileIOPermission 的文件访问权限。默认情况下,在本地 Intranet 区域和 Internet 区域中运行的应用程序可以使用独立存储来存储数据;但是,某些设置可能会有所不同,如磁盘配额。有关独立存储的更多信息,请参见 独立存储介绍

下面的示例使用独立存储将数据写入存储区内的文件中。此示例需要 IsolatedStorageFilePermissionDomainIsolationByUser 枚举值。此示例演示从独立存储内的文件中读取 Button 控件的特定属性值,以及如何将该属性值写入独立存储内的文件中。Read 函数将在应用程序启动后调用;而 Write 函数将在应用程序终止前调用。此示例要求 Read 和 Write 函数作为 Form(包含一个名为 MainButton 的 Button 控件)的成员存在。

' Reads the button options from the isolated storage. Uses Default values 
' for the button if the options file does not exist.
Public Sub Read() 
    Dim isoStore As System.IO.IsolatedStorage.IsolatedStorageFile = _
        System.IO.IsolatedStorage.IsolatedStorageFile. _ 
        GetUserStoreForDomain()

    Dim filename As String = "options.txt"
    Try
        ' Checks to see if the options.txt file exists.
        If (isoStore.GetFileNames(filename).GetLength(0) <> 0) Then

            ' Opens the file because it exists.
            Dim isos As New System.IO.IsolatedStorage.IsolatedStorageFileStream _ 
                 (filename, IO.FileMode.Open,isoStore)
            Dim reader as System.IO.StreamReader
            Try 
                reader = new System.IO.StreamReader(isos)

                ' Reads the values stored.
                Dim converter As System.ComponentModel.TypeConverter
                converter = System.ComponentModel.TypeDescriptor.GetConverter _ 
                    (GetType(Color))

                Me.MainButton.BackColor = _ 
                        CType(converter.ConvertFromString _ 
                         (reader.ReadLine()), Color)
                me.MainButton.ForeColor = _
                        CType(converter.ConvertFromString _ 
                         (reader.ReadLine()), Color)

                converter = System.ComponentModel.TypeDescriptor.GetConverter _ 
                    (GetType(Font))
                me.MainButton.Font = _
                        CType(converter.ConvertFromString _ 
                         (reader.ReadLine()), Font)

            Catch ex As Exception
                Debug.WriteLine("Cannot read options " + _
                    ex.ToString())
            Finally
                reader.Close()
            End Try
        End If

    Catch ex As Exception
        Debug.WriteLine("Cannot read options " + ex.ToString())
    End Try
End Sub

' Writes the button options to the isolated storage.
Public Sub Write() 
    Dim isoStore As System.IO.IsolatedStorage.IsolatedStorageFile = _
        System.IO.IsolatedStorage.IsolatedStorageFile. _ 
        GetUserStoreForDomain()

    Dim filename As String = "options.txt"
    Try 
        ' Checks if the file exists, and if it does, tries to delete it.
        If (isoStore.GetFileNames(filename).GetLength(0) <> 0) Then
            isoStore.DeleteFile(filename)
        End If
    Catch ex As Exception
        Debug.WriteLine("Cannot delete file " + ex.ToString())
    End Try

    ' Creates the options.txt file and writes the button options to it.
    Dim writer as System.IO.StreamWriter
    Try 
        Dim isos As New System.IO.IsolatedStorage.IsolatedStorageFileStream _ 
             (filename, IO.FileMode.CreateNew, isoStore)

        writer = New System.IO.StreamWriter(isos)
        Dim converter As System.ComponentModel.TypeConverter

        converter = System.ComponentModel.TypeDescriptor.GetConverter _ 
           (GetType(Color))
        writer.WriteLine(converter.ConvertToString( _
            Me.MainButton.BackColor))
        writer.WriteLine(converter.ConvertToString( _
            Me.MainButton.ForeColor))

        converter = System.ComponentModel TypeDescriptor.GetConverter _ 
           (GetType(Font))
        writer.WriteLine(converter.ConvertToString( _
            Me.MainButton.Font))

    Catch ex as Exception
        Debug.WriteLine("Cannot write options " + ex.ToString())

    Finally
        writer.Close()
    End Try
End Sub
// Reads the button options from the isolated storage. Uses default values 
// for the button if the options file does not exist.
public void Read() 
{
    System.IO.IsolatedStorage.IsolatedStorageFile isoStore = 
        System.IO.IsolatedStorage.IsolatedStorageFile.
        GetUserStoreForDomain();

    string filename = "options.txt";
    try
    {
        // Checks to see if the options.txt file exists.
        if (isoStore.GetFileNames(filename).GetLength(0) != 0) 
        {
            // Opens the file because it exists.
            System.IO.IsolatedStorage.IsolatedStorageFileStream isos = 
                new System.IO.IsolatedStorage.IsolatedStorageFileStream
                    (filename, System.IO.FileMode.Open,isoStore);
            System.IO.StreamReader reader = null;
            try 
            {
                reader = new System.IO.StreamReader(isos);

                // Reads the values stored.
                TypeConverter converter ;
                converter = TypeDescriptor.GetConverter(typeof(Color));

                this.MainButton.BackColor = 
                 (Color)(converter.ConvertFromString(reader.ReadLine()));
                this.MainButton.ForeColor = 
                 (Color)(converter.ConvertFromString(reader.ReadLine()));

                converter = TypeDescriptor.GetConverter(typeof(Font));
                this.MainButton.Font = 
                  (Font)(converter.ConvertFromString(reader.ReadLine()));
            }
            catch (Exception ex)
            { 
                System.Diagnostics.Debug.WriteLine
                     ("Cannot read options " + ex.ToString());
            }
            finally
            {
                reader.Close();
            }
        }
    } 
    catch (Exception ex) 
    {
        System.Diagnostics.Debug.WriteLine
            ("Cannot read options " + ex.ToString());
    }
}

// Writes the button options to the isolated storage.
public void Write() 
{
    System.IO.IsolatedStorage.IsolatedStorageFile isoStore = 
        System.IO.IsolatedStorage.IsolatedStorageFile.
        GetUserStoreForDomain();

    string filename = "options.txt";
    try 
    {
        // Checks if the file exists and, if it does, tries to delete it.
        if (isoStore.GetFileNames(filename).GetLength(0) != 0) 
        {
            isoStore.DeleteFile(filename);
        }
    }
    catch (Exception ex) 
    {
        System.Diagnostics.Debug.WriteLine
            ("Cannot delete file " + ex.ToString());
    }

    // Creates the options file and writes the button options to it.
    System.IO.StreamWriter writer = null;
    try 
    {
        System.IO.IsolatedStorage.IsolatedStorageFileStream isos = new 
            System.IO.IsolatedStorage.IsolatedStorageFileStream(filename, 
            System.IO.FileMode.CreateNew,isoStore);

        writer = new System.IO.StreamWriter(isos);
        TypeConverter converter ;

        converter = TypeDescriptor.GetConverter(typeof(Color));
        writer.WriteLine(converter.ConvertToString(
            this.MainButton.BackColor));
        writer.WriteLine(converter.ConvertToString(
            this.MainButton.ForeColor));

        converter = TypeDescriptor.GetConverter(typeof(Font));
        writer.WriteLine(converter.ConvertToString(
            this.MainButton.Font));

    }
    catch (Exception ex)
    { 
        System.Diagnostics.Debug.WriteLine
           ("Cannot write options " + ex.ToString());
    }
    finally
    {
        writer.Close();
    }
}

数据库访问

访问数据库所需的权限因数据库提供程序而异;但是,只有用适当权限运行的应用程序才可以通过数据连接访问数据库。有关访问数据库所需权限的更多信息,请参见 代码访问安全性和 ADO.NET

如果您希望应用程序在部分信任环境中运行,导致无法直接访问数据库,则可以将 XML Web services 用作访问数据的备选方法。XML Web services 是一个软件,可以用 XML 通过网络以编程方式进行访问。借助于 XML Web services,应用程序可以跨代码组区域共享数据。默认情况下,本地 Intranet 和 Internet 区域中的应用程序被授予访问其原始站点的权限,从而使这些应用程序可以调用 XML Web services。有关如何生成 XML Web services 的信息,请参见 使用 ASP.NET 的 XML Web services。有关如何使用 XML Web services 的更多信息,请参见生成 XML Web services 客户端

注册表访问

RegistryPermission 类控制对操作系统注册表的访问。默认情况下,只有本地运行的应用程序才能访问注册表。RegistryPermission 只向应用程序授予尝试访问注册表的权限;它不保证访问可获得成功,因为操作系统仍在对注册表强制应用安全性。

由于无法在部分信任环境下访问注册表,因此可能需要使用其他方法来存储数据。在存储应用程序设置时,请使用独立存储而不是注册表。独立存储还可以用于存储其他应用程序特定的文件。您还可以存储有关源服务器或源站点的全局应用程序信息,因为默认情况下,应用程序被授予访问其源站点的权限。

请参见

概念

Windows 窗体中的更加安全的打印

Windows 窗体中额外的安全性注意事项

Windows 窗体中的安全性概述

参考

清单生成和编辑工具 (Mage.exe)

图形化客户端中的清单生成和编辑工具 (MageUI.exe)

其他资源

Windows 窗体安全性