Share via


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

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

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

提示

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

文件访问

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

用户指定的文件

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

提示

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

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

必需的访问值

OpenFileDialog

Open

SaveFileDialog

Save

提示

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

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

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

提示

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

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;
            }
        }
    }
}

提示

在 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

如果因您希望应用程序在部分信任模式下运行而导致无法直接访问数据库,则可以将 Web 服务用作访问数据的备选方法。 Web 服务是一个可通过网络以编程方式进行访问的软件。 借助于 Web 服务,应用程序可以跨代码组区域共享数据。 默认情况下,将向本地 Intranet 和 Internet 区域中的应用程序授予访问其原始站点的权限,从而使这些应用程序可以调用同一服务器上承载的 Web 服务。 有关更多信息,请参见 ASP.NET AJAX and Web ServicesWindows Communication Foundation

注册表访问

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

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

请参见

参考

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

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

概念

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

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

Windows 窗体中的安全性概述

其他资源

Windows 窗体安全