A anonimização de dados é um processo crucial para proteger informações sensíveis ou pessoais, eliminando permanentemente qualquer ligação entre os dados e a pessoa a que pertencem. Este post descreve a implementação de funções de API para transformar dados sensíveis em valores padrão irreversíveis, garantindo que, mesmo se armazenados, não possam ser associados de volta ao indivíduo original.
Importância da Anonimização
Com a crescente preocupação com a privacidade e a segurança dos dados, a anonimização se torna essencial. Por exemplo, um cliente cujos dados são armazenados em um sistema como o Protheus pode solicitar que o fornecedor anonimize seus dados. O fornecedor deve então avaliar a viabilidade dessa anonimização e, se apropriado, aplicar as funções de API disponibilizadas para realizar o processo de forma definitiva.
Implementação Técnica
Para implementar a anonimização no sistema, é necessário aplicar a biblioteca atualizada com a label mínima 20200214 e realizar a atualização do sistema usando o UPDDISTR. A aplicação do UPDDISTR pode ser feita de duas maneiras:
- Pacote diferencial de upgrade para o Release 12.1.27.
- Pacote específico para Dados Protegidos nos Releases 12.1.17, 12.1.23 e 12.1.25. (O Release 12.1.17 é exclusivo para clientes com garantia estendida.)
Os valores dos campos são substituídos por valores padrão diretamente nas tabelas do banco de dados, garantindo que buscas futuras não revelem os dados originais. A transformação dos dados depende do tipo de campo:
- Campos numéricos: são preenchidos com 999999 (de acordo com o tamanho do campo).
- Campos memo e caracter: recebem um único “x”.
- Campos data: são convertidos para a data 01/01/1950.
- Campos lógicos: não permitem anonimização.
Regras de Anonimização
A API verifica a tabela de Dados Protegidos para determinar se um campo específico pode ser anonimizado. As condições para anonimização são:
- Inexistência de Informação: Se não houver linha correspondente para o campo na tabela de Dados Protegidos, a anonimização não é permitida.
- Configuração de Anonimização: Se houver linhas na tabela para o campo e pelo menos uma estiver configurada como “anonimiza = não”, a anonimização também não é permitida. As sugestões TOTVS desabilitadas são consultadas neste caso.
A anonimização é permitida somente se todos os registros do campo na tabela de Dados Protegidos estiverem configurados como “anonimiza = sim”, incluindo as sugestões TOTVS desabilitadas.
Funções Disponibilizadas
As funções de API fornecidas para anonimização são:
- FwProtectedDataUtil()
Cada função possui parâmetros de entrada diferentes, mas ambas transformam os valores dos campos com permissão de anonimização para valores padrão anônimos.
Exemplos de Uso
- Para anonimizar dados por número de registro:plaintext
FwProtectedDataUtil():ToAnonymizeByRecNo('SUS', { 9, 50, 37, 88 })
- Para anonimizar dados por chave:
FwProtectedDataUtil():ToAnonymizeByKey('SUS', { 'US_COD+US_LOJA', { { '000016', '01' }, { '000018', '01' } } })
Essas funções ajudam a garantir a conformidade com regulamentações de proteção de dados, protegendo as informações pessoais de forma eficaz e irreversível.
Exemplo de código em ADVPL com Anonimização de dados para LGPD:
#include ‘protheus.ch’
user function myPDinfo()
Local aRet as array
Local lRet as logical
Local oRet as object
Local lDetail as logical
Local cMessage as character
aRet := FwProtectedDataUtil():UsrAccessPDField(“ID USUÁRIO”, {“RA_SERCP”,”RD0_TPDEFF”,”RA_RG”,”R8_CID”,”A1_END”})
// aRet => Campos que o usuário possui acesso
// aRet[1] => RA_SERCP
// aRet[2] => RA_RG
// aRet[3] => A1_END
lRet := FwProtectedDataUtil():IsFieldInList(‘CAMPO_EXISTE’)
// lRet => .T.
lRet := FwProtectedDataUtil():IsFieldInList(‘CAMPO_NAO_EXISTE’)
// lRet => .F.
lDetail := .T.
FwProtectedDataUtil():AreFieldsInList({‘FIELD1′,’FIELD2′,’FIELD3’}, lDetail)
// aRet[1] => objeto FwPDFieldRepository (:cField => FIELD1, :aDetails => array de FwPDFieldDetailRepository)
// aRet[1]:GetDetails() => [ detail[1] => (:cJustification, :cClassification, …) ]
// => [ detail[2] => (:cJustification, :cClassification, …) ]
// => [ detail[3] => (:cJustification, :cClassification, …) ]
// aRet[2] => objeto FwPDFieldRepository (:cField => FIELD2, :aDetails => array de FwPDFieldDetailRepository)
// aRet[2]:GetDetails() => [ detail[1] => (:cJustification, :cClassification, …) ]
// => [ detail[2] => (:cJustification, :cClassification, …) ]
// => [ detail[3] => (:cJustification, :cClassification, …) ]
aRet := FwProtectedDataUtil():GetSXGFieldsInList(‘SXG_EXISTE’, lDetail)
// aRet[1] => objeto FwPDFieldRepository (:cField => FIELD1, :aDetails => array de FwPDFieldDetailRepository)
// aRet[1]:GetDetails() => [ detail[1] => (:cJustification, :cClassification, …) ]
// => [ detail[2] => (:cJustification, :cClassification, …) ]
// => [ detail[3] => (:cJustification, :cClassification, …) ]
// aRet[2] => objeto FwPDFieldRepository (:cField => FIELD2, :aDetails => array de FwPDFieldDetailRepository)
// aRet[2]:GetDetails() => [ detail[1] => (:cJustification, :cClassification, …) ]
// => [ detail[2] => (:cJustification, :cClassification, …) ]
// => [ detail[3] => (:cJustification, :cClassification, …) ]
aRet := FwProtectedDataUtil():GetSXGFieldsInList(‘SXG_NAO_EXISTE’, lDetail)
// aRet => Lista vazia
lRet := FwProtectedDataUtil():CanFieldBeAnonymized(‘FIELD1’)
// lRet => verdadeiro
lRet := FwProtectedDataUtil():CanFieldBeAnonymized(‘FIELD2’)
// lRet => falso
aRet := FwProtectedDataUtil():GetSXGFieldsCanBeAnonymized(‘SXG_EXISTE’, lDetail)
// aRet[1] => objeto FwPDFieldRepository (:cField => FIELD1, :aDetails => array de FwPDFieldDetailRepository)
// aRet[1]:GetDetails() => [ detail[1] => (:cJustification, :cClassification, …) ]
// => [ detail[2] => (:cJustification, :cClassification, …) ]
// => [ detail[3] => (:cJustification, :cClassification, …) ]
aRet := FwProtectedDataUtil():GetSXGFieldsCannotBeAnonymized(‘SXG_EXISTE’, lDetail)
// aRet[1] => objeto FwPDFieldRepository (:cField => FIELD2, :aDetails => array de FwPDFieldDetailRepository)
// aRet[1]:GetDetails() => [ detail[1] => (:cJustification, :cClassification, …) ]
// => [ detail[2] => (:cJustification, :cClassification, …) ]
// => [ detail[3] => (:cJustification, :cClassification, …) ]
aRet := FwProtectedDataUtil():GetFieldGroups(‘FIELD_EXIST’)
// aRet[1] => objeto FwPDGrouRepository (:cGroup => ID1, :Description => Grupo ID1, :cType => 1, :lPropri => .T.)
// aRet[2] => objeto FwPDGrouRepository (:cGroup => ID2, :Description => Grupo ID2, :cType => 1, :lPropri => .T.)
// aRet[3] => objeto FwPDGrouRepository (:cGroup => ID3, :Description => Grupo ID3, :cType => 2, :lPropri => .T.)
// aRet[4] => objeto FwPDGrouRepository (:cGroup => ID4, :Description => Grupo ID4, :cType => 2, :lPropri => .F.)
aRet := FwProtectedDataUtil():GetFieldGroups(‘FIELD_DOESNT_EXIST’)
// aRet => Lista vazia
oRet := FwProtectedDataUtil():GetFieldDetails(‘FIELD_EXIST’)
// oRet => FwPDFieldRepository (:cField => FIELD2, :aDetails => array de FwPDFieldDetailRepository)
// oRet:GetDetails() => [ detail[1] => (:cJustification, :cClassification, …) ]
// => [ detail[2] => (:cJustification, :cClassification, …) ]
// => [ detail[3] => (:cJustification, :cClassification, …) ]
oRet := FwProtectedDataUtil():GetFieldDetails(‘FIELD_DOESNT_EXIST’)
// oRet => Nil
lRet := FwProtectedDataUtil():IsGroupPersonal(‘XAL_ID’)
// lRet => falso
lRet := FwProtectedDataUtil():IsGroupSensible(‘XAL_ID’)
// lRet => verdadeiro
aRet := FwProtectedDataUtil():GetAliasFieldsInList(‘ALIASX’, lDetail)
// aRet[1] => objeto FwPDFieldRepository (:cField => ALIASX_FIELD1, :aDetails => array de FwPDFieldDetailRepository)
// aRet[1]:GetDetails() => [ detail[1] => (:cJustification, :cClassification, …) ]
// => [ detail[2] => (:cJustification, :cClassification, …) ]
// => [ detail[3] => (:cJustification, :cClassification, …) ]
// aRet[2] => objeto FwPDFieldRepository (:cField => ALIASX_FIELD2, :aDetails => array de FwPDFieldDetailRepository)
// aRet[2]:GetDetails() => [ detail[1] => (:cJustification, :cClassification, …) ]
// => [ detail[2] => (:cJustification, :cClassification, …) ]
// => [ detail[3] => (:cJustification, :cClassification, …) ]
aRet := FwProtectedDataUtil():GetAliasAnonymizeFields(‘ALIASX’, lDetail)
// aRet[1] => objeto FwPDFieldRepository (:cField => ALIASX_FIELD1, :aDetails => array de FwPDFieldDetailRepository)
// aRet[1]:GetDetails() => [ detail[1] => (:cJustification, :cClassification, …) ]
// => [ detail[2] => (:cJustification, :cClassification, …) ]
// => [ detail[3] => (:cJustification, :cClassification, …) ]
lRet := FwProtectedDataUtil():HasAliasAnySensibleField(‘ALIASX’)
// lRet => verdadeiro / falso
FwProtectedDataUtil():HasAliasAnyPersonalField(‘ALIASX’)
// lRet => verdadeiro / falso
lRet := FwProtectedDataUtil():ToAnonymizeByRecNo( ‘ALIASX’, {1}, { “A1_END”, “A1_DATATST”, “A1_COD”, “A1_MUN” }, @cMessage )
// lRet => verdadeiro / falso
lRet := FwProtectedDataUtil():ToAnonymizeByKey( cAlias, {“A1_FILIAL+A1_COD+A1_LOJA”, { {“0101”, “000003”, “01”},;
{“0101”, “000004”, “01”} } } , { “A1_END”, “A1_DATATST”, “A1_COD”, “A1_MUN” }, @cMessage )
// lRet => verdadeiro / falso
return