PCI and PII Compliance When Logging Data In Digital Transformation Projects

Gerry Kovan
8 min readJul 3, 2019

Authored by Gerry Kovan and Ramesh krishnamaneni

When working on digital transformation projects, payment card industry (PCI) and personally identifiable information (PII) compliance is one of the top requirements that must be addressed. Organizations that violate PCI and PII compliance can pay fines into the millions of dollars as well as incur other significant costs to remedy the data breach[1]. Digital transformation projects typically involve developing new modern business applications using microservices architectures. Logging data and events is an essential part of the application in order to allow developers to diagnose and understand runtime behavior of the applications. When logging the data of the microservices process, the data typically has many occurrences of both PCI and PII data, so it is imperative that it be handled in an appropriate and compliant manner.

This article will address how we handled it on several digital enterprise transformation projects. We will use a sample mortgage calculator application to demonstrate the key concepts to ensure your digital transformation project meets PCI and PII requirements. We developed our sample app microservices using Spring Boot, a java based microservices framework; however the concepts can be applied to any programming language and framework.

What is PCI?

Payment card industry (PCI) compliance refers to the technical and operational standards that businesses must follow to ensure that credit card data provided by cardholders is protected [2]. Examples of PCI data is:

· Credit card number

· Credit card expiration data

· Credit card verification code

· Card holder name

What is PII?

Personally Identifiable Information (PII) is any information about an individual maintained by an agency that can be used to distinguish or trace an individual’s identity [3].

Examples of PII data is:

· Full name

· Home address

· Email address

· Passport number

· Data of birth

· Driver’s license number

· Social security number

· Telephone number

· Biometric data

· And many other types

Description of the mortgage calculator application

The application is a REST api that allows users to make requests to get monthly mortgage payment information. The request contains both PCI (i.e. credit card number, expiry data) and PII data (i.e. name, property address, social security number).

The following image shows a sample json request body. The request body includes information such as name, property address, credit card number and expiry date, social security number as well as the required info to calculate a monthly mortgage payment such as principal, interest rate, term and mortgage type.

Sample request body json:

{
"name" : "Gerry Kovan",
"propertyAddress": "99-31 64th Avenue, Rego Park, NY, 11581",
"creditCard": "4111111111111111",
"creditCardExpiry": "05/26",
"socialSecurityNumber": "123-45-6789",
"principal": "100000",
"interestRate": "5.0",
"term": "30",
"type": "fixed"
}

Sample response body json showing the calculated monthly payment amount:

{
"name": "Gerry Kovan",
"propertyAddress": "99-31 64th Avenue, Rego Park, NY, 11581",
"creditCard": "4111111111111111",
"creditCardExpiry": "05/26",
"socialSecurityNumber": "123-45-6789",
"principal": 100000,
"interestRate": 5,
"term": 30,
"type": "fixed",
"monthlyPayment": 536.82
}

Logging

Application logs provide visibility into the runtime behavior of the application. It is critical for the developers to view and analyze the log data in order to diagnose and fix application defects. According to the 12 factor app standard, logs are treated as streams and are typically sent to a service such as splunk (www.splunk.com) or a Hadoop data warehousing system for indexing and analysis [4]. In our application, we log the entire request and response objects. Both the request and response contain PCI and PII information. We used Spring AOP (Aspect Oriented Programming) to achieve this.

The figure below shows the controller code for the /calculate REST endpoint. The request body is a java object called MortgageCalculatorRequest. When the controller executes successfully, it responds with the data encapsulated in the java object called MortgageCalculatorResponse.

The request and response objects map directly to the sample json discussed above.

Figure 1: Controller code showing request and response objects for the /calculate REST endpoint.

In order for developers to debug the code and understand the runtime behavior of the application, we need to log the relevant data. It is typical to log events such as when the controller begins execution and when it ends execution. It is also typical to log the data in the request and response objects.

To achieve this, we leveraged Spring AOP (aspect oriented programming). AOP is a programming paradigm that increases code modularity by allowing separation of cross cutting concerns. Logging is an excellent example of a cross cutting concern. You will notice that the controller code in the figure above does not have any logging code in it which keeps the code clean and easy to follow and read for a developer.

Spring AOP Logging Aspect

The figure below shows the code for the Spring AOP logging aspect. This code gets invoked whenever the REST call to the ‘/calculate’ gets made which invokes the controller. The method ‘controllerStart’ gets invoked before the controller begins processing and this method is responsible for logging the request data. The method ‘controllerEnd’ gets invoked once the controller finishes executing and is responsible for logging the response data.

Figure 2: Spring AOP logging aspect which logs the request and response data

Log messages without addressing PCI and PII compliance

Below are the logs that the aspect prints out before addressing the PCI and PII requirements. Notice that for the request we log the ClientId, RequestURI, RequestURL and request body data. For the response logs, we log the response body data. Notice that the sensitive information in the request and response body is clearly visible to anyone who can gain access to the logs. PII information like name, property address, social security number is clearly visible. PCI information such as credit card number and expiry date are also clearly visible.

Figure 3: Request Body log without masking — all sensitive data is visible in clear text
Figure 4: Response Body log without masking — all sensitive data is visibile in clear text

Log messages after addressing PCI and PII compliance

The request and response logs below address the PCI and PII requirements by masking or encrypting the relevant data. The sensitive data is no longer visible to anyone including developers who can gain access to the logs. The logs are still valuable to developers to help diagnose application issues which is really the end goal from a logging perspective however the users data is protected.

Figure 5: Request body log with masking — sensitive data is not visible in clear text
Figure 6: Response body log with masking — sensitive data is not visible in clear text

PCI and PII Compliance for Log Data

For logging PCI data fields, we replace all the characters with a ‘*’ and we optionally allow the programmer to specify how many characters to show or keep without masking. For example, when we log the credit card number, we do show the last four digits.

For logging PII data fields, we replace all the characters with a hash of the original value keeping the length of the string the same. We also allow the programmer to specify how many characters to show or keep without masking. For example, when we log the social security number, we do show the last 4 digits.

How we implemented the PCI and PII logging compliance?

We created Java annotations for PCI, PII, and Mask as follows…

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
public @interface PCI {
public int keepLastDigits() default 0;
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
public @interface PII {
public int keepLastDigits() default 0;
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Mask {
}

We then annotate the request and response java model objects. We annotate the class with @Mask to indicate that the Java object has PCI and/or PII data fields in it. We then annotate the appropriate data fields with PII or PCI as shown below.


@Mask
public class MortgageCalculatorRequest {

@PII
String name;
@PII
String propertyAddress;
@PCI(keepLastDigits=4)
String creditCard;
@PCI
String creditCardExpiry;
@PII(keepLastDigits=4)
String socialSecurityNumber;
Double principal;
Double interestRate;
Integer term;
String type;
}
@Mask
public class MortgageCalculatorResponse {

@PII
String name;
@PII
String propertyAddress;
@PCI(keepLastDigits=4)
String creditCard;
@PCI
String creditCardExpiry;
@PII(keepLastDigits=4)
String socialSecurityNumber;

Double principal;
Double interestRate;
Integer term;
String type;
Double monthlyPayment;
}

We created a custom serializer that converts the data in the request and response Java objects into a string representation masking the appropriate data fields. The basic logic is as follows:

  • Check if java object has the ‘@Mask’ annotation.
  • If yes, then we iterate through all the fields in the object
  • If a field is annoted with ‘@PCI’ then we replace all characters with a ‘*’ and except for the last characters as specified by ‘keepLastDigits’ annotation parameter.
  • If a field is annotated with ‘@PII’ then we replace all characters with a hexadecimal format of the hash value (one way encryption). We optionally show in plain text the trailing characters in the field as specified by the ‘keepLastDigits’ annotation parameter.

The code snippet below shows the custom serializer that masks the sensitive data when converting the java object to a string for logging.

Figure 7: Custom serializer that masks sensistive PCI and PII data fields for logging

Summary

Logging data is a critical aspect of any application including and especially applications designed using a microservice architecture. Developers must be careful to mask any and all sensitive PCI and PII data in order to protect and prevent any data breaches. This blog demonstrated an approach to do this using the Spring Boot Java framework and core Java concepts.

References

[1] https://www.securitymetrics.com/blog/how-much-does-data-breach-cost-your-organization

[2] https://www.investopedia.com/terms/p/pci-compliance.asp

[3] https://piwik.pro/blog/what-is-pii-personal-data/

[4] https://12factor.net/logs

Bring your plan to the IBM Garage.
Are you ready to learn more about working with the IBM Garage? We’re here to help. Contact us today to schedule time to speak with a Garage expert about your next big idea. Learn about our IBM Garage Method, the design, development and startup communities we work in, and the deep expertise and capabilities we bring to the table.

Schedule a no-charge visit with the IBM Garage.

--

--

Gerry Kovan

IBMer, software engineer, Canadian living in New York, husband, father and many other things.