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

.NET Framework 會使用許可權來協助保護資源和資料。 您的應用程式可以讀取或寫入資料的位置取決於應用程式授與權限。 當您的應用程式在部分信任的環境中執行時,您可能無法存取您的資料,或者您可能要改變您存取資料的方式。

當您遇到安全性限制時,您有兩個選項:判斷權限 (假設已授與您的應用程式),或者使用被寫成具有在部分信任環境運作功能的版本。 下列章節將討論如何使用在部分信任環境執行的應用程式所產生的檔案、資料庫以及登錄存取。

注意

根據預設,產生 ClickOnce 部署的工具會將這些部署預設為從執行所在的電腦要求完全信任。 如果您決定想要在部分信任中執行的新增安全性優點,您必須在 Visual Studio 或其中一個 Windows SDK 工具中變更此預設值(Mage.exe 或 MageUI.exe)。 如需 Windows Forms 安全性的詳細資訊,以及如何判斷應用程式的適當信任層級,請參閱 Windows Forms 中的安全性概觀

檔案存取

類別 FileIOPermission 會控制 .NET Framework 中的檔案和資料夾存取權。 根據預設,安全性系統並未將 FileIOPermission 授與部分安全性環境,例如近端內部網路或者網際網路區域。 然而,如果您修改您應用程式的設計或使用不同方法來存取檔案,需要檔案存取的應用程式依然能夠在這些環境中運作。 根據預設,近端內部網路區域已經被授與權限能夠存取相同網站與相同目錄、連線到網站的原始來源、以及從其安裝目錄讀取。 根據預設,網際網路區域只被授與連回其原始網站的權限。

使用者指定的檔案

沒有檔案存取權限的處理方法之一是使用 OpenFileDialogSaveFileDialog 類別來提示使用者提供特定的檔案資訊。 這種使用者互動有助於提供在某種程度上保證應用程式無法惡意載入私人檔案或覆寫重要檔案。 OpenFileOpenFile 方法,藉著開啟使用者指定的檔案資料流來提供讀取與寫入的檔案存取。 本方法也藉由模糊檔案路徑來協助保護使用者的檔案。

注意

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

FileDialogPermission 類別會指定您的應用程式能夠使用哪一種對話方塊。 下列表格顯示在您要使用每一種 FileDialog 類別時必需要有的值 。

類別 必需的存取值
OpenFileDialog Open
SaveFileDialog Save

注意

特定的權限在方法 OpenFile 真的被呼叫之前不會被要求。

顯示檔案對話方塊的權限不會授與您的應用程式對 FileDialogOpenFileDialogSaveFileDialog 類別所有成員的完整存取權。 如需呼叫每個方法所需的確切許可權,請參閱 .NET Framework 類別庫檔中該方法的參考主題。

下列程式碼範例使用 OpenFile 方法,來將使用者指定的檔案開啟至 RichTextBox 控制項。 這個範例需要 FileDialogPermission 以及相關的列舉值 Open 。 此範例示範如何處理 SecurityException 來判斷是否應該停用儲存功能。 這個範例需要您的 FormButton 控制項命名為 ButtonOpen,和 RichTextBox 控制項命名為 RtfBoxMain

注意

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

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

Other Files

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

下列範例會使用隔離儲存區,將資料寫入存放區中的檔案。 這個範例需要 IsolatedStorageFilePermission 以及 DomainIsolationByUser 列舉值。 此範例示範讀取和寫入 Button 控制項的特定屬性值到隔離儲存區中的檔案。 應用程式啟動之後就會呼叫 Read 函式,並且會在結束前呼叫 Write 函式。 此範例會要求 ReadWrite 函式以 成員的形式存在 Form ,其中包含名為 MainButtonButton 控制項。

' 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 服務,應用程式可以在程式碼群組區域之間分享資料。 根據預設,近端內部網路和網際網路區域中的應用程式會被授與權限來存取他們的來源網站,讓他們能夠呼叫相同的伺服器上裝載的 Web 服務。 如需詳細資訊,請參閱 ASP.NET AJAX Windows Communication Foundation 中的 Web 服務。

登錄存取

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

因為您無法在部分信任下存取登錄,您可能需要尋找儲存資料的其他方法。 當您儲存應用程式設定時,使用隔離儲存區,而不是登錄。 隔離儲存區也可以用來儲存其他應用程式特定的檔案。 您也可以儲存與伺服器或來源網站相關的全域應用程式資訊,因為根據預設,應用程式被授與存取其來源網站的權限。

另請參閱