SAP Cloud Platform, API Management offers many out of the box API Security best practices which can be customized based on your enterprise requirements. These API Security Best Practices includes security policies for Authentication and Authorization, Traffic Management and many more.
Data masking is the process of hiding original data with random characters or data and is an essential component of a comprehensive data security plan. Data masking reduces the exposure of the sensitive data with an organization.
Gartner in their paper describe the data masking concepts to prevent data loss. Data masking is also described in the
GDPR ( General Data Protection Regulation) that takes effect on May 2018 as way to support pseudonymization.
XSLT is an easy way to transform one form of XML data into another format and it works best if the input document or content is in
XML format. JavaScript is a programming language that supports parsing of the
JSON objects and can be used to easily transform or generate new JSON response. Using an
XSL Transform policy for XML response and a
JavaScript Policy for JSON response data masking can be easily achieved in SAP Cloud Platform API Management.
In this blog we will cover the data masking for
OData ( an OASIS standard that defines a set of best practices for building and consuming RESTful APIs) APIs, which supports both XML and JSON format and this concept can be applied to any REST APIs.
More best practices covered in API Security Best Practices blog series.
Prerequisites
Launch API Portal
- Click on the link Access API Portal to open API Portal.
Data masking for OData calls
In this section we would describe the usage of the XSL tranform policy to mask the properties in XML format and JavaScript policy to mask properties in JSON format of the OData APIs. As an example for the OData APIs, we would be using
Business Partner collection of OData service from
SAP Gateway and would be masking the following properties from the API response received from the SAP Gateway system:-
- EmailAddress
- PhoneNumber
- FaxNumber
Refer Rate limit API calls blog to create an API Proxy to an OData API from SAP Gateway and applying an API Rate limit using Quota policy. In this blog we would be extending the same to add the support for data masking for OData APIs.
- Navigate to the Define from the hamburger icon, then select the tab APIs. Select the API Proxy to which API Rate limiting was applied.
- Click on the Policies button of the selected API Proxy.
- Click on the Edit button from the Policy designer and then from Scripts tab click on the + button to add the JavaScript file for masking the properties from the OData APIs.
- In the Create Script dialog provide the name of the XSL file say maskResponseXSLT, select XSL from Type and select Create from the Script drop down. Finally click on the Add button.
- Select the newly added XSL file maskResponseXSLT and in the Script Resource copy paste the following code snippet.
<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:ns3="http://www.hr-xml.org/3" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="maskvalue">*******</xsl:param>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:choose>
<xsl:when test="local-name(.)='EmailAddress' or local-name(.)='PhoneNumber' or local-name(.)='FaxNumber'">
<xsl:value-of select="$maskvalue"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="@*|node()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
The above XSL checks for the element name EmailAddress, PhoneNumber and FaxNumber and if a match is found then it would replace the value with maskValue parameter value else the response value would be copied.
Note that the XSL in the blog is just a sample snippet and this snippet would have to be adjusted to handle all the edge cases of OData calls.
- Select PostFlow from the ProxyEndPoint section and then click on the + button next to the XSL Policy available under the Mediation Policies segment.
- In the Create policy screen specify the policy name say maskDataInXMLResponse, select Outgoing Response from Stream and then click on the Add button.
- Select the policy newly added maskDataInXMLResponse policy then add the following policy snippet to invoke the maskResponseXSLT XSL file.
<XSL async="true" continueOnError="false" enabled="true" xmlns="http://www.sap.com/apimgmt">
<!-- A variable that stores the output of the transformation -->
<OutputVariable>response.content</OutputVariable>
<!-- The XSLT file to be used for transforming the message. -->
<ResourceURL>xsl://maskResponseXSLT.xsl</ResourceURL>
<!-- Contains the message from which information needs to be extracted -->
<Source>response</Source>
</XSL>
- In the Condition String text box, enter the following snippet so that the XSL policy is executed only for BusinessPartnerSet for XML format.
proxy.pathsuffix MatchesPath "/BusinessPartnerSet**" and ((request.header.Accept = null or request.header.Accept = "" or request.header.Accept = "application/xml") or request.queryparam.$format != "json")
Note that the condition string value used in this blog is just a sample and would have to be extended to handles all the edge cases.
With this we have successfully added an XSL transformation policy to mask the properties from BusinessPartnerSet collection for OData response in XML format. In the subsequent steps we would using adding the support for masking the response in JSON format.
- From Scripts tab click on the + button to add the JavaScript file for masking the properties for the JSON format.
- In the Create Script dialog provide the name of the JavaScript file say maskDataInJsonResponse and then select Create from the Script drop down. Finally click on the Add button.
- Select the newly added JavaScript file maskDataInJsonResponse and in the Script Resource copy paste the following code snippet.
var maskProperties = ["EmailAddress", "PhoneNumber","FaxNumber"];
var maskValue = "****"
function maskData(data){
for(var propertyName in data){
if(maskProperties.indexOf(propertyName) > -1){
data[propertyName] = maskValue;
}
}
return data;
}
function processResponse(response){
if(response != null && response.d){
if(response.d.results && response.d.results.length > 0){
for(var i=0,length =response.d.results.length;i<length ; i++){
response.d.results[i] = maskData(response.d.results[i]);
}
}else{
response.d = maskData(response.d);
}
}
return response;
}
var response = JSON.parse(context.proxyResponse.content);
var maskedResponse = processResponse(response);
context.proxyResponse.content = JSON.stringify(maskedResponse);
The above snippet, checks if this is OData response returns an Array of business partner set or single business partner set entity and then accordingly mask the selected properties from the OData response for JSON format.
Note that the above JavaScript is just a sample snippet and this snippet would have to be adjusted to handle all the edge cases of OData calls.
- Select PostFlow from the ProxyEndPoint section and then click on the + button next to the JavaScript Policy available under the Extensions Policies segment.
- In the Create policy screen specify the policy name say maskDataInJsonFormat, select Outgoing Response from Stream and then click on the Add button.
- Select the policy newly added maskDataInJsonFormat policy then add the following policy snippet to invoke the maskDataInJsonResponse JavaScript file.
<!-- this policy allows us to execute java script code during execution of an API Proxy -->
<Javascript async="false" continueOnError="false" enabled="true" timeLimit="200" xmlns='http://www.sap.com/apimgmt'>
<ResourceURL>jsc://maskDataInJsonResponse.js</ResourceURL>
</Javascript>
- In the Condition String text box, enter the following snippet so that the XSL policy is executed only for BusinessPartnerSet for JSON format.
proxy.pathsuffix MatchesPath "/BusinessPartnerSet**" and (request.header.Accept = "application/json" or request.queryparam.$format = "json")
Note that the condition string value used in this blog is just a sample and would have to be extended to handles all the edge cases.
- Click on the Update button to save the Policy changes
- Click on the Save button to save the changes to API Proxy.
With this we have successfully added a JavaScript transformation policy to mask the properties from BusinessPartnerSet collection for OData response in JSON format. In the subsequent steps we would using adding the support for masking the response for JSON format.
Finally testing the flow
- Navigate to the Test tab from the hamburger icon
- From the APIs list search for the API Proxy that you would like to test say GatewayServiceRestrictedAccess and then click the API to test.
- Click on the Authentication: None link and select Basic Authentication to set the user credential to connect to the SAP Gateway ES4 system
- Enter your user credential to the SAP Gateway ES4 system and click on the OK button
- Append /BusinessPartnerSet to the API Proxy URL and Send button
- In the response body, the EmailAddress, PhoneNumber and FaxNumber values would be masked with *****.
- Click on the Headers button. Enter Accept as header name and application/json as the header value and then click on the Send button
- In the response body, the EmailAddress, PhoneNumber and FaxNumber values would be masked with *****.
Further Reads