From 030e99a9b819b4ae7334b2e4a1b0466157cc2c64 Mon Sep 17 00:00:00 2001 From: arunmish Date: Fri, 22 May 2026 23:52:18 +0530 Subject: [PATCH 1/9] ssl verification added for apple pay --- validateApplePayMerchant.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/validateApplePayMerchant.php b/validateApplePayMerchant.php index d8c71bb..e6cf126 100644 --- a/validateApplePayMerchant.php +++ b/validateApplePayMerchant.php @@ -23,11 +23,9 @@ curl_setopt($ch, CURLOPT_POSTFIELDS, $validationPayload); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 300); - // The following two curl SSL options are set to "false" for ease of development/debug purposes only. - // Any code used in production should either remove these lines or set them to the appropriate - // values to properly use secure connections for PCI-DSS compliance. - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //for production, set value to true or 1 - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //for production, set value to 2 + // SSL certificate verification enabled for secure connections and PCI-DSS compliance + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); //verify SSL certificate + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); //verify certificate matches hostname curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); curl_setopt($ch, CURLOPT_SSLCERT, './certs/apple-pay-test-cert.pem'); curl_setopt($ch, CURLOPT_SSLCERTPASSWD, $pemPwd); From edab2beafe0f6c428f93c6166df9bce9d07f1eec Mon Sep 17 00:00:00 2001 From: arunmish Date: Sat, 23 May 2026 01:05:12 +0530 Subject: [PATCH 2/9] ssl verification fixes for application --- createTransactionWithProfile.php | 9 ++++----- getHostedPaymentForm.php | 9 ++++----- getProfiles.php | 9 ++++----- getToken.php | 9 ++++----- transactionCaller.php | 9 ++++----- 5 files changed, 20 insertions(+), 25 deletions(-) diff --git a/createTransactionWithProfile.php b/createTransactionWithProfile.php index b05511d..e36f41a 100644 --- a/createTransactionWithProfile.php +++ b/createTransactionWithProfile.php @@ -43,11 +43,10 @@ curl_setopt($ch, CURLOPT_POSTFIELDS, $transRequestXml->asXML()); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 300); - // The following two curl SSL options are set to "false" for ease of development/debug purposes only. - // Any code used in production should either remove these lines or set them to the appropriate - // values to properly use secure connections for PCI-DSS compliance. - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //for production, set value to true or 1 - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //for production, set value to 2 + // SSL certificate verification enabled for secure connections and PCI-DSS compliance + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); //verify SSL certificate + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); //verify certificate matches hostname + curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); //enforce TLS 1.2 minimum curl_setopt($ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false ); $content = curl_exec($ch); if (FALSE === $content) diff --git a/getHostedPaymentForm.php b/getHostedPaymentForm.php index f40cd7c..de43daa 100644 --- a/getHostedPaymentForm.php +++ b/getHostedPaymentForm.php @@ -79,11 +79,10 @@ curl_setopt($ch, CURLOPT_POSTFIELDS, $xml->asXML()); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 300); - // The following two curl SSL options are set to "false" for ease of development/debug purposes only. - // Any code used in production should either remove these lines or set them to the appropriate - // values to properly use secure connections for PCI-DSS compliance. - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //for production, set value to true or 1 - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //for production, set value to 2 + // SSL certificate verification enabled for secure connections and PCI-DSS compliance + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); //verify SSL certificate + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); //verify certificate matches hostname + curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); //enforce TLS 1.2 minimum curl_setopt($ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false); //curl_setopt($ch, CURLOPT_PROXY, 'userproxy.visa.com:80'); $content = curl_exec($ch); diff --git a/getProfiles.php b/getProfiles.php index f461f2c..6406804 100755 --- a/getProfiles.php +++ b/getProfiles.php @@ -20,11 +20,10 @@ curl_setopt($ch, CURLOPT_POSTFIELDS, $xml->asXML()); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 300); - // The following two curl SSL options are set to "false" for ease of development/debug purposes only. - // Any code used in production should either remove these lines or set them to the appropriate - // values to properly use secure connections for PCI-DSS compliance. - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //for production, set value to true or 1 - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //for production, set value to 2 + // SSL certificate verification enabled for secure connections and PCI-DSS compliance + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); //verify SSL certificate + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); //verify certificate matches hostname + curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); //enforce TLS 1.2 minimum curl_setopt($ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false ); $content = curl_exec($ch); $profileResponse = new SimpleXMLElement($content); diff --git a/getToken.php b/getToken.php index 2684874..a3e2546 100755 --- a/getToken.php +++ b/getToken.php @@ -50,11 +50,10 @@ curl_setopt($ch, CURLOPT_POSTFIELDS, $xml->asXML()); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 300); - // The following two curl SSL options are set to "false" for ease of development/debug purposes only. - // Any code used in production should either remove these lines or set them to the appropriate - // values to properly use secure connections for PCI-DSS compliance. - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //for production, set value to true or 1 - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //for production, set value to 2 + // SSL certificate verification enabled for secure connections and PCI-DSS compliance + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); //verify SSL certificate + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); //verify certificate matches hostname + curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); //enforce TLS 1.2 minimum curl_setopt($ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false); $content = curl_exec($ch); $response = new SimpleXMLElement($content); diff --git a/transactionCaller.php b/transactionCaller.php index e4938a1..de4ee77 100644 --- a/transactionCaller.php +++ b/transactionCaller.php @@ -55,11 +55,10 @@ curl_setopt($ch, CURLOPT_POSTFIELDS, $transRequestXml->asXML()); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 300); - // The following two curl SSL options are set to "false" for ease of development/debug purposes only. - // Any code used in production should either remove these lines or set them to the appropriate - // values to properly use secure connections for PCI-DSS compliance. - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //for production, set value to true or 1 - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //for production, set value to 2 + // SSL certificate verification enabled for secure connections and PCI-DSS compliance + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); //verify SSL certificate + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); //verify certificate matches hostname + curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); //enforce TLS 1.2 minimum curl_setopt($ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false ); $content = curl_exec($ch); if (FALSE === $content) From 28d106e7a2aa6026a8d51fcef7eecfd634ea6bc0 Mon Sep 17 00:00:00 2001 From: arunmish Date: Sat, 23 May 2026 01:47:17 +0530 Subject: [PATCH 3/9] session authentication fixes --- index.php | 8 ++++++++ login.php | 27 +++++++++++++++++++++------ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/index.php b/index.php index c961c0e..f6e0868 100755 --- a/index.php +++ b/index.php @@ -1,5 +1,13 @@ messages->resultCode != "Ok") { diff --git a/login.php b/login.php index 3d137da..8802405 100644 --- a/login.php +++ b/login.php @@ -1,20 +1,35 @@ @@ -78,4 +93,4 @@ - \ No newline at end of file + From 8b52cd31808f42ce3ba603c4dd97390ff5c2ae21 Mon Sep 17 00:00:00 2001 From: arunmish Date: Sat, 23 May 2026 17:45:33 +0530 Subject: [PATCH 4/9] addition of authentication and csrf --- chargeProfile.js | 117 ++++++++++++++++--------------- createTransactionWithProfile.php | 28 ++++++++ index.php | 6 ++ 3 files changed, 93 insertions(+), 58 deletions(-) diff --git a/chargeProfile.js b/chargeProfile.js index cee3665..da1b875 100644 --- a/chargeProfile.js +++ b/chargeProfile.js @@ -1,17 +1,19 @@ -function showResult(msg) -{ - try{ - responseObj=JSON.parse(msg); - if(responseObj.transactionResponse.responseCode=='1'){ - message="Transaction Successful!
Transaction ID: "+responseObj.transactionResponse.transId; - } - else{ - message="Transaction Unsuccessful.";//+responseObj.messages.message[0].text; - if(responseObj.transactionResponse.errors!=null)//to do: take care of errors[1] array being parsed into single object - { - message+=responseObj.transactionResponse.errors.error.errorText; - } - /*else if(responseObj.transactionResponse.errors[0]!=null) +function showResult(msg) { + try { + responseObj = JSON.parse(msg); + if (responseObj.transactionResponse.responseCode == "1") { + message = + "Transaction Successful!
Transaction ID: " + + responseObj.transactionResponse.transId; + } else { + message = "Transaction Unsuccessful."; //+responseObj.messages.message[0].text; + if ( + responseObj.transactionResponse.errors != null + ) //to do: take care of errors[1] array being parsed into single object + { + message += responseObj.transactionResponse.errors.error.errorText; + } + /*else if(responseObj.transactionResponse.errors[0]!=null) { for(i=0;iACCEPT.JS EXAMPLE"); - $('#acceptJSReceiptBody').html(message); - //jQuery.noConflict(); - $('#acceptJSReceiptModal').modal('show'); -} + if (responseObj.transactionResponse.transId != null) { + message += "
"; + message += "Transaction ID: " + responseObj.transactionResponse.transId; + } + } + } catch (error) { + console.log("Couldn't parse result string"); + message = "Error."; + } -function createProfileTransaction() { - - $.ajax({ - - url: "createTransactionWithProfile.php", - // These profiles IDs would NOT BE HARDCODED of course but rather taken from the logged in user - data: {amount: Math.floor((Math.random() * 100) + 1), customerProfileId: "1808251712", paymentProfileId: "1803116214"}, - method: 'POST', - timeout: 5000 - - }).done(function(data){ - - console.log('Success'); - - }).fail(function(){ - - console.log('Error'); - - }).always(function(textStatus){ - - console.log(textStatus); - showResult(textStatus); - - }) - + //alert(message); + + $("#acceptJSReceiptHeader").html( + "", + ); + $("#acceptJSReceiptBody").html(message); + //jQuery.noConflict(); + $("#acceptJSReceiptModal").modal("show"); } +function createProfileTransaction() { + // Security: Get CSRF token from hidden input + var csrfToken = $("#csrfToken").val(); + $.ajax({ + url: "createTransactionWithProfile.php", + // These profiles IDs would NOT BE HARDCODED of course but rather taken from the logged in user + data: { + amount: Math.floor(Math.random() * 100 + 1), + customerProfileId: "1808251712", + paymentProfileId: "1803116214", + csrf_token: csrfToken, // Security: Include CSRF token + }, + method: "POST", + timeout: 5000, + }) + .done(function (data) { + console.log("Success"); + }) + .fail(function () { + console.log("Error"); + }) + .always(function (textStatus) { + console.log(textStatus); + showResult(textStatus); + }); +} diff --git a/createTransactionWithProfile.php b/createTransactionWithProfile.php index e36f41a..bf5ddfe 100644 --- a/createTransactionWithProfile.php +++ b/createTransactionWithProfile.php @@ -1,4 +1,32 @@ 'Unauthorized', 'message' => 'Authentication required']); + exit; +} + +// Security: Validate that authenticated user owns the profile +$authenticatedCustomerId = $_SESSION['authenticated_cpid']; +$requestedCustomerId = $_POST['customerProfileId']; + +if($authenticatedCustomerId !== $requestedCustomerId){ + http_response_code(403); + header('Content-Type: application/json'); + echo json_encode(['error' => 'Forbidden', 'message' => 'You do not have permission to use this profile']); + exit; +} + +// Security: Validate CSRF token +if(!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']){ + http_response_code(403); + header('Content-Type: application/json'); + echo json_encode(['error' => 'Forbidden', 'message' => 'Invalid CSRF token']); + exit; +} $transRequestXmlStr=<< diff --git a/index.php b/index.php index f6e0868..1b29d26 100755 --- a/index.php +++ b/index.php @@ -8,6 +8,11 @@ exit; } + // Security: Generate CSRF token for form submissions + if(!isset($_SESSION['csrf_token'])){ + $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); + } + include 'getToken.php'; include 'generateCardinalJWT.php'; if ($response->messages->resultCode != "Ok") { @@ -414,6 +419,7 @@ function onVisaCheckoutReady() { + '>
From 89f201637493fda2bf1369f3af30ba7fcf6550b7 Mon Sep 17 00:00:00 2001 From: arunmish Date: Sat, 23 May 2026 17:52:29 +0530 Subject: [PATCH 5/9] addition of authentication and csrf for payments --- acceptJSCaller.js | 192 +++++++++++----------- applePayCaller.js | 258 +++++++++++++++--------------- payerAuthCaller.js | 319 ++++++++++++++++++++----------------- transactionCaller.php | 26 +++ visaCheckoutTransaction.js | 121 +++++++------- 5 files changed, 492 insertions(+), 424 deletions(-) diff --git a/acceptJSCaller.js b/acceptJSCaller.js index 22febb0..cc5eb90 100644 --- a/acceptJSCaller.js +++ b/acceptJSCaller.js @@ -1,18 +1,20 @@ // The result of the transaction processing will be returned from the processing script as a JSON object. Parse the object to determine success or failure, and alert the user. -function messageFunc(msg) -{ - try{ - responseObj=JSON.parse(msg); - if(responseObj.transactionResponse.responseCode=='1'){ - message="Transaction Successful!
Transaction ID: "+responseObj.transactionResponse.transId; - } - else{ - message="Transaction Unsuccessful.";//+responseObj.messages.message[0].text; - if(responseObj.transactionResponse.errors!=null)//to do: take care of errors[1] array being parsed into single object - { - message+=responseObj.transactionResponse.errors.error.errorText; - } - /*else if(responseObj.transactionResponse.errors[0]!=null) +function messageFunc(msg) { + try { + responseObj = JSON.parse(msg); + if (responseObj.transactionResponse.responseCode == "1") { + message = + "Transaction Successful!
Transaction ID: " + + responseObj.transactionResponse.transId; + } else { + message = "Transaction Unsuccessful."; //+responseObj.messages.message[0].text; + if ( + responseObj.transactionResponse.errors != null + ) //to do: take care of errors[1] array being parsed into single object + { + message += responseObj.transactionResponse.errors.error.errorText; + } + /*else if(responseObj.transactionResponse.errors[0]!=null) { for(i=0;i