braintree
The mere mention of “PCI Compliance” usually elicits a combination of confused looks and sweaty palms from business owners who accept credit card payments online. But what does it really mean?
仅仅提到“ PCI Compliance”通常会引起混淆的外观和来自在线接受信用卡付款的企业主的汗水。 但这到底是什么意思?
It’s a complicated topic, but the short version is that the major credit card companies founded a council called the Payment Card Industry Security Standards Council (PCI SSC) in 2006 in order to create a set of rules standardizing the security policies and procedures that merchants should follow (PCI DSS) when processing and storing sensitive credit card information. In order to determine whether your systems are compliant, you would normally choose the appropriate Self Assessment Questionnaire (SAQ) from one of eight options, and then answer a series of questions to determine whether you were, in fact, compliant. Large corporations often employ the services of a Qualified Security Assessor (QSA) to help them fill out SAQ D (the most involved of the SAQS), which can cost hundreds of thousands of dollars. And to make matters worse: if your systems are compromised and it is determined that they were not compliant when they were breached, you could be liable for fines of up to $500,000 per incident.
这是一个复杂的话题,但简短的说法是,主要的信用卡公司于2006年成立了一个名为“ 支付卡行业安全标准委员会 (PCI SSC)”的委员会 ,以制定一套规范商家应采用的安全策略和程序的规则。处理和存储敏感的信用卡信息时,请遵循(PCI DSS)。 为了确定您的系统是否符合要求,通常您会从八个选项中选择一个合适的自我评估问卷(SAQ) ,然后回答一系列问题以确定您实际上是否符合要求。 大型公司通常会聘用合格安全评估师(QSA)的服务来帮助他们填写SAQ D(SAQS中涉及最多的),这可能会花费数十万美元。 更糟的是:如果您的系统受到威胁,并且确定系统在受到破坏时不合规,则可能会为每次事件处以最高500,000美元的罚款。
So what is a small business owner supposed to do? That’s where Braintree Payment Solutions comes in. They offer two solutions to minimize your PCI Compliance burden: Transparent Redirect and Braintree.js. I should mention that neither Braintree nor any other PCI DSS compliant service provider can tell you which SAQ to fill out, or whether your systems are compliant. But they have paired with Security Metrics, an industry-leading QSA, to provide a cost-free solution to help all of their customers achieve and maintain PCI Compliance. And in their experience, customers using either Transparent Redirect or Braintree.js have typically been able to fill out SAQ A, which is much less involved (and therefore costly) than SAQ D. You can read more here.
那么,小企业主应该怎么做? 那就是Braintree支付解决方案的用武之地。它们提供了两种解决方案来最大程度地减少PCI合规性负担:透明重定向和Braintree.js。 我应该提到,Braintree和任何其他符合PCI DSS的服务提供商都无法告诉您要填写哪个SAQ,或者您的系统是否符合要求。 但是,他们已经与行业领先的QSA Security Metrics配对,以提供免费的解决方案来帮助所有客户实现并维持PCI法规遵从性。 并且根据他们的经验,使用透明重定向或Braintree.js的客户通常能够填写SAQ A,与SAQ D相比,它参与起来少(因此成本高)。您可以在此处阅读更多内容。
But enough background; let’s write some code.
但是足够的背景; 让我们写一些代码。
入门 (Getting Started)
This article is going to focus on the Transparent Redirect method. The first thing we have to do is head over to Braintree to get our server-side API keys. For those of you without a production account, point your browser to the Braintree Sandbox and sign up for a test account. Log in, and click on “Account -> API Keys.” Then, click the “Generate New” button, and finally click “View” under the Private Key column of the newly generated API key. You’ll be brought to the following screen, which contains all of the information you need to configure the Braintree Client Library.
本文将重点介绍透明重定向方法。 我们要做的第一件事就是前往Braintree获取我们的服务器端API密钥。 对于那些没有生产帐户的用户,请将浏览器指向Braintree沙箱,然后注册一个测试帐户。 登录,然后单击“帐户-> API密钥”。 然后,单击“生成新”按钮,最后单击新生成的API密钥的“私钥”列下的“查看”。 您将进入以下屏幕,其中包含配置Braintree客户端库所需的所有信息。
You can see it even has a tool that generates the configuration code for you in a variety of languages.
您甚至可以看到它具有一个可以用多种语言为您生成配置代码的工具。
Now it’s time to install the actual Braintree PHP Client Library. We can do that with Composer by running the following command:
现在是时候安装实际的Braintree PHP客户端库了。 我们可以通过运行以下命令来使用Composer做到这一点:
composer require braintree/braintree:*
透明重定向 (Transparent Redirect)
One of the main factors that helps determine whether you have to fill out SAQ D or SAQ A is whether credit card data is transmitted through your system. And in the beginning of the typical Server to Server (S2S) model, your web server would send a payment form to the customer’s browser. After filling out the form, the customer would press submit, which would POST the data back to your web server, which would in turn forward some of that data on to Braintree for validation and processing. That would look something like this:
帮助确定是否必须填写SAQ D或SAQ A的主要因素之一是信用卡数据是否通过系统传输。 在典型的服务器到服务器(S2S)模型的开始,您的Web服务器会将付款表格发送到客户的浏览器。 填写完表格后,客户将按Submit(提交),它将数据回传到您的Web服务器,然后将其转发到Braintree进行验证和处理。 看起来像这样:
With Transparent Redirect, however, the form action is set so that the form will POST directly to Braintree’s servers, and the response is sent back to the client browser. The browser is then redirected to a script on the web server using an HTTP 303 redirect. Finally, the web server script confirms the transaction with Braintree, and presents the results to the client browser. So that model looks more like this:
但是,使用“透明重定向”,将设置表单操作,以便表单将直接 POST 到Braintree的服务器 ,并将响应发送回客户端浏览器。 然后,使用HTTP 303重定向将浏览器重定向到Web服务器上的脚本。 最后,Web服务器脚本通过Braintree确认交易,并将结果呈现给客户端浏览器。 因此该模型看起来更像这样:
Now that we have the theory under our belt, let’s go ahead and write some code. Those of you who would like to see the complete version can find it on Github.
现在我们已经掌握了理论,让我们继续编写一些代码。 那些想查看完整版本的人可以在Github上找到它。
The first thing we’re going to do is create a very basic HTML form so that we can enter some data to send to Braintree for processing. I’m going to make this as simple as possible so we can focus on functionality.
我们要做的第一件事是创建一个非常基本HTML表单,以便我们可以输入一些数据发送给Braintree进行处理。 我将使其尽可能简单,以便我们专注于功能。
<!doctype html>
<html lang="en">
<body>
<div id="wrap">
<form method="post" action="" autocomplete="off">
<label>Name on Card: <input type="text" name="transaction[credit_card][cardholder_name]"></label>
<label>Card Number: <input type="text" name="transaction[credit_card][number]"></label>
<label>CVV: <input type="text" name="transaction[credit_card][cvv]" class="short"></label>
<label>Expiration Date (MM/YYYY): <input type="text" name="transaction[credit_card][expiration_date]" class="short"></label>
<input type="submit" value="submit payment">
</form>
</div>
</body>
</html>
There’s nothing complicated going on here. The only thing that you’ll notice is that the input field names are in array format. You can see a full list of valid field names here. The other thing that I’ll point out from that page is that if you are using a framework that has issues with using arrays for input names (I’m looking at you, Zend Framework!), then you can use an alternate double underscore syntax. So your expiration date input would look like this:
这里没有什么复杂的事情。 您唯一会注意到的是输入字段名称是数组格式。 您可以在此处查看有效字段名称的完整列表。 我要从该页面指出的另一件事是,如果您使用的框架在使用数组作为输入名称方面存在问题(我正在看您的Zend Framework!),那么您可以使用另一个双下划线句法。 因此,您的到期日期输入将如下所示:
<input type="text" name="transaction__credit_card__expiration_date">
The only other thing you may notice is that I’ve added an “autocomplete” attribute to my form, and set its value to off. Braintree recommends doing this, and I hope the reason for this is obvious…
您可能会注意到的另一件事是,我向表单添加了“自动完成”属性,并将其值设置为off。 布伦特里(Braintree)建议这样做,我希望这样做的原因很明显…
There are a few other things we need to do in order to harness the magic of Transparent Redirect on our form. But before we do that, we need to configure our script to work with Braintree’s API.
为了利用透明重定向在表单上的魔力,我们还需要做其他一些事情。 但是在执行此操作之前,我们需要配置脚本以与Braintree的API配合使用。
Before I tell you how to do that, I’m going to just mention that, for the sake of clarity, I’ve put all of the PHP and HTML in the same file in my sample code. I hope it goes without saying that in a production project that the setup code would go in my project’s bootstrap file, and that the form processing code would go into a controller action or other separate file. OK, enough apologizing – let’s get this thing set up!
在告诉您如何执行此操作之前,为了清楚起见,我将仅提及所有PHP和HTML放在示例代码中的同一文件中。 我希望不用说,在生产项目中,设置代码将进入我项目的引导文件中,而表单处理代码将进入控制器操作或其他单独的文件中。 好了,很抱歉–让我们开始做这件事!
<?php
require('vendor/autoload.php');
Braintree_Configuration::environment('sandbox');
Braintree_Configuration::merchantId('YOUR_MERCHANT_ID');
Braintree_Configuration::publicKey('YOUR_PUBLIC_KEY');
Braintree_Configuration::privateKey('YOUR_PRIVATE_KEY');
?>
The first line simply allows us to take advantage of Composer’s autoloader and use Braintree’s library without explicitly including any additional files. Hopefully, the next four lines look familiar, because they were copied verbatim from the Sandbox Control Panel API Key tool that I introduced you to in the previous section. Obviously you’ll replace this with the code from your own Control Panel account.
第一行仅使我们能够利用Composer的自动加载器并使用Braintree的库,而无需显式包括任何其他文件。 希望接下来的四行看起来很熟悉,因为它们是从上一节中向您介绍的“沙盒控制面板API密钥”工具逐字复制的。 显然,您将用您自己的“控制面板”帐户中的代码替换它。
The next thing I want to do is set the form action so that our customer will send their sensitive data directly to Braintree, which is the whole point of using TR. Fortunately, the Braintree library makes this very easy by providing a helper object/method. So simply modify your form code like so:
我接下来要做的是设置表单操作,以便我们的客户将其敏感数据直接发送到Braintree,这就是使用TR的重点。 幸运的是,Braintree库通过提供帮助对象/方法使此操作非常容易。 因此,只需修改您的表单代码,如下所示:
<form ... action="<?= Braintree_TransparentRedirect::url()?>">
The only other thing we have to do is create a hidden input which contains a hashed representation of the URL you want Braintree to redirect the customer to after they have submitted the form, as well as any information that you don’t want them to be able to specify. For example, this is where you might put the transaction amount. Just as a matter of style, I like to set the return URL to the payment form itself so that I can display any errors to the user and give them the chance to resubmit. So this is what that would look like:
我们要做的唯一另一件事是创建一个隐藏的输入,其中包含您希望Braintree在客户提交表单后将其重定向到的URL的哈希表示,以及您不希望他们成为的任何信息能够指定。 例如,您可以在其中放置交易金额。 就样式而言,我希望将退货URL设置为付款表单本身,以便我可以向用户显示任何错误,并为他们提供重新提交的机会。 因此,结果如下所示:
$tr_data = Braintree_TransparentRedirect::transactionData([
'transaction' => [
'type' => Braintree_Transaction::SALE,
'amount' => '100.00'
],
'redirectUrl' => 'https://YOUR-DOMAIN.COM/transparent-redirect-form-basic.php'
]);
Obviously I’m hard-coding the amount here, but in a production app you would either generate this using some server-side logic, or in the case of a donation form with an unspecified total, you would create a form field and allow the user to provide one. I also usually set the “submit for settlement” option to true. Otherwise this transaction will simply
显然,我在这里对金额进行了硬编码,但是在生产应用程序中,您可以使用一些服务器端逻辑来生成该金额,或者在捐赠表格的总数未指定的情况下,您可以创建一个表格字段并允许用户提供一个。 我通常还将“提交解决方案”选项设置为true。 否则,此交易只会
Now I just need to add this as a hidden field to my form like so:
现在,只需将其作为隐藏字段添加到表单中,如下所示:
<input type="hidden" name="tr_data" value="<?=$tr_data?>">
Now that we’re ready to submit our data to Braintree, we need to add some code to process the actual Transparent Redirect response.
现在我们准备将数据提交给Braintree,我们需要添加一些代码来处理实际的透明重定向响应。
$status = '';
if(isset($_GET['http_status']) && $_GET['http_status'] == '200') {
try {
$result = Braintree_TransparentRedirect::confirm($_SERVER['QUERY_STRING']);
if ($result->success) {
$status = 'Your transaction was processed successfully.';
} else {
$status = $result->message;
}
} catch (Braintree_Exception_NotFound $e) {
$status = 'Due to security reasons, the reload button has been disabled on this page.';
}
}
Now let’s figure out what we’ve just done. When the user presses the submit button, the form POSTed directly to Braintree, and all of the customer’s sensitive information is stored safely on their PCI CSS compliant servers. Then, an HTTP 303 redirect is sent to the browser, which sends the user to the URL you specified when generating the $tr_data
variable, and appends several parameters to the URL’s query string.
现在让我们弄清楚我们刚刚完成了什么。 当用户按下“提交”按钮时,表格直接过帐到Braintree,所有客户的敏感信息都安全地存储在其PCI CSS兼容服务器上。 然后,将HTTP 303重定向发送到浏览器,该浏览器将用户发送到生成$tr_data
变量时指定的URL,并将几个参数附加到URL的查询字符串中。
When the data is successfully submitted, one of those parameters will be http_status
, and if everything is running smoothly with Braintree’s servers, it will be set to 200
. Obviously in production you would want to also handle non-200 response codes, but for now we’re just making sure to only execute the code inside this if
statement if we have successfully submitted our payment information to their system.
成功提交数据后,这些参数之一将是http_status
,如果Braintree的服务器运行顺利,则将其设置为200
。 显然,在生产中,您还希望处理非200响应代码,但是目前,如果我们已成功将付款信息提交给他们的系统,我们只是确保仅在if
语句中执行代码。
The next thing that happens is that we have to take the query string from our Transparent Redirect and send it back to Braintree to complete the transaction. So we run another library function (Braintree_TransparentRedirect::confirm
) and provide it with our URL query string, in order to tell Braintree to go ahead and process our payment. Once that happens, Braintree sends our script back a result object. Internally, that object can either be a Braintree_Result_Error
or Braintree_Result_Successful
, but both objects have a boolean success
property so you can see whether the transaction succeeded or not.
接下来发生的事情是,我们必须从透明重定向中获取查询字符串,并将其发送回 Braintree以完成事务。 因此,我们运行另一个库函数( Braintree_TransparentRedirect::confirm
)并为其提供URL查询字符串,以告诉Braintree继续进行付款。 一旦发生这种情况,Braintree将我们的脚本发送回结果对象。 在内部,该对象可以是Braintree_Result_Error
或Braintree_Result_Successful
,但是两个对象都具有布尔success
属性,因此您可以查看事务是否成功。
You’ve also probably noticed that I wrapped the entire confirmation in a try/catch block. The one drawback of using the same page to display the form and process the results is that you can only confirm a TR query string once. That means if someone hits the reload button after a failed transaction, your code will try to reconfirm an expired query string, and Braintree will throw an exception.
您可能还注意到,我将整个确认包裹在try / catch块中。 使用同一页面显示表单和处理结果的一个缺点是只能确认一次TR查询字符串。 这意味着,如果某人在交易失败后点击了重载按钮,您的代码将尝试重新确认过期的查询字符串,并且Braintree将引发异常。
Now that we have everything we need we can go ahead and run some test transactions. Full documentation on using the Sandbox can be found here, but if you’re really excited and want to run a successful transaction right away, go ahead and enter your name in the “Name on Card”, 4111111111111111
(4 followed by fifteen ones) as a “Card Number” , 123 in the CVV box, and any date in the future as an expiration date. If everything goes well, you should be able to head back to the Sandbox, click “Transactions” under “Advanced Search”, and after clicking the “Search” button, see your first successful transaction.
现在我们有了所需的一切,我们可以继续进行一些测试事务。 您可以在此处找到有关使用沙盒的完整文档,但是如果您真的很兴奋并且想立即进行成功的交易,请继续在“卡片上的姓名”中输入您的姓名,名称为4111111111111111
(其中4个,后跟15个)作为“卡号”,在CVV框中为123,并将将来的任何日期作为到期日期。 如果一切顺利,您应该可以回到沙盒,单击“高级搜索”下的“交易”,然后单击“搜索”按钮,查看您的第一个成功交易。
花式 (Getting Fancy)
Transparent Redirect is a great way to help minimize your PCI Compliance burden, but it does have a few quirks that you’ll need to get used to. First of all, if you want to include any data on your payment form that doesn’t correspond to one of Braintree’s transactions, customers or credit card objects, then you have to use their “custom field” feature. Let’s say I wanted to capture a user’s favorite color. The first thing I would do is head over to the control panel and click on “Settings -> Processing.” Scroll down to the “Custom Fields” section and click “New.” You’ll find yourself on the following screen:
透明重定向是一种有助于最大程度地减少PCI遵从性负担的好方法,但是它确实有一些需要习惯的怪癖。 首先,如果您想在付款表中包含与Braintree的交易,客户或信用卡对象之一不符的任何数据,则必须使用其“自定义字段”功能。 假设我想捕获用户喜欢的颜色。 我要做的第一件事是转到控制面板,然后单击“设置->处理”。 向下滚动到“自定义字段”部分,然后单击“新建”。 您将在以下屏幕上找到自己:
The Api name is what you will reference in the form input’s name attribute. The display name is for your reference, and you can specify whether you want to store your custom field’s value on Braintree with your transaction, or simply pass it back to your server.
Api名称是您将在表单输入的name属性中引用的名称。 显示名称仅供参考,您可以指定是将自定义字段的值与事务一起存储在Braintree上,还是直接将其传递回服务器。
Collecting it is then simply a matter of adding the following field to your form.
然后,只需将以下字段添加到表单中即可收集它。
<label>Customer Favorite Color: <input type="text" name="transaction[custom_fields][color]"></label>
If you tried to do that without adding the custom field in the Braintree Control panel, you would trigger a validation error.
如果尝试执行此操作而未在Braintree Control面板中添加自定义字段,则会触发验证错误。
Speaking of validation, TR can complicate server-side validation of your payment form. Let’s say I wanted to require my customer’s email address. I wouldn’t know that the user had left it blank until after the transaction had already been confirmed. The solution I have found is to run my validation in the success
block of my TR script, and then void the transaction if my validations don’t pass. So that would alter our code like this:
说到验证,TR可以使您的付款表单的服务器端验证复杂化。 假设我想要求客户的电子邮件地址。 我不知道用户将其留为空白,直到确认交易之后。 我发现的解决方案是在TR脚本的success
块中运行验证,然后在验证未通过的情况下使事务无效。 这样会改变我们的代码,如下所示:
if ($result->success) {
// transaction was successful, but email is missing
if ($result->transaction->customer['email'] == '') {
Braintree_Transaction::void($result->transaction->id);
$status = 'Email address is a required field';
} else {
$status = 'Your transaction was processed succesfully.';
}
}
As you can see, if my local validations don’t pass, I use the client library to void the transaction, using the transaction id from my Braintree_Result_Success
object.
如您所见,如果我的本地验证未通过,我将使用客户库通过Braintree_Result_Success
对象中的事务ID来使事务无效。
Finally, in our basic example, I didn’t bother repopulating form fields for the user, because all of our fields contain sensitive credit card data that Braintree hides from our server. But now that we’ve added some customer data, I can pre-fill those less sensitive fields with data from the Braintree result object. You can see the full code in my Github sample, but the trick to understanding what’s going on is to know that the Braintree_Result_Success
object stores the user-submitted form data in its transaction
property, whereas the Braintree_Result_Error
stores it in a params
property. So for instance, the first name variable would found in $result->transaction->customer['firstName']
when the transaction was successful, while a failed transaction would store it in $result->params['transaction']['customer']['firstName']
.
最后,在我们的基本示例中,我没有为用户重新填充表单字段,因为我们所有的字段都包含Braintree从服务器隐藏的敏感信用卡数据。 但是,既然我们已经添加了一些客户数据,就可以用Braintree结果对象中的数据预填充那些不太敏感的字段。 您可以在我的Github示例中看到完整的代码,但了解发生了什么的技巧是知道Braintree_Result_Success
对象将用户提交的表单数据存储在其transaction
属性中,而Braintree_Result_Error
将其存储在params
属性中。 因此,例如,当交易成功时,名字变量将在$result->transaction->customer['firstName']
,而失败的交易会将其存储在$result->params['transaction']['customer']['firstName']
。
结语 (Wrapping Up)
Braintree’s Transparent Redirect is one way to minimize your application’s exposure to sensitive customer data, thereby reducing your PCI Compliance burden, and their PHP Client Library greatly simplifies the process of integration, but it does make it more difficult to collect and validate non payment-related information on the same form as your customer’s credit card information.
Braintree的透明重定向是最大程度地减少应用程序对敏感客户数据的暴露程度,从而减轻PCI合规性负担的一种方法,其PHP客户端库大大简化了集成过程,但确实使收集和验证与支付无关的内容更加困难信息的格式与客户的信用卡信息相同。
Next time, we’ll take a look at their other clever solution: Braintree.js.
下次,我们将看看他们的另一个聪明的解决方案:Braintree.js。
翻译自: https://www.sitepoint.com/transparent-redirects-braintree/
braintree