Optim Data Privacy 包含一组数据隐私功能提供程序,它们能够屏蔽或替换各种信息类型,比如信用卡号、日期和一些国家的全国性 ID。这些数据隐私功能提供程序是跨平台和跨环境的,被实现为一系列共享库,而且可由所有支持 C 语言调用约定的应用程序调用。
SQL Database (SQLDB) 在 Bluemix 上提供了 IBM DB2 Enterprise Server Edition 10.5 版的一个基于云的实例,这是 IBM 的开放云架构的一种实现,该实现利用了 Cloud Foundry 使开发人员能够快速构建、部署和管理云应用程序。因为 SQLDB 属于 DB2,所以 Optim Data Privacy 特性可以在配备的数据库实例中提供。
在本教程中您将会看到,Bluemix 和 Optim 提供了必要的工具和技术,帮助您在应用程序中构建有效的数据隐私保护。
您需要满足的前提条件
要完成本教程的学习,您应该对面向对象的设计和开发具有充分的理解。还应该基本熟悉 JEE Servlet 和关联的应用编程接口 (API)。因为该应用程序使用了 JDBC 和 SQL,所以了解该 API 和如何编写 SQL 语句会对您有所帮助。
如果不熟悉 SQLDB,可以在 SQL Database 入门 中了解有关的基本知识。“数据隐私特性” 一节包含一组用户定义的函数和主要用例。下面将简短介绍用户定义的函数和数据隐私特性。
用户定义的函数
用户定义的函数 (UDF) 是一种由用户提供的自定义函数,可像内置函数(比如 ABS、CONCAT 和 SUBSTR)一样从 SQL 语句调用。Optim Data Privacy UDF 是标量函数,它们接受一个值和一个屏蔽规范字符串作为输入,返回一个经过屏蔽的值。
标量函数(内置的和 UDF)可用在任何可合法使用列引用或文字的 SQL 语句中。下面这个示例返回一组屏蔽的信用卡号。
单 1. UDF 使用示例
- SELECT
- DB2INST1.OptimMaskStr(CREDITCARD_NUMBER,'pro=ccn,method=repeatable, \
- pattern=6C,wheninvalid=preserve,flddef1=(name=c1,dt=varchar)'),
- FROM USER01.OPTIM_CUSTOMERS
在 Bluemix 中,Optim UDF 安装在 DB2INST1 SQL Database 目录中,所以函数名称必须按上述方式进行限定。所有 Optim UDF 的名称都以 OptimMask
开头,以便与其他 UDF 进行区分。函数名称的后缀表明它接受的数据类型。
在本例中,Str
指一个字符串,比如 CHAR
或 VARCHAR
。其他后缀包括 Date
(接受一个日期)和 Int16
和 Int32
(分别接受 16 和 32 位整数)。
数据隐私特性
Optim Data Privacy 提供程序能够屏蔽许多不同类型的信息。各种 UDF 可通过屏蔽作为一个输入参数传递的规范字符串,指定要屏蔽的信息类型。
亲缘性隐私功能提供程序
可使用亲缘性隐私功能提供程序来屏蔽数据,同时保持来源值的格式和字符类型。例如,该提供程序可以保持数据的格式,比如帐号或驾照编号,同时使用字符数据屏蔽字符数据,使用数字屏蔽数字。
年龄隐私功能提供程序
可使用年龄隐私功能提供程序屏蔽一个来源字段中的年龄值。来源值可包含字符、数字、日期或时间戳数据,但必须始终表示一个日期,比如生日。
信用卡隐私功能提供程序
可以使用信用卡隐私功能提供程序来生成一个有效且惟一的信用卡号 (CCN)。在默认情况下,该提供程序使用了一种可重复的方法,通过算法基于来源 CCN 生成一个经过一致地修改的 CCN。在来源数据没有 CCN 值时,或者不需要以一致的方式转换来源 CCN 时,该提供程序还可以生成一个随机值。
电子邮件隐私功能提供程序
可以使用电子邮件隐私功能提供程序生成一个电子邮件地址。电子邮件地址由两部分组成,一个用户名和一个域名,它们之间使用 @ 符号分开。例如 user@domain.com。
哈希隐私功能提供程序
可使用哈希隐私功能提供程序,使用一个哈希算法生成的数字值屏蔽来源数据。可以这些数字值为基础,提供来自查找表或一个值数组的替换数据。
全国性 ID 隐私功能提供程序
可以使用全国性 ID 隐私功能提供程序屏蔽全国性 ID 编号,比如美国社会安全编号。该提供程序可以使用保留了部分来源值的可重复方法,或者使用不会保留来源值的任何部分的随机方法来屏蔽全国性 ID 编号。该提供程序还包含输出值的多个分隔符选项(斜杠、句点、空格或无分隔符)。
其他隐私功能提供程序
Optim Data Privacy 提供程序库还包含用于对通常无法通过算法屏蔽的信息类型(比如姓名和地址)执行查找操作的提供程序。但是,大多数关系数据库管理系统 (RDMS) 都不允许从 SQL UDF 内访问数据库表,所以要执行查找,需要使用哈希隐私功能提供程序,并使用该哈希值作为键来选择查找替换值,比如通过联结 (join)。
- String vcapServices = System.getenv("VCAP_SERVICES");
- if (vcapServices != null) {
- context.log("Has VCAP_SERVICES.");
- String vcapKey =
- context.getInitParameter(InitParameterNames.VCAP_KEY);
- if (vcapKey != null) {
- context.log("The VCAP key is '" + vcapKey + "'");
- }
- JsonParser parser = new JsonParser();
- try {
- JsonObject services = parser.parse(vcapServices).getAsJsonObject();
- JsonArray array = null;
- JsonObject service = null;
- if (vcapKey != null) {
- context.log("Looking up service '" + vcapKey + "'...");
- JsonElement element = services.get(vcapKey);
- if (element != null) {
- context.log("Service '" + vcapKey + "' found.");
- array = element.getAsJsonArray();
- }
- }
- if (array == null) {
- context.log("Using first available service...");
- Set<Entry<String, JsonElement>> entrySet = services.entrySet();
- Iterator<Entry<String, JsonElement>> iterator =
- entrySet.iterator();
- if (iterator.hasNext()) {
- Entry<String, JsonElement> entry = iterator.next();
- JsonElement element = entry.getValue();
- array = element.getAsJsonArray();
- } else {
- context.log("No services defined.");
- }
- }
- if (array != null) {
- if (array.size() > 0) {
- service = array.get(0).getAsJsonObject();
- String name = service.get("name").getAsString();
- context.log("Service name is '" + name + "'.");
- String label = service.get("label").getAsString();
- context.log("Service label is '" + label + "'.");
- String plan = service.get("plan").getAsString();
- context.log("Service plan is '" + plan + "'.");
- JsonObject credentials =
- service.get("credentials").getAsJsonObject();
- url = credentials.get("jdbcurl").getAsString();
- context.log("URL is '" + url + "'.");
- user = credentials.get("username").getAsString();
- context.log("User is '" + user + "'.");
- password = credentials.get("password").getAsString();
- context.log("Password is '" + password + "'.");
- }
- }
- } catch (Exception e) {
- context.log("Error parsing VCAP_SERVICES", e);
- }
- }
从 VCAP_SERVICES 获得连接 URL 和凭据后,连接到 SQL Database 就像使用 JDBC 连接到 DB2 LUW 一样:
清单 3. 连接到 SQL Database
- connection = null;
- ApplicationConfiguration configuration = getConfiguration();
- try {
- connection = DriverManager.getConnection(
- configuration.getUrl(),
- configuration.getUser(),
- configuration.getPassword());
- log("Connected to database.");
- } catch (SQLException e) {
- log("Unable to connect to database.", e);
- }
演示应用程序支持使用清单 6 中所示的 CREATE TABLE AS VIEW 机制来创建一个包含敏感信息的表的副本。像其他 JDBC 应用程序一样,这些步骤非常简单:
- 构建要执行的 SQL。
- 从连接中获取(或重用)一个 SQL 语句。
- 执行该 SQL。
清单 4. 获取该 SQL 语句
- Connection connection = connectionManager.getConnection();
- if (connection == null) {
- thrownew IllegalStateException("Database connection not available");
- }
- if (connection != this.connection) {
- log("Connection is new or has changed - creating new statement.");
- this.connection = connection;
- if (statement != null) {
- try {
- statement.close();
- } catch (SQLException e) {
- // Ignore.
- }
- }
- statement = connection.createStatement();
- }
- return statement;
清单 5. 执行该 SQL 语句
- Statement statement = getStatement();
- return statement.executeUpdate(sql);
#p#
创建一个屏蔽的表副本涉及两个步骤:
- 创建新表。
- 插入来自原始表的数据,使用 UDF 屏蔽敏感信息。
清单 6. 创建 SQL 来构建新表
- ApplicationConfiguration configuration = getConfiguration();
- return String.format("CREATE TABLE %s.OPTIM_SALES_MASKED AS
- (SELECT * FROM %s.OPTIM_SALES) WITH NO DATA",
- configuration.getSchema(),
- configuration.getSchema());
清单 7. 创建 SQL 来插入来自原始表的数据
- ApplicationConfiguration configuration = getConfiguration();
- StringBuilder builder = new StringBuilder();
- builder.append(String.format("INSERT INTO %s.OPTIM_SALES_MASKED (\n",
- configuration.getSchema()));
- builder.append(" SALESMAN_ID,\n");
- builder.append(" FIRST_NAME,\n");
- builder.append(" LAST_NAME,\n");
- builder.append(" NATIONALITY,\n");
- builder.append(" NATIONAL_ID,\n");
- builder.append(" PHONE_NUMBER,\n");
- builder.append(" AGE,\n");
- builder.append(" SEX,\n");
- builder.append(" TERRITORY,\n");
- builder.append(" EMAIL_ADDRESS,\n");
- builder.append(" MANAGER_ID\n");
- builder.append(") SELECT SALESMAN_ID,\n");
- builder.append(" FIRST_NAME,\n");
- builder.append(" LAST_NAME,\n");
- builder.append(" NATIONALITY,\n");
- if (configuration.isUseUDFs()) {
- builder.append(" ");
- String udfSchema = configuration.getUdfSchema();
- if (udfSchema != null) {
- builder.append(udfSchema);
- builder.append('.');
- }
- builder.append("OptimMaskStr(NATIONAL_ID,'pro=nid,switch=us,
- wheninvalid=preserve,flddef1=(name=c1,dt=varchar)'),\n");
- } else {
- builder.append(" NATIONAL_ID,\n");
- }
- builder.append(" PHONE_NUMBER,\n");
- builder.append(" AGE,\n");
- builder.append(" SEX,\n");
- builder.append(" TERRITORY,\n");
- builder.append(" EMAIL_ADDRESS,\n");
- builder.append(" MANAGER_ID\n");
- builder.append(String.format(" FROM %s.OPTIM_SALES WHERE NATIONALITY =
- 'U.S.'\n", configuration.getSchema()));
- return builder.toString();
SQL Database DDL
由于 SQL Database 服务作为基于云的产品的性质,该服务提供的 DB2 数据库存在多种限制和局限性。最明显的限制是,目前无法从云外部连接到 SQL Database 实例。这使得用户无法使用 DB2 命令行实用程序和其他 SQL 工具(比如 Eclipse)。但 SQL Database 有一个与 Bluemix 集成的控制台提供了此功能。
要启动该控制台,需要使用您的凭据登录到 Bluemix。这会调出您的仪表板。在左侧,可以访问应用程序和服务。单击 SERVICES 展开该列表并选择您的 SQL Database 服务。
图 1. 您的 Bluemix 仪表板
1.要启动该控制台,需要使用您的凭据登录到 Bluemix。这会调出您的仪表板。在左侧,可以访问应用程序和服务。单击 SERVICES 展开该列表并选择您的 SQL Database 服务。
图 1. 您的 Bluemix 仪表板
2.这会打开 SQL 控制台的启动面板。单击 LAUNCH,这会在浏览器中打开一个新窗口或选项卡。Bluemix 建议采用的默认名称为 mySQLDB。我选择使用 sqldb。
图 2. SQL Database 控制台启动面板
3.单击 Work with Database Objects 查看数据库实例元数据,比如模式、表、视图和函数。
图 3. SQL Database 控制台
4.如果有多个 SQL Database 服务器绑定到您的应用程序,那么可以使用 Database: 下拉菜单选择您想要查看和使用的数据库。
要创建数据库表和视图,可以单击 Run DDL。
图 4. 使用数据库对象
#p#
5.这会调出一个选项卡,用于键入或粘贴 DDL,或者从您的本地文件系统加载一个 SQL 脚本文件。
图 5. 运行 DDL
清单 8. DDL 语句
- ------------------------------------------------
- -- DDL Statements for table "USER01 "."OPTIM_CUSTOMERS"
- ------------------------------------------------
- CREATETABLE "USER01 "."OPTIM_CUSTOMERS" (
- "CUST_ID" CHAR(5) NOTNULL ,
- "CUSTNAME" CHAR(20) NOTNULL ,
- "ADDRESS1" VARCHAR(100) NOTNULL ,
- "ADDRESS2" VARCHAR(100) ,
- "LOCALITY" VARCHAR(56) ,
- "CITY" VARCHAR(60) ,
- "STATE" VARCHAR(30) ,
- "COUNTRY_CODE" CHAR(2) ,
- "POSTAL_CODE" VARCHAR(15) ,
- "POSTAL_CODE_PLUS4" CHAR(4) ,
- "EMAIL_ADDRESS" VARCHAR(70) ,
- "PHONE_NUMBER" VARCHAR(20) ,
- "YTD_SALES" DECIMAL(7,2) NOTNULLWITHDEFAULT ,
- "SALESMAN_ID" CHAR(6) ,
- "NATIONALITY" VARCHAR(30) ,
- "NATIONAL_ID" VARCHAR(30) ,
- "CREDITCARD_NUMBER" VARCHAR(19) ,
- "CREDITCARD_TYPE" VARCHAR(30) ,
- "CREDITCARD_EXP" CHAR(4) ,
- "CREDITCARD_CVV" VARCHAR(4) ,
- "DRIVER_LICENSE" VARCHAR(30) ,
- "CREDITCARD_HISTORY" CLOB(1048576) LOGGED NOT COMPACT )
- IN "USERSPACE1" ;
- -- DDL Statements for indexes on Table "USER01 "."OPTIM_CUSTOMERS"
- CREATEUNIQUEINDEX "USER01 "."XPK_CUST" ON "USER01 "."OPTIM_CUSTOMERS"
- ("CUST_ID" ASC)
- COMPRESS NO ALLOW REVERSE SCANS;
- -- DDL Statements for primary key on Table "USER01 "."OPTIM_CUSTOMERS"
- ALTERTABLE "USER01 "."OPTIM_CUSTOMERS"
- ADDPRIMARYKEY
- ("CUST_ID");
- ------------------------------------------------
- -- DDL Statements for table "USER01 "."OPTIM_SALES"
- ------------------------------------------------
- CREATETABLE "USER01 "."OPTIM_SALES" (
- "SALESMAN_ID" CHAR(6) NOTNULL ,
- "FIRST_NAME" VARCHAR(15) NOTNULL ,
- "LAST_NAME" VARCHAR(15) NOTNULL ,
- "NATIONALITY" VARCHAR(30) ,
- "NATIONAL_ID" VARCHAR(30) ,
- "PHONE_NUMBER" VARCHAR(20) NOTNULL ,
- "AGE" SMALLINTNOTNULLWITHDEFAULT ,
- "SEX" CHAR(1) NOTNULLWITHDEFAULT ,
- "TERRITORY" VARCHAR(14) NOTNULL ,
- "EMAIL_ADDRESS" VARCHAR(70) NOTNULL ,
- "MANAGER_ID" VARCHAR(6) )
- IN "USERSPACE1" ;
- -- DDL Statements for indexes on Table "USER01 "."OPTIM_SALES"
- CREATEUNIQUEINDEX "USER01 "."XPK_SALES" ON "USER01 "."OPTIM_SALES"
- ("SALESMAN_ID" ASC)
- COMPRESS NO ALLOW REVERSE SCANS;
- -- DDL Statements for primary key on Table "USER01 "."OPTIM_SALES"
- ALTERTABLE "USER01 "."OPTIM_SALES"
- ADDPRIMARYKEY
- ("SALESMAN_ID");
加载数据
执行必要的 DDL 后,可以将任何所需的数据加载到数据库实例中。演示应用程序的数据包含两个表:
- 客户数据
- 销售数据
这两个表包含敏感信息,在真实世界中,应该在用于分析或测试之前先屏蔽这些信息。
图 6. 客户数据
图 7. 销售数据
以下步骤展示了销售数据的加载。
1.单击控制台的 Getting Started 页面上的 Load Data,如 图 3 所示。这会调出 Load Data 页面。
单击 Browse files 选择您的本地文件系统中的一个文件,其中包含逗号分隔值 (CSV) 格式的数据。一定要为 Row one contains the column names 选择 No。
使用 table 下拉菜单选择该表,单击 Load File 将数据上传到 Bluemix。
图 8. 浏览并上传数据
上传并解析文件后,会显示内容的预览视图。单击 Next 选择加载目标。
图 9. 上传的数据的预览视图
确保已选择 Load into an existing table 并单击 Next。
图 10. 选择目标
#p#
为数据选择模式 USER01 和目标表。您会看到一个列出了表列的弹出窗口,在确认您已选择正确的表后,可以关闭此弹窗。
图 11. 选择表
如果该表已在上面的 运行 DDL 步骤中创建,那么是附加数据还是替换数据没有任何区别。如果该表之前已加载,而且您希望重新开始,那么可以选择 Replace any data in the table with new data,然后单击 Finish。
Bluemix 将数据加载到表中后,您将获得一个表明加载、拒绝、删除和跳过的行数的状态,以及一个表预览视图。
图 12. 选择加载选项
加载了客户和销售数据后,演示应用程序就可以使用数据库了。
图 13. 加载完成
部署和测试您的应用程序
可以使用 Cloud Foundry cf 命令行实用程序 部署 Web 应用程序归档文件 (WAR)。
- 在可以部署(推送)应用程序之前,必须登录到您的 API 端点:
- 可以推送一个
.war
文件或一个目录的内容(布局类似于一个.war
文件)。在本例中,只需推送.war
文件: - 也可以使用 cf 查询部署的应用程序和它们使用的服务:
- 完成上述操作后,您应该注销:
- 应用程序被推送到 Bluemix 后,可以从 Web 浏览器通过 http://<app name>.mybluemix.net/ 访问它。
单击 Mask Customer Credit Card Numbers 或 Mask Sales Social Security Numbers。
图 14. 演示应用程序
在下一个屏幕上,单击 Mask Social Security Numbers。
图 15. 未屏蔽的销售数据
预览将执行的 3 个步骤: 然后单击 Perform Steps and Compare。
图 16. 屏蔽销售错误
- 丢弃包含屏蔽的数据的表(如果存在)。
- 创建将包含屏蔽的数据的表。
- 发出一个语句来插入销售数据,同时屏蔽社会安全编号。
- 检查屏蔽的数据,您可能注意到,所有社会安全编号都与原始编号不同。
图 17. 屏蔽的销售数据
结束语
随着有关数据隐私的法律法规得到更多的关注,企业拥有具有数据屏蔽功能的应用程序变得至关重要。如本教程所示,IBM Bluemix 和 Optim 提供了必要的技术和工具来帮助您构建这些应用程序。
原文出自:http://www.ibm.com/developerworks/cn/cloud/library/cl-optimprivacy-app/index.html