Operations

What are operations?

Operations are different ways to navigate structured data and transform a piece of it by either redacting or replacing the value with a surrogate value.

Operations Examples

Most Common:

  • JSONPath (JSON)

  • XPath (XML)

  • Form

  • HTML / CSS

  • Regex

JSONPath

{
    "customers": {
        "first_customer": {
            "first_name": "John",
            "last_name": "Doe",
            "credit_card": "4111111111111111",
            "card_exp": "9/23",
            "card_cvv": "123"
            },
        "second_customer": {
            "first_name": "Jane",
            "last_name": "Smith",
            "credit_card": "4222222222222222",
            "card_exp": "9/23",
            "card_cvv": "123"
        }
    }
}

To redact the PCI data in this, we would simply need to create two JSONPath Operations.

Nesting with JSONPath is fairly straightforward. Every level down you go in standard JSON is just $.toplevelkey.midlevelkey.finallevelkey like if there are lists in between; you select the item using the index (or you can use wildcards).

To redact the credit_card number. All we have to do is select the key. With JSONPath selected as the operation, enter this snippet on the line next to it:

$.customers..credit_card

To redact credit_card number only for the first_customer, we would need to select the next snippet:

$.[0].credit_card

If you want to experiment with JSONPath, check out this tool.

In advanced options, you can select FPE_6_T_4 to keep the credit card format for mod 10/ Luhn validation.

To redact the CVV, we need to store that in memory, not persistently. So, we add an "Add Entry".

Do exactly the same thing, but change JSONPath to:

$.[0].card_cvv

In the advanced options, we need to select Storage Volatile

Xpath

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schp.org/e/" xmlns:xsd="http:rg/2chema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
        <AddCardResponse xmlns="">
            <ResponseCode>00</ResponseCode>
            <ResponseDesc>New Card Purchase Order Completed Successfully (932501******1238)</ResponseDesc>
            <NewCardNumber>
                    <Number>4111111111111111</Number>
                <ExpiryDate>092019</ExpiryDate>
            </NewCardNumber>
            <Balance>0.00</Balance>
            <TransId>F378</TransId>
            <CustomerId>3250033</CustomerId>
            <Fee>0.00</Fee>
            <ReferenceID>32513325</ReferenceID>
            <NameOnCard>Andrew</NameOnCard>
        </AddCardResponse>
    </soapenv:Body>
</soapenv:Envelope>

An example of how to correctly specify the path to get Number data:

//Number

or

/Envelope/Body/AddCardResponse/NewCardNumber/Number

Invalid path:

/soapenv:Envelope/soapenv:Body/AddCardResponse/NewCardNumber/Number

You do not need to specify Namespace in your path

To check XPath navigation, use this tool.

Form

The last type of transformer in this guide is the Form operation. We just use the form field input names as the selector.

HTML form example:

<div class="creditCardForm">
    <div class="heading">
        <h1>Confirm Purchase</h1>
    </div>
    <div class="payment">
        <form action="https://<VAULT_ID>.<ENVIRONMENT>.verygoodproxy.com" method="post">
            <div class="form-group owner">
                <label for="owner">Owner</label>
                <input type="text" class="form-control" name="owner" id="owner">
            </div>
            <div class="form-group CVV">
                <label for="cvv">CVV</label>
                <input type="text" class="form-control" name="cvv" id="cvv">
            </div>
            <div class="form-group" id="card-number-field">
                <label for="cardNumber">Card Number</label>
                <input type="text" class="form-control" name="cardNumber" id="cardNumber">
            </div>
            <div class="form-group" name="expiration-date" id="expiration-date">
                <label>Expiration Date</label>
                <select>
                    <option value="01">January</option>
                    <option value="02">February </option>
                    <option value="03">March</option>
                    <option value="04">April</option>
                    <option value="05">May</option>
                    <option value="06">June</option>
                    <option value="07">July</option>
                    <option value="08">August</option>
                    <option value="09">September</option>
                    <option value="10">October</option>
                    <option value="11">November</option>
                    <option value="12">December</option>
                </select>
                <select>
                    <option value="16"> 2016</option>
                    <option value="17"> 2017</option>
                    <option value="18"> 2018</option>
                    <option value="19"> 2019</option>
                    <option value="20"> 2020</option>
                    <option value="21"> 2021</option>
                </select>
            </div>
            <div class="form-group" id="pay-now">
                <button type="submit" class="btn btn-default" id="confirm-purchase">Confirm</button>
            </div>
        </form>
    </div>
</div>

For forms, the "name" of the input field is all that's required to replace with a surrogate value. If the Form is URL encoded, make sure you enter the filters as they look decoded.

Select the "Form" transformer and just enter:

cardNumber

and under a new entry, volatile storage for CVV

cvv

HTML

You can select this transformer option to select data in HTML forms by using CSS selectors.

If you have used a JS library like Sizzle or jQuery, you will already be familiar with these.

The simplest selectors allow you to match on

  • class names through a . e.g. .myClassName

  • an identifier via a # e.g. #myId

  • an attribute using a series of brackets, with an attribute name and optionally a value inside, e.g. [attr=value]

  • an element type by simply typing the name of the element, e.g. input

You can nest these selectors in order to achieve precise selection of data on the page, e.g. #myId .myClassName will match the input element in the following section

<html>
  <body>
    <div id="myId">
      <span class="myClassName">
        Text that will be operated on
      </span>
    </div>
  </body>
</html>

Regex

If the above examples do not cover the type of selection you need, then you can always fall back to a regex. VGS provides a series of named prefixes to assist with complex matching. These are

  • prefix - Anything to match before

  • token - The data to match

  • suffix - Anything matched after

If these are omitted, then anything matched by the regex in its entirety will be operated on.

Here are two examples

  • (\d{16}) - would operate on any 16-digit sequence

  • (?<prefix>foo)(?<token>\d{16})(?<suffix>\d{3}) - would operate on a 16 digit sequence prefixed with foo and suffixed with three digits e.g. foo1234567890123456123 would become footok_sandbox_asd123123 where the prefix is foo, the suffix is 123 and the 16 digit value 1234567890123456 is replaced with the value tok_sandbox_asd123

These examples cover the most common operation use cases.

Replace the value with any text and aliased value.

Replacement parameter: any text <alias placeholder>

Route config:

transformer: REGEX
transformer_config: - '\b[0-9 ]{13,20}\b'
transformer_config_map:
    patterns: - '\b[0-9 ]{13,20}\b'
    replacement: 'any text:%s'

Input:

{
    "first_name": "JOHN",
    "card_number": "4111 1111 1111 1111",
    "ssn": "444411111",
    "dob": "1931-01-01"
}

Output:

{
    "first_name": "JOHN",
    "card_number": "any text:tok_sfvDwkNetJGnNWaPqPeYhY",
    "ssn": "444411111",
    "dob": "1931-01-01"
}

Replace the value with aliased value and preserved group.

Replacement parameter: <regexp group placeholder> any text <alias placeholder>

Route config:

transformer: REGEX
transformer_config: - '4313-35(?<card1>00)-(?<card2>0000)-(?<lastFour>\d{4})'
transformer_config_map:
    patterns: - '4313-35(?<card1>00)-(?<card2>0000)-(?<lastFour>\d{4})'
    replacement: '%s:${lastFour}'

Input:

{
    "first_name": "JOHN",
    "card_number": "4313-3500-0000-1234",
    "ssn" : "444411111",
    "dob" : "1931-01-01"
}

Output:

{
    "first_name": "JOHN",
    "card_number": "tok_mTkSAHoAvvNiFUCEiYSWtj:1234",
    "ssn": "444411111",
    "dob": "1931-01-01"
}

If you have any questions or trouble, please reach out on our site chat or contact [email protected].

Last updated