Search code examples
javascriptangularjspayment-gatewaycredit-cardbraintree

Encrypting credit card details using AngularJS in Braintree


I am using Braintree for payment gateway and I have across an issue.
I am sending credit card information with other user details.

For security purposes Credit card information has to be encrypted and it is being done by Braintree by including following:

braintree.onSubmitEncryptForm('braintree-payment-form');

This works fine until I use pure javascript (AngularJS) in front-end and I'm seeing that data is not encrypted while sending to server,
Here is code:

<form name="paymentForm" ng-submit="submitUser(userDetails)" method="post" id="braintree-payment-form">
<p>
  <label style="color:white">Name</label>
  <input type="text" ng-model="userDetails.userName" name="userName" size="20" />
</p>
<p>
  <label style="color:white">Email</label>
  <input type="text" ng-model="userDetails.email" name="email" size="20"/>
</p>
<p>
  <label style="color:white">Company</label>
  <input type="text" ng-model="userDetails.company" name="company" size="20" />
</p>
  <label style="color:white">Card Number</label>
  <input type="text" size="20" ng-model="userDetails.number" autocomplete="off" data-encrypted-name="number" />
</p>
<p>
  <label style="color:white">CVV</label>
  <input type="text" size="4" ng-model="userDetails.cvv" autocomplete="off" data-encrypted-name="cvv" />
</p>
<p>
  <label style="color:white">Expiration (MM/YYYY)</label>
  <input type="text" size="2" ng-model="userDetails.month" data-encrypted-name="month" /> / <input type="text" size="4" ng-model="userDetails.year" data-encrypted-name="year" />
</p>
<input type="submit" id="submit" />

On form submit, I am sending data to server.

$scope.submitUser = function(userDetails){
    $http({
        url: '/createtransaction',
        method: 'POST',
        data: JSON.stringify(userDetails),
        headers: {'Content-Type': 'application/json'}
    }).success(function (data, status, headers, config) {
        // success
    }).error(function (data, status, headers, config) {
        //error
    });
}

Is there anyway I can encrypt card details?


Solution

  • The question is "why is the AJAX request data not encrypted by Braintree JS", and the answer is nothing to do with HTTPS.

    Yes, HTTPS is required to encrypt traffic in production - and in this case it will encrypt the already encrypted card data - but HTTPS is neither the question nor the answer here.

    If you look at the Braintree documentation (Example here) you'll note that each input in the example form has added an attribute data-encrypted-name:

    <input type="text" size="20" autocomplete="off" data-encrypted-name="number" />
    

    The documentation then points out this code:

    braintree.onSubmitEncryptForm('braintree-payment-form');
    

    When the form is submitted, code in braintree.js is invoked, inspects the form, looks at the plain text in each marked input, encrypts it, save those encrypted values according to the data--encrypted-name attributes, and then that encrypted data is used when the form is transmitted via HTTP/HTTPS.

    In the AngularJS example code above, the OP does include the data-encrypted-name attributes on some of the inputs (I don't know if it needs to be on all of them) but just labeling the input is not enough. The function to encrypt the raw input values (or in this case, the model data) still needs to be invoked, and then that encrypted model can be sent in a POST back to the server.

    Said another way, the problem implementation:

    1. Form builds a model
    2. Model sent via HTTP to server

    The corrected implementation would be:

    1. Form builds a model
    2. Braintree.js invoked to encrypt some parts of the model.
    3. Encrypted model is sent via HTTP (or HTTPS in production) to server

    Here's a plunkr someone else did showing one way to encrypt AngularJS model data on the fly:

    http://plnkr.co/edit/2kF9Im?p=preview

    If it were me, I'd just call braintree.encrypt() on each field immediately prior to submitting the form rather than on every keypress - or modify the directive to work on the form at submission time.