Share via


Windows Form 中更安全的檔案和資料存取

更新:2007 年 11 月

.NET Framework 會透過使用權限來協助保護資源和資料。應用程式能否讀取或寫入資料,需視應用程式所取得的使用權限而定。如果應用程式是在部分信任的環境中執行,您可能就無法存取資料,或者可能必須變更存取資料的方式。

當您遇到安全性限制時,您有兩個選擇:判斷提示 (Assert) 使用權限 (即假設應用程式已取得使用權限),或是使用針對在部分信任環境中執行而撰寫的功能版本。下列小節將討論如何從在部分信任環境中執行的應用程式進行檔案、資料庫和登錄的存取。

注意事項:

根據預設,產生 ClickOnce 部署的工具會預設這些部署要求執行部署的電腦必須具有「完全信任」的權限。如果您決定要取得在部分信任下執行所增加的安全性優點,便必須在 Visual Studio 或 Windows Software Development Kit (SDK) 工具 (Mage.exe 或 MageUI.exe) 中變更這個預設值。如需 Windows Form 安全性以及如何判斷適合應用程式之信任層級的詳細資訊,請參閱 Windows Form 中的安全性概觀

檔案存取

FileIOPermission 類別會控制 .NET Framework 中的檔案和資料夾存取。根據預設,安全性系統不會將 FileIOPermission 授與部分信任的環境,例如近端內部網路區域和網際網路區域。然而,如果修改應用程式的設計或使用不同的方法存取檔案,則要求檔案存取的應用程式仍能在這些環境中運作。近端內部網路區域預設能取得具有相同站台存取和相同目錄存取、連接回原始站台,以及讀取安裝目錄的權限;而網際網路區域則預設只能取得連接回原始站台的權限。

使用者指定的檔案

如果沒有檔案存取權限,其中一種處理方式是提示使用者透過 OpenFileDialogSaveFileDialog 類別提供特定的檔案資訊。藉由這種使用者互動,可以進一步確保應用程式無法惡意載入私人檔案或覆寫重要檔案。OpenFileOpenFile 方法會藉由開啟使用者指定之檔案的檔案資料流,提供讀取和寫入檔案的存取權限。這兩個方法也可以透過隱藏檔案路徑的方式來保護使用者的檔案。

注意事項:

這些使用權限會根據應用程式是位於網際網路區域或內部網路區域而有所不同。網際網路區域的應用程式只能使用 OpenFileDialog,而內部網路區域的應用程式則對檔案對話方塊的使用權限沒有限制。

FileDialogPermission 類別會指定應用程式可以使用的檔案對話方塊類型。下表顯示使用各個 FileDialog 類別所必須具有的值。

類別

必要存取值

OpenFileDialog

Open

SaveFileDialog

Save

注意事項:

直到確實呼叫 OpenFile 方法前,都不需要特定的使用權限。

顯示檔案對話方塊的使用權限不會授與應用程式對所有 FileDialogOpenFileDialogSaveFileDialog 類別成員的完整存取權限。如需瞭解呼叫各方法所需要的確實使用權限,請參閱 .NET Framework 類別庫 (Class Library) 文件中該方法的參考主題。

在下列程式碼範例中,會使用 OpenFile 方法在 RichTextBox 控制項中開啟使用者指定的檔案。此範例需要 FileDialogPermission 和相關聯的 Open 列舉值。這個範例會示範如何處理 SecurityException,以判斷是否要停用儲存功能。在這個範例中,Form 必須要有一個名為 ButtonOpen 的 Button 控制項和一個名為 RtfBoxMain 的 RichTextBox 控制項。

注意事項:

此範例中不會顯示儲存功能的程式設計邏輯。

 [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;
            }
        }
    }
}
注意事項:

在 Visual C# 中,請務必加入可啟用事件處理常式的程式碼。下列程式碼會利用前一個範例中的程式碼,說明如何啟用事件處理常式。this.ButtonOpen.Click += newSystem.Windows.Forms.EventHandler(this.ButtonOpen_Click);

其他檔案

有時候您會需要讀取或寫入使用者未指定的檔案,例如,當您必須保存 (Persist) 應用程式設定時。在近端內部網路區域和網際網路區域中,應用程式不會具有可將資料儲存到本機檔案的使用權限。但是,應用程式可以將資料儲存在隔離儲存區 (Isolated Storage)。隔離儲存區是抽象的資料區間 (而非特定的儲存位置),其中包含一或多個稱為存放區的隔離儲存區檔案,這些檔案中才會包含儲存資料的實際目錄位置。隔離儲存區不需要 FileIOPermission 之類的檔案存取權限,而是由 IsolatedStoragePermission 類別控制隔離儲存區的使用權限。根據預設,在近端內部網路區域和網際網路區域中執行的應用程式可以使用隔離儲存區來儲存資料,不過,它們的磁碟配額等設定可能會不同。如需隔離儲存區的詳細資訊,請參閱隔離儲存區的簡介

下列範例使用隔離儲存區,將資料寫入位於存放區內的檔案。此範例需要 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 Service 做為存取資料的替代方式。XML Web Service 是一種可以透過 XML 以程式設計方式在網路上存取的軟體。有了 XML Web Services,應用程式就可以在不同的程式碼群組區域之間共用資料。根據預設,近端內部網路區域和網際網路區域中的應用程式可以取得存取原始站台的權限,讓它們能夠呼叫 XML Web Service。如需建置 (Build) XML Web Service 的詳細資訊,請參閱使用 ASP.NET 的 XML Web Service。如需如何使用 XML Web Service 的詳細資訊,請參閱建置 XML Web Service 用戶端

登錄存取

RegistryPermission 類別可控制對作業系統登錄的存取。根據預設,只有在本機執行的應用程式才能存取登錄。RegistryPermission 只授與應用程式嘗試存取登錄的權限,並不保證一定能存取成功,因為作業系統仍然會對登錄強制執行安全性檢查。

由於您無法在部分信任的環境中存取登錄,因此可能需要尋求其他儲存資料的方法。當您儲存應用程式設定時,請使用隔離儲存區,不要使用登錄。隔離儲存區也可用於儲存其他應用程式特定檔案。您還可以儲存伺服器或原始站台的全域應用程式資訊,因為根據預設,應用程式可以取得存取原始站台的權限。

請參閱

概念

Windows Form 中更安全的列印

Windows Form 中的其他安全性考量

Windows Form 中的安全性概觀

參考

資訊清單產生和編輯工具 (Mage.exe)

圖形用戶端、資訊清單產生和編輯工具 (MageUI.exe)

其他資源

Windows Form 的安全性