Руководство разработчика Windows Information Protection (WIP)

Просвещенное приложение отличается от корпоративных и персональных данных и знает, какие средства защиты следует защищать на основе политик Windows Information Protection (WIP), определенных администратором.

В этом руководстве мы покажем, как создать его. По завершении администраторы политик смогут доверять приложению использовать данные своей организации. И сотрудники будут любить, что вы сохранили свои персональные данные нетронутыми на своем устройстве, даже если они не регистрируются из управления мобильными устройствами организации (MDM) или покидают организацию полностью.

Примечание. Это руководство поможет вам просвещать приложение UWP. Если вы хотите просвещать классическое приложение C++ для Windows, ознакомьтесь с руководством разработчика Windows Information Protection (WIP) (C++).

Дополнительные сведения о WIP и просвещенных приложениях см. здесь: Windows Information Protection (WIP).

Полный пример можно найти здесь.

Если вы готовы пройти каждую задачу, давайте начнем.

Сначала соберите необходимые сведения

Вам потребуется следующее:

  • Тестовая виртуальная машина, которая работает под управлением Windows 10 версии 1607 или более поздней. Приложение будет отлаживаться на этой тестовой виртуальной машине.

  • Компьютер разработки, работающий под управлением Windows 10 версии 1607 или более поздней версии. Это может быть тестовая виртуальная машина, если на ней установлена Visual Studio.

Настроить среду разработки.

Вы выполните следующие действия:

Установка помощника разработчика по настройке WIP на тестовую виртуальную машину

Используйте это средство для настройки политики Windows Information Protection на тестовой виртуальной машине.

Скачайте средство здесь: помощник разработчика по настройке 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 эту возможность.

Настройка удаленной отладки

Установите средства удаленной работы Visual Studio на тестовой виртуальной машине, только если вы разрабатываете приложение на компьютере, отличном от виртуальной машины. Затем на компьютере разработки запустите удаленный отладчик и проверьте, запущено ли приложение на тестовой виртуальной машине.

См . инструкции по удаленному компьютеру.

Добавление этих пространств имен в файлы кода

Добавьте эти инструкции 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;

Определение того, следует ли использовать API WIP в приложении

Убедитесь, что операционная система, на которой запущено приложение, поддерживает 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;
}

Не вызывайте API WIP, если операционная система не поддерживает WIP или WIP на устройстве.

Чтение корпоративных данных

Чтобы прочитать защищенные файлы, сетевые конечные точки, данные буфера обмена и данные, которые вы принимаете из контракта общего доступа, приложению потребуется запросить доступ.

Windows Information Protection предоставляет ваше приложение разрешение, если ваше приложение находится в списке разрешенных политик защиты.

В этом разделе:

Чтение данных из файла

Шаг 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.
}

Значение FileProtectionStatus в Protected означает, что файл защищен, и приложение может открыть его, так как ваше приложение находится в списке разрешенных политик.

Значение FileProtectionStatus в UnProtected означает, что файл не защищен, и ваше приложение может открыть файл, даже если приложение не находится в списке разрешенных политик.

Программные интерфейсы
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);

Если конечная точка не управляется политикой, вы получите пустую строку.

Программные интерфейсы
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, чтобы очистить любой тег удостоверения из текущего потока.

Программные интерфейсы
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; }
    }
}

Программные интерфейсы
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;
        }
    }
}

Программные интерфейсы
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);
}

Программные интерфейсы
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.
                }
            }
        }
    }
}

Программные интерфейсы
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.
        }

    }

}

Программные интерфейсы
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;

Программные интерфейсы
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();

Программные интерфейсы
ProtectionPolicyManager.TryApplyProcessUIPolicy

Защита данных в файле

Создайте защищенный файл и напишите в него.

Шаг 1. Определение того, может ли ваше приложение создать корпоративный файл

Приложение может создать корпоративный файл, если строка удостоверения управляется политикой, и ваше приложение находится в списке разрешенных политик.

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

Программные интерфейсы
ProtectionPolicyManager.IsIdentityManaged

Шаг 2. Создание файла и его защита для удостоверения

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

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

Программные интерфейсы
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);

      }

Программные интерфейсы
FileProtectionInfo
FileProtectionStatus

Защита данных в файле в качестве фонового процесса

Этот код может выполняться, пока экран устройства заблокирован. Если администратор настроил безопасную политику защиты данных под блокировкой (DPL), Windows удаляет ключи шифрования, необходимые для доступа к защищенным ресурсам из памяти устройства. Это предотвращает утечку данных, если устройство потеряно. Эта же функция также удаляет ключи, связанные с защищенными файлами при закрытии их дескрипторов.

При создании файла необходимо использовать подход, который сохраняет дескриптор файла открытым.

Шаг 1. Определение возможности создания корпоративного файла

Корпоративный файл можно создать, если используемое удостоверение управляется политикой, и приложение находится в списке разрешенных политик.

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

Программные интерфейсы
ProtectionPolicyManager.IsIdentityManaged

Шаг 2. Создание файла и его защита для удостоверения

FileProtectionManager.CreateProtectedAndOpenAsync создает защищенный файл и сохраняет дескриптор файла открытым во время записи.

StorageFolder storageFolder = ApplicationData.Current.LocalFolder;

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

Программные интерфейсы
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.
}

Программные интерфейсы
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;

Программные интерфейсы
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;

Программные интерфейсы
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.
}

Программные интерфейсы
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;
}

Перед защитой папки убедитесь, что папка пуста. Невозможно защитить папку, которая уже содержит элементы.

Программные интерфейсы
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);

Программные интерфейсы
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;
}

Программные интерфейсы
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);
    }
}

Программные интерфейсы
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).
    }
}

Программные интерфейсы
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();
}

Программные интерфейсы
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;
        }
    }

}

Программные интерфейсы
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'.
}

Программные интерфейсы
ProtectionPolicyManager_ProtectedContentRevoked

Пример Windows Information Protection (WIP)