1.[2022-03-07]cvv/cvc除了amex是4,其余都按3位处理
2.[2022-03-07]cardbin验证规则
nf.cards.push({cardType:"mc",startingRules:[51,52,53,54,55,22,23,24,25,26,27],permittedLengths:[16],pattern:/^(5[1-5][0-9]{0,14}|2[2-7][0-9]{0,14})$/,securityCode:"CVC"}),
nf.cards.push({cardType:"visadankort",startingRules:[4571],permittedLengths:[16],pattern:/^(4571)[0-9]{0,12}$/}),
nf.cards.push({cardType:"visa",startingRules:[4],permittedLengths:[13,16,19],pattern:/^4[0-9]{0,18}$/,securityCode:"CVV"}),
nf.cards.push({cardType:"amex",startingRules:[34,37],permittedLengths:[15],pattern:/^3[47][0-9]{0,13}$/,securityCode:"CID"}),
nf.cards.push({cardType:"diners",startingRules:[36],permittedLengths:[14],pattern:/^(36)[0-9]{0,12}$/}),
nf.cards.push({cardType:"maestrouk",startingRules:[6759],permittedLengths:[16,18,19],pattern:/^(6759)[0-9]{0,15}$/}),
nf.cards.push({cardType:"solo",startingRules:[6767],permittedLengths:[16,18,19],pattern:/^(6767)[0-9]{0,15}$/}),
nf.cards.push({cardType:"laser",startingRules:[6304,6706,677117,677120],permittedLengths:[16,17,18,19],pattern:/^(6304|6706|6709|6771)[0-9]{0,15}$/,cvcPolicy:"optional"}),
nf.cards.push({cardType:"discover",startingRules:[6011,644,645,646,647,648,649,65],permittedLengths:[16],pattern:/^(6011[0-9]{0,12}|(644|645|646|647|648|649)[0-9]{0,13}|65[0-9]{0,14})$/}),
nf.cards.push({cardType:"jcb",startingRules:[3528,3529,353,354,355,356,357,358],permittedLengths:[16,19],pattern:/^(352[8,9]{1}[0-9]{0,15}|35[4-8]{1}[0-9]{0,16})$/,securityCode:"CAV"}),
nf.cards.push({cardType:"bcmc",startingRules:[6703,479658,606005],permittedLengths:[16,17,18,19],pattern:/^((6703)[0-9]{0,15}|(479658|606005)[0-9]{0,13})$/,cvcPolicy:"hidden"}),
nf.cards.push({cardType:"bijcard",startingRules:[5100081],permittedLengths:[16],pattern:/^(5100081)[0-9]{0,9}$/}),
nf.cards.push({cardType:"dankort",startingRules:[5019],permittedLengths:[16],pattern:/^(5019)[0-9]{0,12}$/}),
nf.cards.push({cardType:"hipercard",startingRules:[606282],permittedLengths:[16],pattern:/^(606282)[0-9]{0,10}$/}),
nf.cards.push({cardType:"cup",startingRules:[62,81],permittedLengths:[14,15,16,17,18,19],pattern:/^(62|81)[0-9]{0,17}$/}),
nf.cards.push({cardType:"maestro",startingRules:[50,56,57,58,6],permittedLengths:[16,17,18,19],pattern:/^(5[0|6-8][0-9]{0,17}|6[0-9]{0,18})$/,cvcPolicy:"optional"}),
nf.cards.push({cardType:"elo",startingRules:[506699,50670,50671,50672,50673,50674,50675,50676,506770,506771,506772,506773,506774,506775,506776,506777,506778,401178,438935,451416,457631,457632,504175,627780,636297,636368],permittedLengths:[16],pattern:/^((((506699)|(506770)|(506771)|(506772)|(506773)|(506774)|(506775)|(506776)|(506777)|(506778)|(401178)|(438935)|(451416)|(457631)|(457632)|(504175)|(627780)|(636368)|(636297))[0-9]{0,10})|((50676)|(50675)|(50674)|(50673)|(50672)|(50671)|(50670))[0-9]{0,11})$/}),
nf.cards.push({cardType:"uatp",startingRules:[1],permittedLengths:[15],pattern:/^1[0-9]{0,14}$/,cvcPolicy:"optional"}),
nf.cards.push({cardType:"cartebancaire",startingRules:[4,5,6],permittedLengths:[16],pattern:/^[4-6][0-9]{0,15}$/}),
nf.cards.push({cardType:"visaalphabankbonus",startingRules:[450903],permittedLengths:[16],pattern:/^(450903)[0-9]{0,10}$/}),
nf.cards.push({cardType:"mcalphabankbonus",startingRules:[510099],permittedLengths:[16],pattern:/^(510099)[0-9]{0,10}$/}),
nf.cards.push({cardType:"hiper",startingRules:[637095,637568,637599,637609,637612],permittedLengths:[16],pattern:/^(637095|637568|637599|637609|637612)[0-9]{0,10}$/}),
nf.cards.push({cardType:"oasis",startingRules:[982616],permittedLengths:[16],pattern:/^(982616)[0-9]{0,10}$/,cvcPolicy:"optional"}),
nf.cards.push({cardType:"karenmillen",startingRules:[98261465],permittedLengths:[16],pattern:/^(98261465)[0-9]{0,8}$/,cvcPolicy:"optional"}),
nf.cards.push({cardType:"warehouse",startingRules:[982633],permittedLengths:[16],pattern:/^(982633)[0-9]{0,10}$/,cvcPolicy:"optional"}),
nf.cards.push({cardType:"mir",startingRules:[220],permittedLengths:[16,17,18,19],pattern:/^(220)[0-9]{0,16}$/}),
nf.cards.push({cardType:"codensa",startingRules:[590712],permittedLengths:[16],pattern:/^(590712)[0-9]{0,10}$/}),
nf.cards.push({cardType:"naranja",startingRules:[377798,377799,402917,402918,527571,527572,589562],permittedLengths:[16,17,18,19],pattern:/^(37|40|5[28])([279])\d$/}),
nf.cards.push({cardType:"cabal",startingRules:[589657,600691,603522,6042,6043,636908],permittedLengths:[16,17,18,19],pattern:/^(58|6[03])([03469])\d$/}),
nf.cards.push({cardType:"shopping",startingRules:[2799,589407,603488],permittedLengths:[16,17,18,19],pattern:/^(27|58|60)([39])\d$/}),
nf.cards.push({cardType:"argencard",startingRules:[501],permittedLengths:[16,17,18,19],pattern:/^(50)(1)\d$/}),
nf.cards.push({cardType:"troy",startingRules:[9792],permittedLengths:[16],pattern:/^(97)(9)\d$/}),
nf.cards.push({cardType:"forbrugsforeningen",startingRules:[600722],permittedLengths:[16],pattern:/^(60)(0)\d$/}),
nf.cards.push({cardType:"vpay",startingRules:[401,408,413,434,435,437,439,441,442,443,444,446,447,455,458,460,461,463,466,471,479,482,483,487],permittedLengths:[13,14,15,16,17,18,19],pattern:/^(40[1,8]|413|43[4,5]|44[1,2,3,4,6,7]|45[5,8]|46[0,1,3,6]|47[1,9]|48[2,3,7])[0-9]{0,16}$/}),
nf.cards.push({cardType:"rupay",startingRules:[508528],permittedLengths:[16],pattern:/^(100003|508(2|[5-9])|60(69|[7-8])|652(1[5-9]|[2-5][0-9]|8[5-9])|65300[3-4]|8172([0-1]|[3-5]|7|9)|817(3[3-8]|40[6-9]|410)|35380([0-2]|[5-6]|9))[0-9]{0,12}$/})
cardType 卡组
startingRules 卡号开头匹配
permittedLengths 总长度
pattern 完整卡号正则
securityCode:"CVV"
securityCode:"CID"
securityCode:"CVC"
securityCode:"CAV"
这些只是对cvv的不同叫法而已
3.[2022-03-07]建议:
传输:用户输入的信息要加密后(eg:RSA)在传输.
存储:
cvc/cvv不可以持久化存储, 也不可以写日志,
完整卡号不持久化存储(除非有特殊需求在做pci的时候就要完整保存,有单独的整改项),不写日志
前6后4可以持久化存储,可以写日志
日期:可以加密持久化存储,不写日志
持卡人姓名:可以加密持久化存储,不写日志
4.[2022-03-16].双标卡的话,可以做成让用户选择走哪个卡组,如果简化的话那就自己写逻辑选择走哪个卡组[见第五条]
效果大致
5.[2022-03-16]双标卡的话可能会出现一个卡多个卡组,如果涉及支付路由的话要自己考虑这种情况然后按照自己的偏好来选择走哪个卡组的路由
6.[2022-03-26]3ds的适配页面可以通过challenge的一个参数来指定
const cReqData = {threeDSServerTransID : pResp.additionalData['threeDSServerTransID'],
acsTransID : pResp.additionalData['acsTransID'],
messageVersion : pResp.additionalData['.messageVersion'],
challengeWindowSize : '05',
messageType : 'CReq'
}
identifier size
01 250px x 400px
02 390px x 400px
03 500px x 600px
04 600px x 400px
05 100% x 100%
7.[2022-03-26]如果一个卡号可以同时命中多个规则,可以调用接口/cardBinDetails来确定是哪个卡组,如果还是能拿到多个卡组信息就说明是双标卡,可以按双标卡的逻辑走
即使luhncheck检查过了只要cardBinDetails查询不到或者报错
{"status":422,"errorCode":"193","message":"Bin Details not found for the given card number","errorType":"validation"}
可以认为当前卡不支持则不需要在继续了
8.[2022-04-17]使用adyen token 绑的卡如果过期了,绑定关系不会自动解除,会返回卡过期的报错,如果要自动更新过期时间可以参考这2个产品
1.account updater: https://docs.adyen.com/online-payments/account-updater
2.network token:https://docs.adyen.com/online-payments/network-tokenization
adyentoken都是有network_token对应的.如果银行不支持network_ token的话那么adyen_token也是与明文卡号关联的
理论上绑卡的3ds只会在第一次绑卡时才会需要验证信息后续的绑卡交易都不需要3ds验证了
9.[2022-04-17]3ds相关
3ds2
https://docs.adyen.com/checkout-build-your-own-3ds2
3ds1
https://docs.adyen.com/online-payments/3d-secure/redirect-3ds2-3ds1
https://docs.adyen.com/online-payments/api-only/handling-redirects
自己实现3ds接入的方式
1.web形式的3ds,适用于web与app
要实现web形式的3ds是需要一个中间页来处理3ds第二步第三步的交互
2.app based
需要拿到EMVCO的证书
参考https://www.emvco.com/processes-forms/certification/