新闻中出现的数据破坏报告越来越多。数据破坏在法律和财务上都具有深远的影响,所以组织开始越来越多地关注数据隐私合规性要求,尤其在数据和应用程序位于云中的时候。IBM InfoSphere Optim Data Privacy 提供了一些技术,让您可以在云应用程序中构建所需的数据隐私保护。本教程将介绍如何使用 Bluemix SQL 数据库,在 Java EE 应用程序中利用 Optim 的用户定义的数据隐私函数。
““在本教程中您会看到,Bluemix 和 Optim 提供了必要的工具和技术,帮助您在应用程序中构建有效的数据隐私保护。”
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 语句中。下面这个示例返回一组屏蔽的信用卡号。
1234SELECT 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 时,该提供程序还可以生成一个随机值。
可以使用电子邮件隐私功能提供程序生成一个电子邮件地址。电子邮件地址由两部分组成,一个用户名和一个域名,它们之间使用 @ 符号分开。例如 [email protected]。
可使用哈希隐私功能提供程序,使用一个哈希算法生成的数字值屏蔽来源数据。可以这些数字值为基础,提供来自查找表或一个值数组的替换数据。
可以使用全国性 ID 隐私功能提供程序屏蔽全国性 ID 编号,比如美国社会安全编号。该提供程序可以使用保留了部分来源值的可重复方法,或者使用不会保留来源值的任何部分的随机方法来屏蔽全国性 ID 编号。该提供程序还包含输出值的多个分隔符选项(斜杠、句点、空格或无分隔符)。
Optim Data Privacy 提供程序库还包含用于对通常无法通过算法屏蔽的信息类型(比如姓名和地址)执行查找操作的提供程序。但是,大多数关系数据库管理系统 (RDMS) 都不允许从 SQL UDF 内访问数据库表,所以要执行查找,需要使用哈希隐私功能提供程序,并使用该哈希值作为键来选择查找替换值,比如通过联结 (join)。
有关的更多信息,请访问 IBM InfoSphere Optim Test Data Management Solution 信息中心 和 Optim Data Privacy library 章节。
为了演示 SQL Database 数据隐私特性,我开发了一个使用 Java 代码撰写的 演示应用程序,该应用程序可以部署在 Bluemix 上。它使用了标准的 Java Enterprise Edition (JEE) 和 Java Database Connectivity (JDBC) 特性,以及通过 VCAP_SERVICES 实现的动态配置支持。
该应用程序使用了 Eclipse for JEE 开发工具,以及 WebSphere Application Server Liberty 配置文件和 DB2 for Linux, UNIX, and Windows (DB2 LUW) 编写。
开发并向 Bluemix 部署应用程序时,通常会向每个应用程序绑定一个或多个服务,比如 SQL Database。有关绑定到该应用程序的服务的详细信息,包含在环境变量 VCAP_SERVICES 所提供的一个 JSON 文档中。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657String 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); } }
1234567891011connection = 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); }
1234567891011121314151617Connection 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;
12Statement statement = getStatement(); return statement.executeUpdate(sql);
12345ApplicationConfiguration configuration = getConfiguration(); return String.format( "CREATE TABLE %s.OPTIM_SALES_MASKED AS (SELECT * FROM %s.OPTIM_SALES) WITH NO DATA ", configuration.getSchema(), configuration.getSchema());
12345678910111213141516171819202122232425262728293031323334353637383940ApplicationConfiguration 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 服务作为基于云的产品的性质,该服务提供的 DB2 数据库存在多种限制和局限性。最明显的限制是,目前无法从云外部连接到 SQL Database 实例。这使得用户无法使用 DB2 命令行实用程序和其他 SQL 工具(比如 Eclipse)。但 SQL Database 有一个与 Bluemix 集成的控制台提供了此功能。
要创建数据库表和视图,可以单击 Run DDL。
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859------------------------------------------------ -- 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 后,可以将任何所需的数据加载到数据库实例中。演示应用程序的数据包含两个表:
这两个表包含敏感信息,在真实世界中,应该在用于分析或测试之前先屏蔽这些信息。
以下步骤展示了销售数据的加载。
单击 Browse files 选择您的本地文件系统中的一个文件,其中包含逗号分隔值 (CSV) 格式的数据。一定要为 Row one contains the column names 选择 No。
使用 table 下拉菜单选择该表,单击 Load File 将数据上传到 Bluemix。
Bluemix 将数据加载到表中后,您将获得一个表明加载、拒绝、删除和跳过的行数的状态,以及一个表预览视图。
可以使用 Cloud Foundry cf 命令行实用程序 部署 Web 应用程序归档文件 (WAR)。
1cf login https: //api.ng.bluemix
.war
文件或一个目录的内容(布局类似于一个 .war
文件)。在本例中,只需推送 .war
文件:
1cf push –p SQLDBOptim.war
1cf apps
1cf services
1cf logout
单击 Mask Customer Credit Card Numbers 或 Mask Sales Social Security Numbers。
随着有关数据隐私的法律法规得到更多的关注,企业拥有具有数据屏蔽功能的应用程序变得至关重要。如本教程所示,IBM Bluemix 和 Optim 提供了必要的技术和工具来帮助您构建这些应用程序。
点击这里,查看原文