Guida per gli sviluppatori di Windows Information Protection (WIP)

Un'app abilitata al riconoscimento dei dati distingue i dati aziendali da quelli personali e sa quali proteggere in base ai criteri di Windows Information Protection (WIP) definiti dall'amministratore.

In questa guida ti mostreremo come realizzarne una. Al termine, gli amministratori dei criteri saranno in grado di considerare attendibile l'utilizzo dei dati dell'organizzazione da parte dell'app. I dipendenti apprezzeranno il fatto che i loro dati personali rimangano intatti nel dispositivo anche se annullano la registrazione dal sistema di gestione di dispositivi mobili (MDM) dell'organizzazione o lasciano l'organizzazione.

Nota Questa guida ti aiuta ad abilitare al riconoscimento dei dati un'app UWP. Se desideri abilitare al riconoscimento dei dati un'app desktop di Windows C++, consulta Guida per gli sviluppatori di Windows Information Protection (WIP) (C++).

Per altre informazioni su WIP e sulle app con riconoscimento dei dati aziendali, consulta Windows Information Protection (WIP).

Un esempio completo è disponibile qui.

Se sei pronto per eseguire ogni attività, iniziamo.

Prima di tutto, occorre raccogliere ciò di cui avrai bisogno

Sarà necessario quanto segue:

  • Una macchina virtuale di test (VM) che esegue Windows 10 versione 1607 o successiva. Il debug dell'app sarà eseguito su questa macchina virtuale di test.

  • Un computer di sviluppo che esegue Windows 10, versione 1607 o successiva. Potrebbe trattarsi della macchina virtuale di test, se è installato Visual Studio.

Configurare l'ambiente di sviluppo

Eseguiremo queste operazioni:

Installare WIP Setup Developer Assistant sulla macchina virtuale di test

Usa questo strumento per configurare i criteri di Windows Information Protection sulla macchina virtuale di test.

Scarica lo strumento qui: WIP Setup Developer Assistant.

Creare i criteri di protezione

Definisci i criteri aggiungendo informazioni a ogni sezione di WIP Setup Developer Assistant. Scegli l'icona della Guida accanto a ogni impostazione per ulteriori informazioni su come usarla.

Per indicazioni più generali su come usare questo strumento, consulta la sezione Note sulla versione nella pagina di download dell'app.

Configurare un progetto di Visual Studio

  1. Sul computer di sviluppo apri il progetto.

  2. Aggiungi un riferimento alle estensioni desktop e per dispositivi mobili per Universal Windows Platform (UWP).

    Add UWP Extensions

  3. Aggiungi questa funzionalità al file manifesto del pacchetto:

       <rescap:Capability Name="enterpriseDataPolicy"/>
    

    Lettura facoltativa: il prefisso "rescap" indica una funzionalità con restrizioni. Consulta Funzionalità speciali e con restrizioni.

  4. Aggiungi questo spazio dei nomi al file manifesto del pacchetto:

      xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
    
  5. Aggiungi il prefisso dello spazio dei nomi all'elemento <ignorableNamespaces> del file manifesto del pacchetto.

        <IgnorableNamespaces="uap mp rescap">
    

    In questo modo, se l'app viene eseguita in una versione del sistema operativo Windows che non supporta funzionalità limitate, Windows ignorerà la funzionalità enterpriseDataPolicy.

Configurare il debug remoto

Installa Visual Studio Remote Tools nella macchina virtuale di test solo se si sviluppa l'app su un computer diverso dalla macchina virtuale. Quindi, sul computer di sviluppo avvia il debugger remoto e verifica se l'app viene eseguita nella macchina virtuale di test.

Consulta Istruzioni per il PC remoto.

Aggiungi questi spazi dei nomi ai file codice

Aggiungi queste istruzioni using all'inizio dei file di codice (i frammenti di codice in questa guida li usano):

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;

Determina se usare le API WIP nell'app

Assicurati che il sistema operativo che esegue l'app supporti WIP e che WIP sia abilitato nel dispositivo.

bool use_WIP_APIs = false;

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

Non chiamare le API WIP se il sistema operativo non supporta WIP o WIP non è abilitato nel dispositivo.

Lettura dei dati aziendali

Per leggere file protetti, endpoint di rete, dati degli Appunti e dati accettati da un contratto di condivisione, l'app dovrà richiedere l'autorizzazione all'accesso.

Windows Information Protection concede all'app l'autorizzazione se l'app si trova nell'elenco di criteri di protezione consentiti.

Contenuto della sezione:

Lettura di dati da un file

Passaggio 1: ottenere l'handle di file

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

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

Passaggio 2: determinare se l'app può aprire il file

Chiama FileProtectionManager.GetProtectionInfoAsync per determinare se l'app può aprire il file.

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

Un valore FileProtectionStatus di Protected indica che il file è protetto e l'app può aprirlo poiché la stessa si trova nell'elenco degli elementi consentiti dei criteri.

Un valore FileProtectionStatus di UnProtected indica che il file non è protetto e l'app può aprire il file anche se la stessa non è presente nell'elenco di criteri consentiti.

API
FileProtectionManager.GetProtectionInfoAsync
FileProtectionInfo
FileProtectionStatus
ProtectionPolicyManager.IsIdentityManaged

Passaggio 3: leggere il file in un flusso o in un buffer

Leggere il file in un flusso

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

Leggere il file in un buffer

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

Lettura di dati da un endpoint di rete

Crea un contesto di thread protetto da leggere da un endpoint aziendale.

Passaggio 1: ottenere l'identità dell'endpoint di rete

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

Se l'endpoint non è gestito dai criteri, si otterrà una stringa vuota.

API
ProtectionPolicyManager.GetPrimaryManagedIdentityForNetworkEndpointAsync

Passaggio 2: creare un contesto di thread protetto

Se l'endpoint è gestito dai criteri, crea un contesto di thread protetto. In questo modo vengono etichettate tutte le connessioni di rete eseguite nello stesso thread all'identità.

Ciò consente inoltre di accedere alle risorse di rete aziendali gestite da tale criterio.

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

Questo esempio racchiude le chiamate socket in un blocco using. In caso contrario, assicurati di chiudere il contesto del thread dopo aver recuperato la risorsa. Vedere ThreadNetworkContext.Close.

Non creare file personali in quel thread protetto poiché tali file verranno crittografati automaticamente.

Il metodo ProtectionPolicyManager.CreateCurrentThreadNetworkContext restituisce un oggetto ThreadNetworkContext indipendentemente dal fatto che l'endpoint venga gestito dai criteri. Se l'app gestisce sia le risorse personali sia quelle aziendali, chiama ProtectionPolicyManager.CreateCurrentThreadNetworkContext per tutte le identità. Dopo aver ottenuto la risorsa, elimina ThreadNetworkContext per cancellare qualsiasi tag di identità dal thread corrente.

API
ProtectionPolicyManager.GetForCurrentView
ProtectionPolicyManager.Identity
ProtectionPolicyManager.CreateCurrentThreadNetworkContext

Passaggio 3: leggere la risorsa in un buffer

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

    client = new HttpClient();

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

    catch (Exception) { return null; }
}

(Facoltativo) Usa un token di intestazione invece di creare un contesto di thread protetto

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

Gestire i reindirizzamenti di pagina

In alcuni casi, un server Web reindirizzerà il traffico a una versione più recente di una risorsa.

Per gestire questa operazione, inoltra richieste fino a quando lo stato della risposta della richiesta non assume il valore OK.

Usa quindi l'URI di tale risposta per ottenere l'identità dell'endpoint. Ecco un modo per farlo:

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

Recupero di dati dagli Appunti

Ottenere l'autorizzazione all'uso dei dati dagli Appunti

Per ottenere dati dagli Appunti, chiedi a Windows l'autorizzazione. Utilizza DataPackageView.RequestAccessAsync per eseguire questa operazione.

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

Nascondere o disabilitare le funzionalità che usano i dati degli Appunti

Determina se la visualizzazione corrente dispone dell'autorizzazione per ottenere i dati presenti negli Appunti.

In caso contrario, è possibile disabilitare o nascondere i controlli che consentono agli utenti di incollare le informazioni dagli Appunti o visualizzarne in anteprima il contenuto.

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

Impedire agli utenti di ricevere una richiesta con una finestra di dialogo di consenso

Un nuovo documento non è personale o aziendale. È semplicemente nuovo. Se un utente incolla i dati aziendali in esso, Windows applica i criteri e all'utente viene richiesto il consenso tramite un'apposita finestra di dialogo. Questo codice impedisce che ciò accada. Questa attività non aiuta la protezione dei dati. Si tratta di impedire agli utenti di ricevere la finestra di dialogo di consenso nei casi in cui l'app provvede a creare un nuovo elemento.

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

Lettura di dati da un contratto di condivisione

Quando i dipendenti scelgono l'app per condividere le informazioni, l'app aprirà un nuovo elemento che contiene tale contenuto.

Come accennato in precedenza, un nuovo elemento non è personale o aziendale. È semplicemente nuovo. Se il codice aggiunge contenuto aziendale all'elemento, Windows applica i criteri e all'utente viene richiesto il consenso tramite un'apposita finestra di dialogo. Questo codice impedisce che ciò accada.

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

Protezione dei dati aziendali

Proteggere i dati aziendali che lasciano l'app. I dati lasciano l'app quando vengono visualizzati in una pagina, salvati in un file o in un endpoint di rete o tramite un contratto di condivisione.

Contenuto della sezione:

Proteggere i dati visualizzati nelle pagine

Quando visualizzi i dati in una pagina, consenti a Windows di conoscere di quale tipo di dati si tratta (personali o aziendali). A tale scopo, contrassegna la vista dell'app corrente o contrassegnare l'intero processo dell'app.

Quando contrassegni la vista o il processo, Windows applica i criteri. Ciò consente di evitare perdite di dati risultanti da azioni non controllate dall'app. Ad esempio, in un computer, un utente può usare CTRL-V per copiare le informazioni aziendali da una visualizzazione e quindi incollare tali informazioni in un'altra app. Windows protegge da questo. Windows consente anche di applicare contratti di condivisione.

Contrassegnare la visualizzazione dell'app corrente

Eseguire questa operazione se l'app ha più viste in cui alcune visualizzazioni usano i dati aziendali e alcune quelli personali.


// 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

Contrassegnare il processo

Eseguire questa operazione se tutte le visualizzazioni dell'app funzioneranno con un solo tipo di dati (personali o aziendali).

Ciò impedisce di dover gestire visualizzazioni con tag indipendenti.



// 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

Proteggere i dati in un file

Crea un file protetto e quindi scrivi in esso.

Passaggio 1: determinare se l'app può creare un file aziendale

L'app può creare un file aziendale se la stringa di identità è gestita da criteri e l'app si trova nell'elenco Consentito di tale criterio.

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

API
ProtectionPolicyManager.IsIdentityManaged

Passaggio 2: creare il file e proteggerlo nell'identità

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

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

API
FileProtectionManager.ProtectAsync

Passaggio 3: scrivere il flusso o il buffer nel file

Scrivi un flusso

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

    }

Scrivi un buffer

     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

Proteggere i dati in un file come processo in background

Questo codice può essere eseguito mentre la schermata del dispositivo è bloccata. Se l'amministratore ha configurato un criterio (DPL) "Protezione dei dati con blocco" sicuro, Windows rimuove le chiavi di crittografia necessarie per accedere alle risorse protette dalla memoria del dispositivo. In questo modo, si evitano perdite di dati in caso di smarrimento del dispositivo. Questa stessa funzionalità rimuove anche le chiavi associate ai file protetti quando i relativi handle vengono chiusi.

Sarà necessario usare un approccio che mantenga aperto l'handle di file quando si crea un file.

Passaggio 1: determinare se è possibile creare un file aziendale

È possibile creare un file aziendale se l'identità che si sta utilizzando è gestita da criteri e l'app si trova nell'elenco Consentito di tale criterio.

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

API
ProtectionPolicyManager.IsIdentityManaged

Passaggio 2: creare un file e proteggerlo nell'identità

FileProtectionManager.CreateProtectedAndOpenAsync crea un file protetto e mantiene aperto l'handle di file durante la scrittura.

StorageFolder storageFolder = ApplicationData.Current.LocalFolder;

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

API
FileProtectionManager.CreateProtectedAndOpenAsync

Passaggio 3: scrivere un flusso o un buffer nel file

Questo esempio scrive un flusso in un file.

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

Proteggere parte di un file

Nella maggior parte dei casi, è più comodo archiviare i dati aziendali e personali separatamente, ma è anche possibile archiviarli nello stesso file, se necessario. Ad esempio, Microsoft Outlook può archiviare messaggi aziendali insieme a messaggi personali in un singolo file di archivio.

Crittografare i dati aziendali ma non l'intero file. In questo modo, gli utenti possono continuare a usare tale file anche se annullano la registrazione da MDM o i diritti di accesso ai dati aziendali vengono revocati. Inoltre, l'app deve tenere traccia dei dati che crittografa, in modo da sapere quali dati proteggere quando leggerà nuovamente il file in memoria.

Passaggio 1: aggiungere dati aziendali a un flusso o un buffer crittografato

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

Passaggio 2: aggiungere dati personali a un flusso o un buffer non crittografato

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

Passaggio 3: scrivere flussi o buffer in un file

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

Passaggio 4: tenere traccia della posizione dei dati aziendali nel file

È responsabilità dell'app tenere traccia dei dati in tale file di proprietà dell'azienda.

È possibile archiviare tali informazioni in una proprietà associata al file, in un database o in un testo di intestazione nel file.

In questo esempio, le informazioni vengono salvate in un file XML separato.

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

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

Leggere la parte protetta di un file

Ecco come leggere i dati aziendali da tale file.

Passaggio 1: ottenere la posizione dei dati aziendali nel file

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

Passaggio 2: aprire il file di dati e assicurarsi che non sia protetto

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

Passaggio 3: leggere i dati aziendali dal file

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

Passaggio 4: decrittografare il buffer che contiene dati aziendali

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

Proteggere i dati in una cartella

È possibile creare una cartella e proteggerla. In questo modo, tutti gli elementi aggiunti a tale cartella vengono protetti automaticamente.

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

Assicurati che la cartella sia vuota prima di proteggerla. Non è possibile proteggere una cartella che contiene già elementi.

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

Proteggere i dati in un endpoint di rete

Crea un contesto di thread protetto per inviare tali dati a un endpoint aziendale.

Passaggio 1: ottenere l'identità dell'endpoint di rete

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

string identity = await ProtectionPolicyManager.
    GetPrimaryManagedIdentityForNetworkEndpointAsync(hostName);

API
ProtectionPolicyManager.GetPrimaryManagedIdentityForNetworkEndpointAsync

Passaggio 2: creare un contesto di thread protetto e inviare dati all'endpoint di rete

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

Proteggere i dati condivisi dall'app tramite un contratto di condivisione

Se si desidera che gli utenti condividano il contenuto dell'app, sarà necessario implementare un contratto di condivisione e gestire l'evento DataTransferManager.DataRequested.

Nel gestore eventi, impostare il contesto dell'identità aziendale nel pacchetto di dati.

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

Proteggere i file copiati in un altro percorso

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

Proteggere i dati aziendali quando la schermata del dispositivo è bloccata

Rimuovere tutti i dati sensibili in memoria quando il dispositivo è bloccato. Quando l'utente sblocca il dispositivo, l'app può aggiungere i dati in modo sicuro.

Gestisci l'evento ProtectionPolicyManager.ProtectedAccessSuspending in modo che l'app sappia quando la schermata è bloccata. Questo evento viene generato solo se l'amministratore configura una protezione dei dati sicura in base ai criteri di blocco. Windows rimuove temporaneamente le chiavi di protezione dei dati di cui viene effettuato il provisioning nel dispositivo. Windows rimuove queste chiavi per assicurarsi che non vi sia accesso non autorizzato ai dati crittografati mentre il dispositivo è bloccato e magari non in possesso del proprietario.

Gestisci l'evento ProtectionPolicyManager.ProtectedAccessResumed in modo che l'app sappia quando la schermata è sbloccata. Questo evento viene generato indipendentemente dal fatto che l'amministratore configuri una protezione dei dati sicura nei criteri di blocco.

Rimuovere i dati sensibili in memoria quando lo schermo è bloccato

Proteggi i dati sensibili e chiudi tutti i flussi di file aperti dall'app nei file protetti per garantire che il sistema non memorizzi nella cache dati sensibili in memoria.

Questo esempio salva il contenuto da un blocco di testo in un buffer crittografato e rimuove il contenuto da tale blocco di testo.

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

Aggiungere dati sensibili quando il dispositivo viene sbloccato

ProtectionPolicyManager.ProtectedAccessResumed viene generato quando il dispositivo viene sbloccato e le chiavi sono nuovamente disponibili nel dispositivo.

ProtectedAccessResumedEventArgs.Identities è una raccolta vuota, se l'amministratore non ha configurato una protezione dei dati sicura nei criteri di blocco.

Questo esempio esegue l'operazione inversa dell'esempio precedente. Decrittografa il buffer, aggiunge informazioni dal buffer alla casella di testo e quindi elimina il buffer.

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

Gestire i dati aziendali quando viene revocato il contenuto protetto

Se desideri che l'app venga notificata quando il dispositivo non è registrato da MDM o quando l'amministratore dei criteri revoca esplicitamente l'accesso ai dati aziendali, gestisci l'evento ProtectionPolicyManager_ProtectedContentRevoked.

Questo esempio stabilisce se i dati in una cassetta postale aziendale per un'app di posta elettronica sono stati revocati.

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

esempio Windows Information Protection (WIP)