2

我正在处理 SAS 中包含敏感客户识别信息的客户数据。挑战在于以保持数字/字母/字母数字的方式屏蔽该字段。我找到了一种在 SAS(BXOR、BOR、BAND)中使用按位函数的方法,但输出中充满了 SAS 无法处理/排序/合并等的特殊字符。

我还考虑过根据密钥对字段本身进行加扰,但无法看穿它。以下是挑战:

1)它必须是基于密钥的 2)必须是可逆的。3) 屏蔽/加扰字段必须是数字/字母/字母数字,才能在 SAS 中使用。4)要屏蔽的字段既有字母又有数字,但长度不同,有数百万个观察值。

任何关于如何实现这种掩蔽/加扰的提示都会非常感激:(

4

2 回答 2

2

这是一个简单的基于密钥的解决方案。我在这里介绍数据步骤解决方案,然后将介绍一个 FCMP 版本。我将所有内容保持在 48 到 127 的范围内(数字、字母和常见字符,例如 @ > < 等);这不是字母数字,但我无法想象为什么在这种情况下会很重要。您可以使用相同的方法将其进一步减少为仅真正的字母数字,但它会使密钥变得更糟(只有 62 个值)并且使用起来很笨拙(因为您有 3 个不连续的范围)。

data construct_key;
length keystr $1500;
do _t = 1 to 1500;
  _rannum = ceil(ranuni(7)*80);
  *if _rannum=12 then _rannum=-15;
  substr(keystr,_t,1)=byte(47+_rannum);

end;
call symput('keystr',keystr);
run;
%put %bquote(&keystr);



data encrypted;
set sashelp.class;
retain key "&keystr";
length name_encrypt $30;
do _t = 1 to length(name);
  substr(name_encrypt,_t,1) = byte(mod(rank(substr(name,_t,1)) + rank(substr(key,1,1))-94,80)+47);
  key = substr(key,2);
end;
keep name:;
run;

data unencrypted;
set encrypted;
retain key "&keystr";
length name_unenc $30;
do _t = 1 to length(name_encrypt);
  substr(name_unenc,_t,1) = byte(
      mod(80+rank(substr(name_encrypt,_t,1)) - rank(substr(key,1,1)),80)
+47);
  key = substr(key,2);
end;
run;

在这个解决方案中,存在中等级别的加密——具有 80 个可能值的密钥不足以阻止真正老练的黑客,但对于大多数目的来说足够强大。您需要将密钥本身或种子传递给密钥算法才能解密;如果您多次使用它,请确保每次都选择一个新种子(而不是与数据相关的东西)。如果您使用零(或非正整数)作为种子,您将有效地保证每次都有一个新密钥,但您必须传递密钥本身而不是种子,这可能会带来一些数据安全问题(显然,密钥本身可以是由恶意用户获取,并且必须存储在与数据不同的位置)。通过种子传递密钥可能更好,

我不确定我是否推荐这种方法。一种更好的方法很可能是使用高级加密方法(例如 PGP)简单地加密整个 SAS 数据集。您的确切解决方案可能会有所不同,但如果您有一些客户信息对于您的流程的大多数步骤实际上并不是必需的,那么您最好将该信息与其余(非敏感)数据分开并仅合并在需要的时候。

例如,我有一个流程,我为客户提取样本以进行医疗保健调查。我从除了数字唯一标识符之外没有客户信息的数据集中选择有效记录;一旦我将样本范围缩小到有效记录,然后我从单独的数据集中附加客户信息并创建邮件文件(存储在加密目录中)。这样可以尽可能长时间地保持数据不敏感。这并不完美 - 唯一的数字标识符仍然意味着有一个联系,即使它不是项目之外有人会知道的任何事情 - 但它尽可能长时间地保证我们的安全。

这是 FCMP 版本:

%let keylength=5;
%let seed=15;

proc fcmp outlib=work.funcs.test;
subroutine encrypt(value $,key $);
  length key $&keylength.;
  outargs value,key;
  do _t = 1 to lengthc(value);
    substr(value,_t,1) = byte(mod(rank(substr(value,_t,1)) + rank(substr(key,1,1))-62,96)+31);
    key = substr(key,2)||substr(key,1,1);
  end;
endsub;

subroutine unencrypt(value $,key $);
  length key $&keylength.;
  outargs value,key;
  do _t = 1 to lengthc(value);
    substr(value,_t,1) = byte(mod(96+rank(substr(value,_t,1)) - rank(substr(key,1,1)),96)+31);
    key = substr(key,2)||substr(key,1,1);
  end;
endsub;

subroutine gen_key(seed,keystr $);
  outargs keystr;
  length keystr $&keylength.;
  do _t = 1 to &keylength.;
    _rannum = ceil(ranuni(seed)*80);    
    substr(keystr,_t,1)=byte(47+_rannum);
  end;
endsub;
quit;

options cmplib=work.funcs;



data encrypted;
set sashelp.class;
length key $&keylength.;
retain key ' '; *the missing is to avoid the uninitialized variable warning;
if _n_ = 1 then call gen_key(&seed,key);
call encrypt(name,key);
drop key;
run;

data unencrypted;
set encrypted;
length key $&keylength.;
retain key ' ';
if _n_ = 1 then call gen_key(&seed,key);
call unencrypt(name,key);
run;

这更健壮一些;它允许 32 到 127 个字符而不是 48 个字符,这意味着它可以成功处理空格。(选项卡仍然无法正确解码 - 它会变成一个“k”。)您将种子传递给调用 gen_key,然后它在该过程的其余部分使用该密钥。

不言而喻,这不能保证满足您的目的和/或成为一个安全的解决方案,如果您有大量的安全需求,您应该咨询安全专家。发帖人不为任何目的提供任何保证,发帖人不承担因使用该帖子而产生的任何和所有责任。

于 2013-05-16T15:04:47.567 回答
1

SAS 在其网站上有一篇关于如何加密特定变量的文章。希望这会对您有所帮助。

关联

于 2013-05-16T12:10:34.033 回答