共用方式為


Windows 資訊保護 (WIP) 開發人員指南

啟發式應用程式可以區分公司資料和個人資料,並根據管理員定義的 Windows 資訊保護 (WIP) 原則知道要保護哪些資料。

在此指南中,我們將向您介紹如何建立此類應用程式。 完成後,原則管理員將能夠信任您的應用程式來使用其組織的資料。 而員工則會很高興得知,就算他們從組織的行動裝置管理 (MDM) 取消註冊,或是完全離該組織,他們的個人資料也能在裝置上保持不變。

注意 本指南可協助您啟發 UWP 應用程式。 如果您想了解 C++ Windows 桌面應用程式,請參閱 Windows 資訊保護 (WIP) 開發人員指南 (C++)

您可以在此處閱讀有關 WIP 和啟發式應用程式的更多資訊:Windows 資訊保護 (WIP)

您可以在這裡找到完整的範例。

如果您已準備好完成每項工作,那我們就開始吧。

首先,準備好所需的前置條件

您將會需要:

  • 執行 Windows 10 版本 1607 或更新版本的測試虛擬機器 (VM)。 您將針對此測試虛擬機器偵錯您的應用程式。

  • 執行 Windows 10 版本 1607 或更新版本的開發電腦。 如果您安裝了 Visual Studio,則該電腦可以做為您的測試 VM。

設定開發環境

您將執行下列工作︰

將 WIP 設定開發人員助理安裝到測試 VM

使用此工具在測試 VM 上設定 Windows 資訊保護原則。

在這裡下載工具:WIP 設定開發人員助理

建立保護原則

將資訊新增至 WIP 設定開發人員助理中的各個區段,以定義您的原則。 選擇任何設定旁邊的幫助圖示,以了解有關如何使用它的更多資訊。

有關更多使用此工具的通用指南,請參閱應用程式下載頁面上的版本說明區段。

設定 Visual Studio 專案

  1. 在您的開發電腦上,開啟您的專案。

  2. 新增對通用 Windows 平台 (UWP) 的桌面和行動擴充功能的參考。

    新增UWP擴充功能

  3. 將此功能新增至您的套件資訊清單檔案:

       <rescap:Capability Name="enterpriseDataPolicy"/>
    

    選擇性閱讀:「rescap」前置詞代表受限功能。 請參閱特殊和受限功能

  4. 將此命名空間新增至您的套件資訊清單檔案:

      xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
    
  5. 將命名空間前置詞新增至套件資訊清單檔案的 <ignorableNamespaces> 元素。

        <IgnorableNamespaces="uap mp rescap">
    

    這樣,如果您的應用程式在不支援受限功能的 Windows 作業系統版本上執行,Windows 將忽略 enterpriseDataPolicy 功能。

安裝程式遠端偵錯

只有在您在 VM 以外的電腦上開發應用程式時,才在測試 VM 上安裝 Visual Studio 遠端工具。 然後,在您的開發電腦上啟動遠端偵錯工具,並查看您的應用程式是否在測試 VM 上執行。

請參閱遠端電腦指示

將這些命名空間新增至程式碼檔案

將這些 using 陳述式新增到程式碼檔案頂端 (本指南中的程式碼片段會使用它們):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Security.EnterpriseData;
using Windows.Web.Http;
using Windows.Storage.Streams;
using Windows.ApplicationModel.DataTransfer;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml;
using Windows.ApplicationModel.Activation;
using Windows.Web.Http.Filters;
using Windows.Storage;
using Windows.Data.Xml.Dom;
using Windows.Foundation.Metadata;
using Windows.Web.Http.Headers;

判斷是否要在您的應用程式中使用 WIP API

請確定執行應用程式的作業系統支援 WIP,且裝置上已啟用 WIP。

bool use_WIP_APIs = false;

if ((ApiInformation.IsApiContractPresent
    ("Windows.Security.EnterpriseData.EnterpriseDataContract", 3)
    && ProtectionPolicyManager.IsProtectionEnabled))
{
    use_WIP_APIs = true;
}
else
{
    use_WIP_APIs = false;
}

如果作業系統不支援 WIP 或裝置未啟用 WIP,請勿呼叫 WIP API。

讀取企業資料

若要讀取受保護的檔案、網路端點、剪貼簿資料以及您從共用合約中接受的資料,您的應用程式必須要求存取權。

如果您的應用程式位於保護原則允許清單中,則 Windows 資訊保護會授予您的應用程式權限。

本節內容:

從檔案讀取資料

步驟 1:取得檔案控制代碼

    Windows.Storage.StorageFolder storageFolder =
        Windows.Storage.ApplicationData.Current.LocalFolder;

    Windows.Storage.StorageFile file =
        await storageFolder.GetFileAsync(fileName);

步驟 2:判斷您的應用程式是否可以開啟檔案

呼叫 FileProtectionManager.GetProtectionInfoAsync 來判斷您的應用程式是否可以開啟檔案。

FileProtectionInfo protectionInfo = await FileProtectionManager.GetProtectionInfoAsync(file);

if ((protectionInfo.Status != FileProtectionStatus.Protected &&
    protectionInfo.Status != FileProtectionStatus.Unprotected))
{
    return false;
}
else if (protectionInfo.Status == FileProtectionStatus.Revoked)
{
    // Code goes here to handle this situation. Perhaps, show UI
    // saying that the user's data has been revoked.
}

ProtectedFileProtectionStatus 值表示該檔案受到保護,並且您的應用程式可以開啟它,因為您的應用程式位於原則的允許清單中。

UnProtectedFileProtectionStatus 值表示該檔案不受保護,即使您的應用程式不在原則的允許清單中,您的應用程式也可以開啟該檔案。

API
FileProtectionManager.GetProtectionInfoAsync
FileProtectionInfo
FileProtectionStatus
ProtectionPolicyManager.IsIdentityManaged

步驟 3:將檔案讀入資料流或緩衝區

將檔案讀入資料流

var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);

將檔案讀入緩衝區

var buffer = await Windows.Storage.FileIO.ReadBufferAsync(file);

從網路端點讀取資料

建立受保護的執行緒內容,以從企業端點讀取。

步驟 1:取得網路端點的身分識別

Uri resourceURI = new Uri("http://contoso.com/stockData.xml");

Windows.Networking.HostName hostName =
    new Windows.Networking.HostName(resourceURI.Host);

string identity = await ProtectionPolicyManager.
    GetPrimaryManagedIdentityForNetworkEndpointAsync(hostName);

如果端點不受原則管理,您將會傳回空白字串。

API
ProtectionPolicyManager.GetPrimaryManagedIdentityForNetworkEndpointAsync

步驟 2:建立受保護的執行緒內容

如果端點是由原則管理,則建立受保護的執行緒內容。 這會將您在同一執行緒上建立的任何網路連線標記到該身分識別。

它還可讓您存取由該原則管理的企業網路資源。

if (!string.IsNullOrEmpty(identity))
{
    using (ThreadNetworkContext threadNetworkContext =
            ProtectionPolicyManager.CreateCurrentThreadNetworkContext(identity))
    {
        return await GetDataFromNetworkRedirectHelperMethod(resourceURI);
    }
}
else
{
    return await GetDataFromNetworkRedirectHelperMethod(resourceURI);
}

此範例會將通訊端呼叫包含在 using 區塊中。 如果您不這樣做,請確定在擷取資源後關閉執行緒內容。 請參閱 ThreadNetworkContext.Close

不要在該受保護的執行緒上建立任何個人檔案,因為這些檔案將自動加密。

無論端點是否由原則管理,ProtectionPolicyManager.CreateCurrentThreadNetworkContext 方法都會傳回 ThreadNetworkContext 物件。 如果您的應用程式同時處理個人和企業資源,請為所有身分識別呼叫 ProtectionPolicyManager.CreateCurrentThreadNetworkContext。 取得資源後,請處置 ThreadNetworkContext 以清除目前執行緒中的任何身分識別標記。

API
ProtectionPolicyManager.GetForCurrentView
ProtectionPolicyManager.Identity
ProtectionPolicyManager.CreateCurrentThreadNetworkContext

步驟 3:將資源讀入緩衝區

private static async Task<IBuffer> GetDataFromNetworkHelperMethod(Uri resourceURI)
{
    HttpClient client;

    client = new HttpClient();

    try { return await client.GetBufferAsync(resourceURI); }

    catch (Exception) { return null; }
}

(選用) 使用標頭權杖,而不是建立受保護的執行緒內容

public static async Task<IBuffer> GetDataFromNetworkbyUsingHeader(Uri resourceURI)
{
    HttpClient client;

    Windows.Networking.HostName hostName =
        new Windows.Networking.HostName(resourceURI.Host);

    string identity = await ProtectionPolicyManager.
        GetPrimaryManagedIdentityForNetworkEndpointAsync(hostName);

    if (!string.IsNullOrEmpty(identity))
    {
        client = new HttpClient();

        HttpRequestHeaderCollection headerCollection = client.DefaultRequestHeaders;

        headerCollection.Add("X-MS-Windows-HttpClient-EnterpriseId", identity);

        return await GetDataFromNetworkbyUsingHeaderHelperMethod(client, resourceURI);
    }
    else
    {
        client = new HttpClient();
        return await GetDataFromNetworkbyUsingHeaderHelperMethod(client, resourceURI);
    }

}

private static async Task<IBuffer> GetDataFromNetworkbyUsingHeaderHelperMethod(HttpClient client, Uri resourceURI)
{

    try { return await client.GetBufferAsync(resourceURI); }

    catch (Exception) { return null; }
}

處理頁面重新導向

有時候網頁伺服器會將流量重新導向至較新版本的資源。

若要處理此問題,請發出要求,直到要求的回應狀態值為 OK

然後使用該回應的 URI 來取得端點的身分識別。 以下是執行此動作的其中一種方式:

private static async Task<IBuffer> GetDataFromNetworkRedirectHelperMethod(Uri resourceURI)
{
    HttpClient client = null;

    HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();
    filter.AllowAutoRedirect = false;

    client = new HttpClient(filter);

    HttpResponseMessage response = null;

        HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, resourceURI);
        response = await client.SendRequestAsync(message);

    if (response.StatusCode == HttpStatusCode.MultipleChoices ||
        response.StatusCode == HttpStatusCode.MovedPermanently ||
        response.StatusCode == HttpStatusCode.Found ||
        response.StatusCode == HttpStatusCode.SeeOther ||
        response.StatusCode == HttpStatusCode.NotModified ||
        response.StatusCode == HttpStatusCode.UseProxy ||
        response.StatusCode == HttpStatusCode.TemporaryRedirect ||
        response.StatusCode == HttpStatusCode.PermanentRedirect)
    {
        message = new HttpRequestMessage(HttpMethod.Get, message.RequestUri);
        response = await client.SendRequestAsync(message);

        try { return await response.Content.ReadAsBufferAsync(); }

        catch (Exception) { return null; }
    }
    else
    {
        try { return await response.Content.ReadAsBufferAsync(); }

        catch (Exception) { return null; }
    }
}

API
ProtectionPolicyManager.GetPrimaryManagedIdentityForNetworkEndpointAsync
ProtectionPolicyManager.CreateCurrentThreadNetworkContext
ProtectionPolicyManager.GetForCurrentView
ProtectionPolicyManager.Identity

從剪貼簿讀取資料

取得使用剪貼簿資料的權限

若要從剪貼簿取得資料,請要求 Windows 權限。 使用 DataPackageView.RequestAccessAsync 來執行該動作。

public static async Task PasteText(TextBox textBox)
{
    DataPackageView dataPackageView = Clipboard.GetContent();

    if (dataPackageView.Contains(StandardDataFormats.Text))
    {
        ProtectionPolicyEvaluationResult result = await dataPackageView.RequestAccessAsync();

        if (result == ProtectionPolicyEvaluationResult..Allowed)
        {
            string contentsOfClipboard = await dataPackageView.GetTextAsync();
            textBox.Text = contentsOfClipboard;
        }
    }
}

API
DataPackageView.RequestAccessAsync

隱藏或停用使用剪貼簿資料的功能

判斷目前視圖是否有權取得剪貼簿上的資料。

如果沒有,您可以停用或隱藏允許使用者從剪貼簿貼上資訊或預覽其內容的控制項。

private bool IsClipboardAllowedAsync()
{
    ProtectionPolicyEvaluationResult protectionPolicyEvaluationResult = ProtectionPolicyEvaluationResult.Blocked;

    DataPackageView dataPackageView = Clipboard.GetContent();

    if (dataPackageView.Contains(StandardDataFormats.Text))

        protectionPolicyEvaluationResult =
            ProtectionPolicyManager.CheckAccess(dataPackageView.Properties.EnterpriseId,
                ProtectionPolicyManager.GetForCurrentView().Identity);

    return (protectionPolicyEvaluationResult == ProtectionPolicyEvaluationResult.Allowed |
        protectionPolicyEvaluationResult == ProtectionPolicyEvaluationResult.ConsentRequired);
}

API
ProtectionPolicyEvaluationResult
ProtectionPolicyManager.GetForCurrentView
ProtectionPolicyManager.Identity

防止使用者收到同意對話方塊提示

新文件不是個人企業的。 就只是新文件。 如果使用者將企業資料貼到其中,Windows 會強制執行原則,並會透過同意對話方塊來提示使用者。 這段程式碼可以防止這種情況發生。 這項工作不是為了協助保護資料。 而為了在您的應用程式建立全新項目時,阻止使用者收到同意對話方塊。

private async void PasteText(bool isNewEmptyDocument)
{
    DataPackageView dataPackageView = Clipboard.GetContent();

    if (dataPackageView.Contains(StandardDataFormats.Text))
    {
        if (!string.IsNullOrEmpty(dataPackageView.Properties.EnterpriseId))
        {
            if (isNewEmptyDocument)
            {
                ProtectionPolicyManager.TryApplyProcessUIPolicy(dataPackageView.Properties.EnterpriseId);
                string contentsOfClipboard = contentsOfClipboard = await dataPackageView.GetTextAsync();
                // add this string to the new item or document here.          

            }
            else
            {
                ProtectionPolicyEvaluationResult result = await dataPackageView.RequestAccessAsync();

                if (result == ProtectionPolicyEvaluationResult.Allowed)
                {
                    string contentsOfClipboard = contentsOfClipboard = await dataPackageView.GetTextAsync();
                    // add this string to the new item or document here.
                }
            }
        }
    }
}

API
DataPackageView.RequestAccessAsync
ProtectionPolicyEvaluationResult
ProtectionPolicyManager.TryApplyProcessUIPolicy

從共用合約讀取資料

當員工選擇您的應用程式來分享他們的資訊時,您的應用程式將開啟一個包含該內容的新項目。

如先前所述,新項目不是個人企業的。 就只是新文件。 如果您的程式碼將企業內容新增至項目中,Windows 會強制執行原則,並會透過同意對話方塊提示使用者。 這段程式碼可以防止這種情況發生。

protected override async void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
    bool isNewEmptyDocument = true;
    string identity = "corp.microsoft.com";

    ShareOperation shareOperation = args.ShareOperation;
    if (shareOperation.Data.Contains(StandardDataFormats.Text))
    {
        if (!string.IsNullOrEmpty(shareOperation.Data.Properties.EnterpriseId))
        {
            if (isNewEmptyDocument)
                // If this is a new and empty document, and we're allowed to access
                // the data, then we can avoid popping the consent dialog
                ProtectionPolicyManager.TryApplyProcessUIPolicy(shareOperation.Data.Properties.EnterpriseId);
            else
            {
                // In this case, we can't optimize the workflow, so we just
                // request consent from the user in this case.

                ProtectionPolicyEvaluationResult protectionPolicyEvaluationResult = await shareOperation.Data.RequestAccessAsync();

                if (protectionPolicyEvaluationResult == ProtectionPolicyEvaluationResult.Allowed)
                {
                    string text = await shareOperation.Data.GetTextAsync();

                    // Do something with that text.
                }
            }
        }
        else
        {
            // If the data has no enterprise identity, then we already have access.
            string text = await shareOperation.Data.GetTextAsync();

            // Do something with that text.
        }

    }

}

API
ProtectionPolicyManager.RequestAccessAsync
ProtectionPolicyEvaluationResult
ProtectionPolicyManager.TryApplyProcessUIPolicy

保護企業資料

保護離開您應用程式的企業資料。 當您在頁面中顯示資料、將其儲存到檔案或網路端點或透過共用合約儲存資料時,資料就會離開您的應用程式。

本節內容:

保護頁面中出現的資料

當您在頁面中顯示資料時,讓 Windows 知道它是什麼類型的資料 (個人或企業)。 為此,請標記目前應用程式視圖或標記整個應用程式程序。

當您標記檢視或程序時,Windows 會在該檢視上強制執行原則。 這有助於防止因應用程式無法控制的動作而導致的資料外洩。 例如,在電腦上,使用者可以使用 CTRL-V 從視圖複製企業訊息,然後將該資訊貼上到另一個應用程式。 Windows 可防止這種情況發生。 Windows 也有助於強制執行共用合約。

標記目前的應用程式檢視

如果您的應用程式有多個視圖,而其中某些視圖取用企業資料,有些視圖取用個人資料,則執行此動作。


// tag as enterprise data. "identity" the string that contains the enterprise ID.
// You'd get that from a file, network endpoint, or clipboard data package.
ProtectionPolicyManager.GetForCurrentView().Identity = identity;

// tag as personal data.
ProtectionPolicyManager.GetForCurrentView().Identity = String.Empty;

API
ProtectionPolicyManager.GetForCurrentView
ProtectionPolicyManager.Identity

標記程序

如果應用程式中的所有視圖僅使用一種類型的資料 (個人或企業),則執行此動作。

這可讓您不必管理獨立標記的視圖。



// tag as enterprise data. "identity" the string that contains the enterprise ID.
// You'd get that from a file, network endpoint, or clipboard data package.
bool result =
            ProtectionPolicyManager.TryApplyProcessUIPolicy(identity);

// tag as personal data.
ProtectionPolicyManager.ClearProcessUIPolicy();

API
ProtectionPolicyManager.TryApplyProcessUIPolicy

保護檔案的資料

建立受保護的檔案,然後對其進行寫入。

步驟 1:確定您的應用程式是否可以建立企業檔案

如果身分識別字串由原則管理,並且您的應用程式位於該原則的允許清單中,則您的應用程式可以建立企業檔案。

  if (!ProtectionPolicyManager.IsIdentityManaged(identity)) return false;

API
ProtectionPolicyManager.IsIdentityManaged

步驟 2:建立檔案並保護其身分識別

StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
StorageFile storageFile = await storageFolder.CreateFileAsync("sample.txt",
    CreationCollisionOption.ReplaceExisting);

FileProtectionInfo fileProtectionInfo =
    await FileProtectionManager.ProtectAsync(storageFile, identity);

API
FileProtectionManager.ProtectAsync

步驟 3:將該資料流或緩衝區寫入檔案

寫入資料流

    if (fileProtectionInfo.Status == FileProtectionStatus.Protected)
    {
        var stream = await storageFile.OpenAsync(FileAccessMode.ReadWrite);

        using (var outputStream = stream.GetOutputStreamAt(0))
        {
            using (var dataWriter = new DataWriter(outputStream))
            {
                dataWriter.WriteString(enterpriseData);
            }
        }

    }

寫入緩衝區

     if (fileProtectionInfo.Status == FileProtectionStatus.Protected)
     {
         var buffer = Windows.Security.Cryptography.CryptographicBuffer.ConvertStringToBinary(
             enterpriseData, Windows.Security.Cryptography.BinaryStringEncoding.Utf8);

         await FileIO.WriteBufferAsync(storageFile, buffer);

      }

API
FileProtectionInfo
FileProtectionStatus

以背景程序的形式保護檔案的資料

此程式碼可以在裝置螢幕鎖定時執行。 如果管理員配置了安全的「鎖定資料保護」(DPL) 原則,Windows 將從裝置記憶體中刪除存取受保護資源所需的加密金鑰。 如果裝置遺失,這可以防止資料外洩。 當受保護檔案的控制代碼關閉時,該功能也會刪除與受保護檔案關聯的金鑰。

您必須使用一種方法,在建立檔案時保持檔案控制代碼開啟。

步驟 1:確定您是否可以建立企業檔案

如果您使用的身分識別由原則管理,且您的應用程式位於該原則的允許清單中,則可以建立企業檔案。

if (!ProtectionPolicyManager.IsIdentityManaged(identity)) return false;

API
ProtectionPolicyManager.IsIdentityManaged

步驟 2:建立檔案並保護其身分識別

FileProtectionManager.CreateProtectedAndOpenAsync 會建立受保護的檔案,並在寫入檔案時保持檔案控制代碼開啟。

StorageFolder storageFolder = ApplicationData.Current.LocalFolder;

ProtectedFileCreateResult protectedFileCreateResult =
    await FileProtectionManager.CreateProtectedAndOpenAsync(storageFolder,
        "sample.txt", identity, CreationCollisionOption.ReplaceExisting);

API
FileProtectionManager.CreateProtectedAndOpenAsync

步驟 3:將資料流或緩衝區寫入檔案

此範例將資料流寫入檔案。

if (protectedFileCreateResult.ProtectionInfo.Status == FileProtectionStatus.Protected)
{
    IOutputStream outputStream =
        protectedFileCreateResult.Stream.GetOutputStreamAt(0);

    using (DataWriter writer = new DataWriter(outputStream))
    {
        writer.WriteString(enterpriseData);
        await writer.StoreAsync();
        await writer.FlushAsync();
    }

    outputStream.Dispose();
}
else if (protectedFileCreateResult.ProtectionInfo.Status == FileProtectionStatus.AccessSuspended)
{
    // Perform any special processing for the access suspended case.
}

API
ProtectedFileCreateResult.ProtectionInfo
FileProtectionStatus
ProtectedFileCreateResult.Stream

保護檔案的一部分

在大多數情況下,將企業資料和個人資料分開儲存會更清楚明瞭,但如果需要,您也可以將它們儲存到同一個檔案中。 例如,Microsoft Outlook 可以將企業郵件與個人郵件一起儲存在單一封存檔案中。

加密企業資料,但不加密整個檔案。 如此一來,即使使用者從 MDM 取消註冊或其企業資料存取權遭到撤銷,也可以繼續使用該檔案。 此外,您的應用程式應該追蹤它加密的資料,以便在將檔案讀回記憶體時知道要保護哪些資料。

步驟 1:將企業資料新增至加密的資料流或緩衝區

string enterpriseDataString = "<employees><employee><name>Bill</name><social>xxx-xxx-xxxx</social></employee></employees>";

var enterpriseData= Windows.Security.Cryptography.CryptographicBuffer.ConvertStringToBinary(
        enterpriseDataString, Windows.Security.Cryptography.BinaryStringEncoding.Utf8);

BufferProtectUnprotectResult result =
   await DataProtectionManager.ProtectAsync(enterpriseData, identity);

enterpriseData= result.Buffer;

API
DataProtectionManager.ProtectAsync
BufferProtectUnprotectResult.buffer

步驟 2:將個人資料新增至未加密的資料流或緩衝區

string personalDataString = "<recipies><recipe><name>BillsCupCakes</name><cooktime>30</cooktime></recipe></recipies>";

var personalData = Windows.Security.Cryptography.CryptographicBuffer.ConvertStringToBinary(
    personalDataString, Windows.Security.Cryptography.BinaryStringEncoding.Utf8);

步驟 3:將資料流或緩衝區寫入檔案

StorageFolder storageFolder = ApplicationData.Current.LocalFolder;

StorageFile storageFile = await storageFolder.CreateFileAsync("data.xml",
    CreationCollisionOption.ReplaceExisting);

 // Write both buffers to the file and save the file.

var stream = await storageFile.OpenAsync(FileAccessMode.ReadWrite);

using (var outputStream = stream.GetOutputStreamAt(0))
{
    using (var dataWriter = new DataWriter(outputStream))
    {
        dataWriter.WriteBuffer(enterpriseData);
        dataWriter.WriteBuffer(personalData);

        await dataWriter.StoreAsync();
        await outputStream.FlushAsync();
    }
}

步驟 4:追蹤檔案中企業資料的位置

您的應用程式有責任追蹤該檔案中企業所擁有的資料。

您可以將該資訊儲存在與檔案相關聯的屬性、資料庫,或檔案的某些標頭文字中。

本範例將該資訊儲存到個別的 XML 檔案中。

StorageFile metaDataFile = await storageFolder.CreateFileAsync("metadata.xml",
   CreationCollisionOption.ReplaceExisting);

await Windows.Storage.FileIO.WriteTextAsync
    (metaDataFile, "<EnterpriseDataMarker start='0' end='" + enterpriseData.Length.ToString() +
    "'></EnterpriseDataMarker>");

讀取檔案的受保護部分

以下是從該檔案中讀取企業資料的方法。

步驟 1:取得您企業資料在檔案中的位置

Windows.Storage.StorageFolder storageFolder =
    Windows.Storage.ApplicationData.Current.LocalFolder;

 Windows.Storage.StorageFile metaDataFile =
   await storageFolder.GetFileAsync("metadata.xml");

string metaData = await Windows.Storage.FileIO.ReadTextAsync(metaDataFile);

XmlDocument doc = new XmlDocument();

doc.LoadXml(metaData);

uint startPosition =
    Convert.ToUInt16((doc.FirstChild.Attributes.GetNamedItem("start")).InnerText);

uint endPosition =
    Convert.ToUInt16((doc.FirstChild.Attributes.GetNamedItem("end")).InnerText);

步驟 2:開啟資料檔,並確定它未受到保護

Windows.Storage.StorageFile dataFile =
    await storageFolder.GetFileAsync("data.xml");

FileProtectionInfo protectionInfo =
    await FileProtectionManager.GetProtectionInfoAsync(dataFile);

if (protectionInfo.Status == FileProtectionStatus.Protected)
    return false;

API
FileProtectionManager.GetProtectionInfoAsync
FileProtectionInfo
FileProtectionStatus

步驟 3:從檔案讀取企業資料

var stream = await dataFile.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);

stream.Seek(startPosition);

Windows.Storage.Streams.Buffer tempBuffer = new Windows.Storage.Streams.Buffer(50000);

IBuffer enterpriseData = await stream.ReadAsync(tempBuffer, endPosition, InputStreamOptions.None);

步驟 4:解密包含企業資料的緩衝區

DataProtectionInfo dataProtectionInfo =
   await DataProtectionManager.GetProtectionInfoAsync(enterpriseData);

if (dataProtectionInfo.Status == DataProtectionStatus.Protected)
{
    BufferProtectUnprotectResult result = await DataProtectionManager.UnprotectAsync(enterpriseData);
    enterpriseData = result.Buffer;
}
else if (dataProtectionInfo.Status == DataProtectionStatus.Revoked)
{
    // Code goes here to handle this situation. Perhaps, show UI
    // saying that the user's data has been revoked.
}

API
DataProtectionInfo
DataProtectionManager.GetProtectionInfoAsync

保護資料夾的資料

您可以建立資料夾並保護它。 如此一來,您新增至該資料夾的任何專案都會自動受到保護。

private async Task<bool> CreateANewFolderAndProtectItAsync(string folderName, string identity)
{
    if (!ProtectionPolicyManager.IsIdentityManaged(identity)) return false;

    StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
    StorageFolder newStorageFolder =
        await storageFolder.CreateFolderAsync(folderName);

    FileProtectionInfo fileProtectionInfo =
        await FileProtectionManager.ProtectAsync(newStorageFolder, identity);

    if (fileProtectionInfo.Status != FileProtectionStatus.Protected)
    {
        // Protection failed.
        return false;
    }
    return true;
}

在保護資料夾之前,請確定資料夾是空的。 您無法保護已經包含項目的資料夾。

API
ProtectionPolicyManager.IsIdentityManaged
FileProtectionManager.ProtectAsync
FileProtectionInfo.Identity
FileProtectionInfo.Status

保護資料到網路端點

建立受保護的執行緒內容,以將資料傳送至企業端點。

步驟 1:取得網路端點的身分識別

Windows.Networking.HostName hostName =
    new Windows.Networking.HostName(resourceURI.Host);

string identity = await ProtectionPolicyManager.
    GetPrimaryManagedIdentityForNetworkEndpointAsync(hostName);

API
ProtectionPolicyManager.GetPrimaryManagedIdentityForNetworkEndpointAsync

步驟 2:建立受保護的執行緒內容,並將資料傳送至網路端點

HttpClient client = null;

if (!string.IsNullOrEmpty(m_EnterpriseId))
{
    ProtectionPolicyManager.GetForCurrentView().Identity = identity;

    using (ThreadNetworkContext threadNetworkContext =
            ProtectionPolicyManager.CreateCurrentThreadNetworkContext(identity))
    {
        client = new HttpClient();
        HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Put, resourceURI);
        message.Content = new HttpStreamContent(dataToWrite);

        HttpResponseMessage response = await client.SendRequestAsync(message);

        if (response.StatusCode == HttpStatusCode.Ok)
            return true;
        else
            return false;
    }
}
else
{
    return false;
}

API
ProtectionPolicyManager.GetForCurrentView
ProtectionPolicyManager.Identity
ProtectionPolicyManager.CreateCurrentThreadNetworkContext

保護應用程式透過共用合約共用的資料

如果您希望使用者共用應用程式中的內容,則必須實作共用合約,並處理 DataTransferManager.DataRequested 事件。

在您的事件處理常式中,在資料套件中設定企業身分識別內容。

private void OnShareSourceOperation(object sender, RoutedEventArgs e)
{
    // Register the current page as a share source (or you could do this earlier in your app).
    DataTransferManager.GetForCurrentView().DataRequested += OnDataRequested;
    DataTransferManager.ShowShareUI();
}

private void OnDataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
    if (!string.IsNullOrEmpty(this.shareSourceContent))
    {
        var protectionPolicyManager = ProtectionPolicyManager.GetForCurrentView();
        DataPackage requestData = args.Request.Data;
        requestData.Properties.Title = this.shareSourceTitle;
        requestData.Properties.EnterpriseId = protectionPolicyManager.Identity;
        requestData.SetText(this.shareSourceContent);
    }
}

API
ProtectionPolicyManager.GetForCurrentView
ProtectionPolicyManager.Identity

保護您複製到其他位置的檔案

private async void CopyProtectionFromOneFileToAnother
    (StorageFile sourceStorageFile, StorageFile targetStorageFile)
{
    bool copyResult = await
        FileProtectionManager.CopyProtectionAsync(sourceStorageFile, targetStorageFile);

    if (!copyResult)
    {
        // Copying failed. To diagnose, you could check the file's status.
        // (call FileProtectionManager.GetProtectionInfoAsync and
        // check FileProtectionInfo.Status).
    }
}

API
FileProtectionManager.CopyProtectionAsync

裝置螢幕鎖定時保護企業資料

裝置鎖定時,請移除記憶體中的所有敏感資料。 當使用者解鎖裝置時,您的應用程式可以安全地將該資料新增回來。

處理 ProtectionPolicyManager.ProtectedAccessSuspending 事件,以便您的應用程式知道螢幕何時鎖定。 只有當管理員在鎖定原則下設定安全資料保護時,才會引發此事件。 Windows 會暫時移除裝置上佈建的資料保護金鑰。 Windows 會刪除這些金鑰,以確保在裝置已鎖定且使用者可能並非其擁有者的情況下,不會未經授權存取加密的資料。

處理 ProtectionPolicyManager.ProtectedAccessResumed 事件,以便您的應用程式知道螢幕何時解鎖。 無論管理員是否在鎖定原則下設定安全資料保護,都會引發此事件。

螢幕鎖定時,移除記憶體中的敏感資料

保護敏感資料,並關閉應用程式在受保護檔案上開啟的所有檔案資料流,以幫助確保系統不會在記憶體中快取任何敏感資料。

此範例將文字區塊中的內容儲存到加密緩衝區,並從該文字區塊中移除內容。

private async void ProtectionPolicyManager_ProtectedAccessSuspending(object sender, ProtectedAccessSuspendingEventArgs e)
{
    Deferral deferral = e.GetDeferral();

    if (ProtectionPolicyManager.GetForCurrentView().Identity != String.Empty)
    {
        IBuffer documentBodyBuffer = CryptographicBuffer.ConvertStringToBinary
           (documentTextBlock.Text, BinaryStringEncoding.Utf8);

        BufferProtectUnprotectResult result = await DataProtectionManager.ProtectAsync
            (documentBodyBuffer, ProtectionPolicyManager.GetForCurrentView().Identity);

        if (result.ProtectionInfo.Status == DataProtectionStatus.Protected)
        {
            this.protectedDocumentBuffer = result.Buffer;
            documentTextBlock.Text = null;
        }
    }

    // Close any open streams that you are actively working with
    // to make sure that we have no unprotected content in memory.

    // Optionally, code goes here to use e.Deadline to determine whether we have more
    // than 15 seconds left before the suspension deadline. If we do then process any
    // messages queued up for sending while we are still able to access them.

    deferral.Complete();
}

API
ProtectionPolicyManager.ProtectedAccessSuspending
ProtectionPolicyManager.GetForCurrentView
ProtectionPolicyManager.Identity
DataProtectionManager.ProtectAsync
BufferProtectUnprotectResult.buffer
ProtectedAccessSuspendingEventArgs.GetDeferral
Deferral.Complete

裝置解除鎖定時,將敏感資料新增回來

當裝置解鎖且金鑰在裝置上再次可用時,將引發 ProtectionPolicyManager.ProtectedAccessResumed

如果管理員未在鎖定原則下設定安全資料保護,則 ProtectedAccessResumedEventArgs.Identities 為空集合。

此範例與上一個範例相反。 它會解密緩衝區,將該緩衝區中的資訊新增回文字框,然後處置該緩衝區。

private async void ProtectionPolicyManager_ProtectedAccessResumed(object sender, ProtectedAccessResumedEventArgs e)
{
    if (ProtectionPolicyManager.GetForCurrentView().Identity != String.Empty)
    {
        BufferProtectUnprotectResult result = await DataProtectionManager.UnprotectAsync
            (this.protectedDocumentBuffer);

        if (result.ProtectionInfo.Status == DataProtectionStatus.Unprotected)
        {
            // Restore the unprotected version.
            documentTextBlock.Text = CryptographicBuffer.ConvertBinaryToString
                (BinaryStringEncoding.Utf8, result.Buffer);
            this.protectedDocumentBuffer = null;
        }
    }

}

API
ProtectionPolicyManager.ProtectedAccessResumed
ProtectionPolicyManager.GetForCurrentView
ProtectionPolicyManager.Identity
DataProtectionManager.UnprotectAsync
BufferProtectUnprotectResult.Status

當受保護的內容撤銷時處理企業資料

如果您希望您的應用程式在裝置從 MDM 取消註冊或原則管理員明確撤銷對企業資料的存取權時收到通知,請處理 ProtectionPolicyManager_ProtectedContentRevoked 事件。

此範例判斷電子郵件應用程式的企業郵箱中的資料是否已撤銷。

private string mailIdentity = "contoso.com";

void MailAppSetup()
{
    ProtectionPolicyManager.ProtectedContentRevoked += ProtectionPolicyManager_ProtectedContentRevoked;
    // Code goes here to set up mailbox for 'mailIdentity'.
}

private void ProtectionPolicyManager_ProtectedContentRevoked(object sender, ProtectedContentRevokedEventArgs e)
{
    if (!new System.Collections.Generic.List<string>(e.Identities).Contains
        (this.mailIdentity))
    {
        // This event is not for our identity.
        return;
    }

    // Code goes here to delete any metadata associated with 'mailIdentity'.
}

API
ProtectionPolicyManager_ProtectedContentRevoked

Windows 資訊保護 (WIP) 範例