diff --git a/common/models/shipping/Dhlexpress.php b/common/models/shipping/Dhlexpress.php index 2b807f220..301921687 100644 --- a/common/models/shipping/Dhlexpress.php +++ b/common/models/shipping/Dhlexpress.php @@ -97,14 +97,20 @@ public function getQuote($address) { $pieces = ShippingHelper::get_package_piece($dhl_packs); $weight_unit = 'KG'; $dim_unit = 'CM'; - $fetch_accountrates = ($rate_type == 'ACCOUNT') ? "" . $dhlexpress_account . "" : ""; + $fetch_accountrates = ($rate_type == 'ACCOUNT') ? "" . $this->escapeXmlValue($dhlexpress_account) . "" : ""; $mailing_date = date('Y-m-d'); $mailing_datetime = date('c'); - $origin_postcode_city = ShippingHelper::get_postcode_city($fromCountryCode, $fromCity, $fromPostcode); + $origin_postcode_city = ShippingHelper::get_postcode_city( + $fromCountryCode, + $this->escapeXmlValue($fromCity), + $this->escapeXmlValue($fromPostcode) + ); //$total_value = $this->cart->get_total(); - $dutiable_content = ($is_dutiable == "Y") ? "{$selected_currency}{$total_value}" : ""; + $declared_currency = $this->escapeXmlValue($selected_currency); + $declared_value = $this->escapeXmlValue($total_value); + $dutiable_content = ($is_dutiable == "Y") ? "{$declared_currency}{$declared_value}" : ""; //$insurance_details = ($this->config->get('shipping_dhlexpress_insurance') == true) ? "". $total_value ."". $this->config->get('config_currency') ."" : ""; //$additional_insurance_details = ($this->config->get('shipping_dhlexpress_insurance') == true) ? "IIXCH" : ""; // @@ -130,7 +136,11 @@ public function getQuote($address) { } }*/ - $destination_postcode_city = ShippingHelper::get_postcode_city($county_code_to, $to_city, $postcode); + $destination_postcode_city = ShippingHelper::get_postcode_city( + $county_code_to, + $this->escapeXmlValue($to_city), + $this->escapeXmlValue($postcode) + ); $payment_country = $county_code_to;// $this->config->get('shipping_dhlexpress_country_code'); /*if ( !empty($this->config->get('shipping_dhlexpress_pay_con')) && $this->config->get('shipping_dhlexpress_pay_con') == "R" ) { @@ -149,31 +159,31 @@ public function getQuote($address) { $xml .= ' '; $xml .= ' '.$mailing_datetime.''; $xml .= ' 1234567890123456789012345678901'; - $xml .= ' '.$dhlexpress_key.''; - $xml .= ' '.$dhlexpress_password.''; + $xml .= ' '.$this->escapeXmlValue($dhlexpress_key).''; + $xml .= ' '.$this->escapeXmlValue($dhlexpress_password).''; $xml .= ' '; $xml .= ' '; $xml .= ' '; - $xml .= ' '.$fromCountryCode.''; + $xml .= ' '.$this->escapeXmlValue($fromCountryCode).''; $xml .= ' '.$origin_postcode_city; $xml .= ' '; $xml .= ' '; - $xml .= ' '.$payment_country.''; + $xml .= ' '.$this->escapeXmlValue($payment_country).''; $xml .= ' '.$mailing_date.''; $xml .= ' PT10H21M'; - $xml .= ' '.$dim_unit.''; - $xml .= ' '.$weight_unit.''; + $xml .= ' '.$this->escapeXmlValue($dim_unit).''; + $xml .= ' '.$this->escapeXmlValue($weight_unit).''; $xml .= ' '; $xml .= ' '.$pieces; $xml .= ' '; $xml .= ' '.$fetch_accountrates; - $xml .= ' '.$is_dutiable.''; + $xml .= ' '.$this->escapeXmlValue($is_dutiable).''; $xml .= ' AL'; //$xml .= ' '.$additional_insurance_details; //$xml .= ' '.$insurance_details; $xml .= ' '; $xml .= ' '; - $xml .= ' '.$county_code_to.''; + $xml .= ' '.$this->escapeXmlValue($county_code_to).''; $xml .= ' '.$destination_postcode_city; $xml .= ' '; $xml .= ' '.$dutiable_content; @@ -261,4 +271,9 @@ public function getQuote($address) { } return $method_data; } -} \ No newline at end of file + + private function escapeXmlValue($value) + { + return htmlspecialchars((string) $value, ENT_XML1 | ENT_QUOTES, 'UTF-8'); + } +} diff --git a/tests/check-dhl-rate-xml-escaping.py b/tests/check-dhl-rate-xml-escaping.py new file mode 100644 index 000000000..9696e1a44 --- /dev/null +++ b/tests/check-dhl-rate-xml-escaping.py @@ -0,0 +1,53 @@ +from pathlib import Path +import re + + +dhl = Path("common/models/shipping/Dhlexpress.php") +source = dhl.read_text(encoding="utf-8") + +required_patterns = [ + r"private\s+function\s+escapeXmlValue\s*\(\s*\$value\s*\)", + r"htmlspecialchars\s*\(\s*\(string\)\s*\$value\s*,\s*ENT_XML1\s*\|\s*ENT_QUOTES\s*,\s*'UTF-8'\s*\)", + r"\"\s*\.\s*\$this->escapeXmlValue\s*\(\s*\$dhlexpress_account\s*\)\s*\.\s*\"", + r"\$this->escapeXmlValue\s*\(\s*\$fromCity\s*\)", + r"\$this->escapeXmlValue\s*\(\s*\$fromPostcode\s*\)", + r"\$this->escapeXmlValue\s*\(\s*\$to_city\s*\)", + r"\$this->escapeXmlValue\s*\(\s*\$postcode\s*\)", + r"\$declared_currency\s*=\s*\$this->escapeXmlValue\s*\(\s*\$selected_currency\s*\)", + r"\$declared_value\s*=\s*\$this->escapeXmlValue\s*\(\s*\$total_value\s*\)", + r"\{\$declared_currency\}", + r"\{\$declared_value\}", + r"'\s*\.\s*\$this->escapeXmlValue\s*\(\s*\$dhlexpress_key\s*\)\s*\.\s*'", + r"'\s*\.\s*\$this->escapeXmlValue\s*\(\s*\$dhlexpress_password\s*\)\s*\.\s*'", + r"'\s*\.\s*\$this->escapeXmlValue\s*\(\s*\$fromCountryCode\s*\)\s*\.\s*'", + r"'\s*\.\s*\$this->escapeXmlValue\s*\(\s*\$payment_country\s*\)\s*\.\s*'", + r"'\s*\.\s*\$this->escapeXmlValue\s*\(\s*\$dim_unit\s*\)\s*\.\s*'", + r"'\s*\.\s*\$this->escapeXmlValue\s*\(\s*\$weight_unit\s*\)\s*\.\s*'", + r"'\s*\.\s*\$this->escapeXmlValue\s*\(\s*\$is_dutiable\s*\)\s*\.\s*'", + r"'\s*\.\s*\$this->escapeXmlValue\s*\(\s*\$county_code_to\s*\)\s*\.\s*'", +] + +missing = [pattern for pattern in required_patterns if not re.search(pattern, source)] +if missing: + raise SystemExit( + "DHL Express XML is missing expected escaping patterns: " + + ", ".join(missing) + ) + +unsafe_patterns = [ + r"\"\s*\.\s*\$dhlexpress_account\s*\.\s*\"", + r"ShippingHelper::get_postcode_city\s*\(\s*\$fromCountryCode\s*,\s*\$fromCity\s*,\s*\$fromPostcode\s*\)", + r"ShippingHelper::get_postcode_city\s*\(\s*\$county_code_to\s*,\s*\$to_city\s*,\s*\$postcode\s*\)", + r"'\s*\.\s*\$dhlexpress_key\s*\.\s*'", + r"'\s*\.\s*\$dhlexpress_password\s*\.\s*'", + r"'\s*\.\s*\$fromCountryCode\s*\.\s*'", + r"'\s*\.\s*\$payment_country\s*\.\s*'", + r"'\s*\.\s*\$dim_unit\s*\.\s*'", + r"'\s*\.\s*\$weight_unit\s*\.\s*'", + r"'\s*\.\s*\$is_dutiable\s*\.\s*'", + r"'\s*\.\s*\$county_code_to\s*\.\s*'", +] + +for unsafe_pattern in unsafe_patterns: + if re.search(unsafe_pattern, source): + raise SystemExit(f"DHL Express XML still writes raw value pattern: {unsafe_pattern}")