【发布时间】:2018-12-14 08:02:45
【问题描述】:
我有一个问题,即在将多个网站连接到一个 Stripe 帐户时,确保网站始终为特定网站上的特定客户收取正确的卡(或银行帐户)费用。
- 站点 A - example1.com 通过 API 连接到 Stripe 帐户 1
- 站点 B - example2.com 通过 API 连接到 Stripe 帐户 1
客户 1 使用他们的个人电子邮件帐户在站点 A 上使用信用卡 1(比如他们的名片)购买了一些东西。他们的电子邮件与他们的客户 ID 一起保存,并且他们的来源设置为名片。然后客户 1 到站点 B 并使用信用卡 2(他们的个人卡)在站点 B 上购物,但使用相同的电子邮件地址。
如何在不更新站点 A 使用的默认卡的情况下让站点 B 每次都使用特定卡?
基本上在创建帐户之前,我会检查以确保客户还没有使用该特定电子邮件的帐户。因此,如果在站点 B 上使用与站点 A 相同的电子邮件,则会为两个站点找到相同的客户帐户。 (出于解释目的简化了代码。)
<?php
// namespace statement
// use \Stripe statements
function exists ($email) {
$customers = Customer::all(['email' => $email]);
$count = 0;
if (isset ($customers['data'])) {
$count = count($customers['data']);
}
if ($count == 1) {
$c = current ($customers['data']);
if ($c instanceof Customer) {
return $c->id;
}
}
return false;
}
function create_customer ($email) {
// Try to get the customer id by email.
$cid = exists ($email);
// Customer not found create them.
if (!$cid) {
try {
$c = Customer::create([
'email' => $e->mail,
]);
return $c->id;
} catch(Exception $e) {
return false;
}
}
return $cid;
}
function set_source ($cid, $token) {
try {
// This updates the default card, if I am understanding the documentation correctly.
Customer::update($customer_id, ['source' => $token]);
return true;
} catch(Exception $e) {
_sec_set_error_messages ($e, $sandbox_message);
}
return false;
}
function charge ($cid, $amount) {
try {
// This charges the default card, if I am understanding the documentation correctly.
$charge = Charge::create([
'amount' => $amount,
'currency' => 'usd',
'customer' => $cid
]);
return $charge;
} catch (Exception $e) {
return false;
}
}
// check_my_db_for_customer_id();
// Create customer if not found.
$email = 'personal@example.com';
$cid = create_customer ($email);
if ($cid) {
// save_to_my_db($email, $cid);
set_source ($cid, $token);
charge ($cid, $amount);
}
?>
问题是,在向客户收费时,如何告诉每个站点使用特定的卡?我可以在我的 set_source 函数期间保存一个源,然后在为卡充电时为特定站点使用相同的源吗?
<?php
function set_source ($cid, $token) {
try {
// Need to add a source if one is found, not update the default.
$get_source_id_somehow = Customer::update($customer_id, ['source' => $token]);
return $get_source_id_somehow;
} catch(Exception $e) {
_sec_set_error_messages ($e, $sandbox_message);
}
return false;
}
function charge ($cid, $amount, $src) {
try {
$charge = Charge::create([
'amount' => $amount,
'currency' => 'usd',
'customer' => $cid,
'source' => $src
]);
return $charge;
} catch (Exception $e) {
return false;
}
}
// check_my_db_for_customer_id_and_source_id();
// Create customer if not found.
$email = 'personal@example.com';
$cid = create_customer ($email);
if ($cid) {
// save_to_my_db($email, $cid);
$src = set_source ($cid, $token);
// save_source_id_to_my_db ($src); ????
charge ($cid, $amount, $src);
}
?>
或者是将每个站点连接到自己独立的 Stripe 帐户的唯一方法?谢谢。
编辑 - 附加问题
这也会带来安全风险吗?如果用户 1 在站点 A 上注册,然后用户 2 使用用户 1 的电子邮件在站点 B 上注册,他们肯定需要输入新的付款详细信息,以便在用户 2 注册时不会从用户 1 的卡上扣款。
编辑 2 - 其他想法
似乎需要以某种方式将客户帐户绑定到单个站点或应用程序。我不知道它是否会验证,但可能会在该站点上使用该域(及其用户 ID)标记电子邮件或客户,这样当您搜索匹配的客户时,您只会找到具有匹配电子邮件的客户域(并通过查找用户 ID 确保它尚未被使用)。否则,用户 2 可以使用用户 1 的电子邮件进行注册,并且根据站点的不同,可能允许在不先验证另一个电子邮件的情况下更改他们的电子邮件,在这种情况下,您无法在站点 B 上更新用户 2 的 Stripe 客户帐户不会为站点 A 上的用户 1 搞砸。
这可能会导致您的 Stripe 帐户中出现多次相同的客户电子邮件,但您可以按标签排序以至少找到各个域并查看用户 ID 正在使用哪些域。
现在,如果用户 1 在站点 A 上使用 personal@email.com 注册,它会创建一个带有站点 A 域及其用户 ID 标记的 Stripe 帐户。如果我们不将其与帐户 ID 相关联,则用户 1 可能能够将其站点的电子邮件切换到 somethingnew@email.com(如果 Stripe 未更新),然后如果用户 2 使用personal@email.com 注册在站点 A 上,该帐户现在会找到与 personal@email.com 绑定的 Stripe 帐户,并且两个帐户都将从同一个 Stripe 帐户运行。
在创建新客户之前尝试匹配客户似乎是一个严重的安全漏洞。或者 Stripe 帐户的电子邮件需要与网站保持同步,但仍需要添加额外的标签以防止用户 1 的 Stripe 帐户被劫持。
可能的解决方案 - 谁能确认?
每次有人注册时创建一个新的 Stripe 帐户并将其绑定到网站的域用户 ID 以供将来搜索是我能想到的唯一安全方法。
<?php
$customer = Customer::create([
'email' => 'paying.user.3@example.com',
'metadata' => [
'site' => 'test/',
'uid' => '6'
]
]);
然后您可以像这样搜索...这不是最优雅的方式,因为您失去了对搜索结果进行分页以换取更精细结果的本机方式,因为元数据无法通过 Customer::all() [我知道]。
<?php
$customers = Customer::all(['email' => $email]);
$matches = [];
foreach ($customers['data'] as $c) {
if (
$c->metadata && is_object ($c->metadata) &&
$c->metadata->site && $c->metadata->site == 'test/' &&
$c->metadata->uid && $c->metadata->uid == $uid
) {
$matches[] = $c;
}
}
【问题讨论】:
标签: php security stripe-payments