Skip to content

Commit

Permalink
Merge pull request #17 from xendit/TPI-2484/callback-vulnerability
Browse files Browse the repository at this point in the history
fix callback vulnerability
  • Loading branch information
IreneGohtami authored Dec 10, 2020
2 parents 8bfea05 + cf6981d commit 89b1364
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 133 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# CHANGELOG

## 2020-12-10
- Improve callback endpoint security to check order number from source of truth

## 2020-07-02
- Refactor xendit_order table for all versions
- Ensure all Xendit orders are recorded in DB
65 changes: 34 additions & 31 deletions opencart1.5.x/upload/catalog/controller/payment/xendit.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,38 +79,17 @@ public function process_notification() {
$this->load->model('payment/xendit');
$this->load->model('checkout/order');

$original_response = json_decode(file_get_contents('php://input'), true);
$invoice_id = $original_response['id'];
$external_id = $original_response['external_id'];
$order_id = preg_replace('/[^0-9]/', '', $external_id);
$order_info = $this->model_checkout_order->getOrder($order_id);

if (empty($order_info)) {
$message = 'Order not found. Order id: ' . $order_id . '.';
$this->response->addHeader('HTTP/1.1 404 Not Found');
$this->response->setOutput($message);
return;
}

$order_status_id = $order_info['order_status_id'];

$api_key = $this->get_api_key();
Xendit::set_secret_key($api_key['secret_key']);
$store_name = $this->config->get('config_name');
$request_url = '/payment/xendit/invoice/' . $invoice_id;
$request_options = array(
'store_name' => $store_name
);

// if status is not pending
if ($order_status_id != 1) {
$message = 'Order status is not pending. Order id: ' . $order_id . '.';
$this->response->addHeader('HTTP/1.1 422 Unprocessable Entity');
$this->response->setOutput($message);
return;
}

try {
$original_response = json_decode(file_get_contents('php://input'), true);
$invoice_id = $original_response['id'];

$api_key = $this->get_api_key();
Xendit::set_secret_key($api_key['secret_key']);
$store_name = $this->config->get('config_name');
$request_url = '/payment/xendit/invoice/' . $invoice_id;
$request_options = array(
'store_name' => $store_name
);
$response = Xendit::request($request_url, Xendit::METHOD_GET, array(), $request_options);

if ( isset($response['error_code']) ) {
Expand All @@ -120,6 +99,30 @@ public function process_notification() {
return;
}

$external_id = $response['external_id'];
$order_id = preg_replace('/[^0-9]/', '', $external_id);
$order_info = $this->model_checkout_order->getOrder($order_id);

if (empty($order_info)) {
$message = 'Order not found. Order id: ' . $order_id . '.';
$this->response->addHeader('HTTP/1.1 404 Not Found');
$this->response->setOutput($message);
return;
}

$order_status_id = $order_info['order_status_id'];


// if status is not pending
if ($order_status_id != 1) {
$message = 'Order status is not pending. Order id: ' . $order_id . '.';
$this->response->addHeader('HTTP/1.1 422 Unprocessable Entity');
$this->response->setOutput($message);
return;
}



return $this->process_order($response, $original_response, $order_id);
} catch (Exception $e) {
echo 'something';
Expand Down
74 changes: 38 additions & 36 deletions opencart2.0.x-2.2.x/upload/catalog/controller/payment/xendit.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,53 +88,55 @@ public function process_notification()
$this->load->model('payment/xendit');
$this->load->model('checkout/order');

$original_response = json_decode(file_get_contents('php://input'), true);
$invoice_id = $original_response['id'];
$external_id = $original_response['external_id'];
$order_id = str_replace(self::EXT_ID_PREFIX, "", $external_id);

if (!is_numeric($order_id)) {
$explodExternalId = explode( '-', $external_id );
$order_id = end($explodExternalId);
}
try {
$original_response = json_decode(file_get_contents('php://input'), true);
$invoice_id = $original_response['id'];

$api_key = $this->get_api_key();
Xendit::set_secret_key($api_key['secret_key']);
$store_name = $this->config->get('config_name');
$request_url = '/payment/xendit/invoice/' . $invoice_id;
$request_options = array(
'store_name' => $store_name
);
$response = Xendit::request($request_url, Xendit::METHOD_GET, array(), $request_options);

if (isset($response['error_code'])) {
$message = 'Could not get xendit invoice. Invoice id: ' . $invoice_id . '. Cancelling order.';
$this->response->addHeader('HTTP/1.1 400 Bad Request');
$this->response->setOutput($message);
return;
}

$order_info = $this->model_checkout_order->getOrder($order_id);
$external_id = $response['external_id'];
$order_id = str_replace(self::EXT_ID_PREFIX, "", $external_id);

if (empty($order_info)) {
$message = 'Order not found. Order id: ' . $order_id . '.';
$this->response->addHeader('HTTP/1.1 404 Not Found');
$this->response->setOutput($message);
return;
}
if (!is_numeric($order_id)) {
$explodExternalId = explode( '-', $external_id );
$order_id = end($explodExternalId);
}

$order_status_id = $order_info['order_status_id'];
$order_info = $this->model_checkout_order->getOrder($order_id);

$api_key = $this->get_api_key();
Xendit::set_secret_key($api_key['secret_key']);
$store_name = $this->config->get('config_name');
$request_url = '/payment/xendit/invoice/' . $invoice_id;
$request_options = array(
'store_name' => $store_name
);
if (empty($order_info)) {
$message = 'Order not found. Order id: ' . $order_id . '.';
$this->response->addHeader('HTTP/1.1 404 Not Found');
$this->response->setOutput($message);
return;
}

// if status is not pending
if ($order_status_id != 1) {
$message = 'Order status is not pending. Order id: ' . $order_id . '.';
$this->response->addHeader('HTTP/1.1 422 Unprocessable Entity');
$this->response->setOutput($message);
return;
}
$order_status_id = $order_info['order_status_id'];

try {
$response = Xendit::request($request_url, Xendit::METHOD_GET, array(), $request_options);

if (isset($response['error_code'])) {
$message = 'Could not get xendit invoice. Invoice id: ' . $invoice_id . '. Cancelling order.';
$this->response->addHeader('HTTP/1.1 400 Bad Request');
// if status is not pending
if ($order_status_id != 1) {
$message = 'Order status is not pending. Order id: ' . $order_id . '.';
$this->response->addHeader('HTTP/1.1 422 Unprocessable Entity');
$this->response->setOutput($message);
return;
}


return $this->process_order($response, $original_response, $order_id);
} catch (Exception $e) {
echo 'something';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,48 +78,48 @@ public function process_notification() {
$this->load->model('extension/payment/xendit');
$this->load->model('checkout/order');

$original_response = json_decode(file_get_contents('php://input'), true);
$invoice_id = $original_response['id'];
$external_id = $original_response['external_id'];
$order_id = str_replace(self::EXT_ID_PREFIX, "", $external_id);

if (!is_numeric($order_id)) {
$order_id = end(explode( '-', $external_id ));
}
try {
$original_response = json_decode(file_get_contents('php://input'), true);
$invoice_id = $original_response['id'];

$api_key = $this->get_api_key();
Xendit::set_secret_key($api_key['secret_key']);
$store_name = $this->config->get('config_name');
$request_url = '/payment/xendit/invoice/' . $invoice_id;
$request_options = array(
'store_name' => $store_name
);
$response = Xendit::request($request_url, Xendit::METHOD_GET, array(), $request_options);

$order_info = $this->model_checkout_order->getOrder($order_id);
if ( isset($response['error_code']) ) {
$message = 'Could not get xendit invoice. Invoice id: ' . $invoice_id . '. Cancelling order.';
$this->response->addHeader('HTTP/1.1 400 Bad Request');
$this->response->setOutput($message);
return;
}

if (empty($order_info)) {
$message = 'Order not found. Order id: ' . $order_id . '.';
$this->response->addHeader('HTTP/1.1 404 Not Found');
$this->response->setOutput($message);
return;
}
$external_id = $response['external_id'];
$order_id = str_replace(self::EXT_ID_PREFIX, "", $external_id);

$order_status_id = $order_info['order_status_id'];
if (!is_numeric($order_id)) {
$order_id = end(explode( '-', $external_id ));
}

$api_key = $this->get_api_key();
Xendit::set_secret_key($api_key['secret_key']);
$store_name = $this->config->get('config_name');
$request_url = '/payment/xendit/invoice/' . $invoice_id;
$request_options = array(
'store_name' => $store_name
);
$order_info = $this->model_checkout_order->getOrder($order_id);

// if status is not pending
if ($order_status_id != 1) {
$message = 'Order status is not pending. Order id: ' . $order_id . '.';
$this->response->addHeader('HTTP/1.1 422 Unprocessable Entity');
$this->response->setOutput($message);
return;
}
if (empty($order_info)) {
$message = 'Order not found. Order id: ' . $order_id . '.';
$this->response->addHeader('HTTP/1.1 404 Not Found');
$this->response->setOutput($message);
return;
}

try {
$response = Xendit::request($request_url, Xendit::METHOD_GET, array(), $request_options);
$order_status_id = $order_info['order_status_id'];

if ( isset($response['error_code']) ) {
$message = 'Could not get xendit invoice. Invoice id: ' . $invoice_id . '. Cancelling order.';
$this->response->addHeader('HTTP/1.1 400 Bad Request');
// if status is not pending
if ($order_status_id != 1) {
$message = 'Order status is not pending. Order id: ' . $order_id . '.';
$this->response->addHeader('HTTP/1.1 422 Unprocessable Entity');
$this->response->setOutput($message);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,38 +78,17 @@ public function process_notification() {
$this->load->model('extension/payment/xendit');
$this->load->model('checkout/order');

$original_response = json_decode(file_get_contents('php://input'), true);
$invoice_id = $original_response['id'];
$external_id = $original_response['external_id'];
$order_id = preg_replace('/[^0-9]/', '', $external_id);
$order_info = $this->model_checkout_order->getOrder($order_id);

if (empty($order_info)) {
$message = 'Order not found. Order id: ' . $order_id . '.';
$this->response->addHeader('HTTP/1.1 404 Not Found');
$this->response->setOutput($message);
return;
}

$order_status_id = $order_info['order_status_id'];

$api_key = $this->get_api_key();
Xendit::set_secret_key($api_key['secret_key']);
$store_name = $this->config->get('config_name');
$request_url = '/payment/xendit/invoice/' . $invoice_id;
$request_options = array(
'store_name' => $store_name
);

// if status is not pending
if ($order_status_id != 1) {
$message = 'Order status is not pending. Order id: ' . $order_id . '.';
$this->response->addHeader('HTTP/1.1 422 Unprocessable Entity');
$this->response->setOutput($message);
return;
}

try {
$original_response = json_decode(file_get_contents('php://input'), true);
$invoice_id = $original_response['id'];

$api_key = $this->get_api_key();
Xendit::set_secret_key($api_key['secret_key']);
$store_name = $this->config->get('config_name');
$request_url = '/payment/xendit/invoice/' . $invoice_id;
$request_options = array(
'store_name' => $store_name
);
$response = Xendit::request($request_url, Xendit::METHOD_GET, array(), $request_options);

if ( isset($response['error_code']) ) {
Expand All @@ -119,6 +98,27 @@ public function process_notification() {
return;
}

$external_id = $response['external_id'];
$order_id = preg_replace('/[^0-9]/', '', $external_id);
$order_info = $this->model_checkout_order->getOrder($order_id);

if (empty($order_info)) {
$message = 'Order not found. Order id: ' . $order_id . '.';
$this->response->addHeader('HTTP/1.1 404 Not Found');
$this->response->setOutput($message);
return;
}

$order_status_id = $order_info['order_status_id'];

// if status is not pending
if ($order_status_id != 1) {
$message = 'Order status is not pending. Order id: ' . $order_id . '.';
$this->response->addHeader('HTTP/1.1 422 Unprocessable Entity');
$this->response->setOutput($message);
return;
}

return $this->process_order($response, $original_response, $order_id);
} catch (Exception $e) {
echo 'something';
Expand Down

0 comments on commit 89b1364

Please sign in to comment.