diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index efd3b52f..f03ce224 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -1,3 +1,8 @@ +6.7.0 (2024-03-18) + - Fix security issue. + - [BREAKING CHANGE] The tcpdf HTML tag syntax has changed, see example_049.php. + - New K_ALLOWED_TCPDF_TAGS configuration constant to set the allowed methods for the tcdpf HTML tag. + 6.6.5 (2023-09-06) - Fix corrupted file. diff --git a/LICENSE.TXT b/LICENSE.TXT index 072e73a7..ec7968a7 100644 --- a/LICENSE.TXT +++ b/LICENSE.TXT @@ -7,7 +7,7 @@ published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - 2002-2023 Nicola Asuni - Tecnick.com LTD + 2002-2024 Nicola Asuni - Tecnick.com LTD ********************************************************************** ********************************************************************** diff --git a/README.md b/README.md index 39ea1c45..f59f6633 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ * **category** Library * **author** Nicola Asuni -* **copyright** 2002-2023 Nicola Asuni - Tecnick.com LTD +* **copyright** 2002-2024 Nicola Asuni - Tecnick.com LTD * **license** http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) * **link** http://www.tcpdf.org * **source** https://github.com/tecnickcom/TCPDF diff --git a/VERSION b/VERSION index 5dbe61b9..f0e13c50 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.6.5 +6.7.0 diff --git a/composer.json b/composer.json index f24d581d..914c4453 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "barcodes" ], "homepage": "http://www.tcpdf.org/", - "version": "6.6.5", + "version": "6.7.0", "license": "LGPL-3.0-or-later", "authors": [ { diff --git a/examples/config/tcpdf_config_alt.php b/examples/config/tcpdf_config_alt.php index d61b1ba7..65fd5760 100644 --- a/examples/config/tcpdf_config_alt.php +++ b/examples/config/tcpdf_config_alt.php @@ -212,6 +212,18 @@ */ define('K_TCPDF_CALLS_IN_HTML', true); +/** + * List the TCPDF methods that are allowed to be called using HTML syntax. + * The constant K_TCPDF_CALLS_IN_HTML must be set to true. + * IMPORTANT: For security reason, disable this feature if you are allowing user HTML content. + */ +define('K_ALLOWED_TCPDF_TAGS', array( + 'AddPage', + 'Rect', + 'SetDrawColor', + 'write1DBarcode', +)); + /** * If true and PHP version is greater than 5, then the Error() method throw new exception instead of terminating the execution. */ diff --git a/examples/example_049.php b/examples/example_049.php index d2a46ada..5ebefc66 100644 --- a/examples/example_049.php +++ b/examples/example_049.php @@ -2,7 +2,7 @@ //============================================================+ // File name : example_049.php // Begin : 2009-04-03 -// Last Update : 2014-12-10 +// Last Update : 2024-03-18 // // Description : Example 049 for TCPDF class // WriteHTML with TCPDF callback functions @@ -78,11 +78,11 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * IMPORTANT: -If you are printing user-generated content, tcpdf tag can be unsafe. -You can disable this tag by setting to false the K_TCPDF_CALLS_IN_HTML -constant on TCPDF configuration file. +If you are printing user-generated content, the tcpdf tag should be considered unsafe. +This tag is disabled by default by the K_TCPDF_CALLS_IN_HTML constant on TCPDF configuration file. +Please use this feature only if you are in control of the HTML content and you are sure that it does not contain any harmful code. -For security reasons, the parameters for the 'params' attribute of TCPDF +For security reasons, the parameters for the 'params' attribute of TCPDF tag must be prepared as an array and encoded with the serializeTCPDFtagParameters() method (see the example below). @@ -91,23 +91,25 @@ $html = '

Test TCPDF Methods in HTML

IMPORTANT:

-If you are using user-generated content, the tcpdf tag can be unsafe.
-You can disable this tag by setting to false the K_TCPDF_CALLS_IN_HTML constant on TCPDF configuration file.
+If you are using user-generated content, the tcpdf tag should be considered unsafe.
+Please use this feature only if you are in control of the HTML content and you are sure that it does not contain any harmful code.
+This feature is disabled by default by the K_TCPDF_CALLS_IN_HTML constant on TCPDF configuration file.

write1DBarcode method in HTML

'; -$params = $pdf->serializeTCPDFtagParameters(array('CODE 39', 'C39', '', '', 80, 30, 0.4, array('position'=>'S', 'border'=>true, 'padding'=>4, 'fgcolor'=>array(0,0,0), 'bgcolor'=>array(255,255,255), 'text'=>true, 'font'=>'helvetica', 'fontsize'=>8, 'stretchtext'=>4), 'N')); -$html .= ''; +$data = $pdf->serializeTCPDFtag('write1DBarcode', array('CODE 39', 'C39', '', '', 80, 30, 0.4, array('position'=>'S', 'border'=>true, 'padding'=>4, 'fgcolor'=>array(0,0,0), 'bgcolor'=>array(255,255,255), 'text'=>true, 'font'=>'helvetica', 'fontsize'=>8, 'stretchtext'=>4), 'N')); +$html .= ''; -$params = $pdf->serializeTCPDFtagParameters(array('CODE 128', 'C128', '', '', 80, 30, 0.4, array('position'=>'S', 'border'=>true, 'padding'=>4, 'fgcolor'=>array(0,0,0), 'bgcolor'=>array(255,255,255), 'text'=>true, 'font'=>'helvetica', 'fontsize'=>8, 'stretchtext'=>4), 'N')); -$html .= ''; +$data = $pdf->serializeTCPDFtag('write1DBarcode', array('CODE 128', 'C128', '', '', 80, 30, 0.4, array('position'=>'S', 'border'=>true, 'padding'=>4, 'fgcolor'=>array(0,0,0), 'bgcolor'=>array(255,255,255), 'text'=>true, 'font'=>'helvetica', 'fontsize'=>8, 'stretchtext'=>4), 'N')); +$html .= ''; -$html .= '

Graphic Functions

'; +$data = $pdf->serializeTCPDFtag('AddPage'); +$html .= '

Graphic Functions

'; -$params = $pdf->serializeTCPDFtagParameters(array(0)); -$html .= ''; +$data = $pdf->serializeTCPDFtag('SetDrawColor', array(0)); +$html .= ''; -$params = $pdf->serializeTCPDFtagParameters(array(50, 50, 40, 10, 'DF', array(), array(0,128,255))); -$html .= ''; +$data = $pdf->serializeTCPDFtag('Rect', array(50, 50, 40, 10, 'DF', array(), array(0,128,255))); +$html .= ''; // output the HTML content diff --git a/include/tcpdf_static.php b/include/tcpdf_static.php index 4c28850e..5e79a649 100644 --- a/include/tcpdf_static.php +++ b/include/tcpdf_static.php @@ -55,7 +55,7 @@ class TCPDF_STATIC { * Current TCPDF version. * @private static */ - private static $tcpdf_version = '6.6.5'; + private static $tcpdf_version = '6.7.0'; /** * String alias for total number of pages. diff --git a/tcpdf.php b/tcpdf.php index cd020512..f192b6b6 100644 --- a/tcpdf.php +++ b/tcpdf.php @@ -1,13 +1,13 @@ * @package com.tecnick.tcpdf * @brief PHP class for generating PDF documents without requiring external extensions. - * @version 6.6.5 + * @version 6.7.0 * @author Nicola Asuni - info@tecnick.com * @IgnoreAnnotation("protected") * @IgnoreAnnotation("public") @@ -17200,41 +17200,49 @@ protected function getSpaceString() { } /** - * Return an hash code used to ensure that the serialized data has been generated by this TCPDF instance. - * @param string $data serialized data - * @return string + * Serialize data to be used with TCPDF tag in HTML code. + * @param string $method TCPDF method name + * @param array $params Method parameters + * @return string Serialized data * @public static */ - protected function getHashForTCPDFtagParams($data) { - return md5(strlen($data).$this->file_id.$data); - } - - /** - * Serialize an array of parameters to be used with TCPDF tag in HTML code. - * @param array $data parameters array - * @return string containing serialized data - * @public static - */ - public function serializeTCPDFtagParameters($data) { + public function serializeTCPDFtag($method, $params=array()) { + $data = array('m' => $method, 'p' => $params); $encoded = urlencode(json_encode($data)); - return $this->getHashForTCPDFtagParams($encoded).$encoded; + $hash = password_hash($encoded.'+'.$this->file_id, PASSWORD_DEFAULT); + return strlen($hash).'+'.$hash.'+'.$encoded; } /** - * Unserialize parameters to be used with TCPDF tag in HTML code. + * Unserialize data to be used with TCPDF tag in HTML code. * @param string $data serialized data * @return array containing unserialized data * @protected static */ - protected function unserializeTCPDFtagParameters($data) { - $hash = substr($data, 0, 32); - $encoded = substr($data, 32); - if ($hash != $this->getHashForTCPDFtagParams($encoded)) { + protected function unserializeTCPDFtag($data) { + $hpos = strpos($data, '+'); + $hlen = intval(substr($data, 0, $hpos)); + $hash = substr($data, $hpos + 1, $hlen); + $encoded = substr($data, $hpos + 2 + $hlen); + if (!password_verify($encoded.'+'.$this->file_id, $hash)) { $this->Error('Invalid parameters'); } return json_decode(urldecode($encoded), true); } + /** + * Check if a TCPDF tag is allowed + * @param string $method TCPDF method name + * @return boolean + * @protected + */ + protected function allowedTCPDFtag($method) { + if (!defined('K_ALLOWED_TCPDF_TAGS') || empty(K_ALLOWED_TCPDF_TAGS)) { + return false; + } + return in_array($method, K_ALLOWED_TCPDF_TAGS, true); + } + /** * Prints a cell (rectangular area) with optional borders, background color and html text string. * The upper-left corner of the cell corresponds to the current position. After the call, the current position moves to the right or to the next line.
@@ -17248,8 +17256,7 @@ protected function unserializeTCPDFtagParameters($data) { * @param float|null $y upper-left corner Y coordinate * @param string $html html text to print. Default value: empty string. * @param mixed $border Indicates if borders must be drawn around the cell. The value can be a number:
  • 0: no border (default)
  • 1: frame
or a string containing some or all of the following characters (in any order):
  • L: left
  • T: top
  • R: right
  • B: bottom
or an array of line styles for each border group - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))) - * @param int $ln Indicates where the current position should go after the call. Possible values are:
  • 0: to the right (or left for RTL language)
  • 1: to the beginning of the next line
  • 2: below
-Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. + * @param int $ln Indicates where the current position should go after the call. Possible values are:
  • 0: to the right (or left for RTL language)
  • 1: to the beginning of the next line
  • 2: below
Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0. * @param boolean $fill Indicates if the cell background must be painted (true) or transparent (false). * @param boolean $reseth if true reset the last cell height (default true). * @param string $align Allows to center or align the text. Possible values are:
  • L : left align
  • C : center
  • R : right align
  • '' : empty string : left for LTR or right for RTL
@@ -19510,17 +19517,14 @@ protected function openHTMLTagHandler($dom, $key, $cell) { case 'tcpdf': { if (defined('K_TCPDF_CALLS_IN_HTML') AND (K_TCPDF_CALLS_IN_HTML === true)) { // Special tag used to call TCPDF methods - if (isset($tag['attribute']['method'])) { - $tcpdf_method = $tag['attribute']['method']; - if (method_exists($this, $tcpdf_method)) { - if (isset($tag['attribute']['params']) AND (!empty($tag['attribute']['params']))) { - $params = $this->unserializeTCPDFtagParameters($tag['attribute']['params']); - call_user_func_array(array($this, $tcpdf_method), $params); - } else { - $this->$tcpdf_method(); - } - $this->newline = true; + // This tag is disabled by default by the K_TCPDF_CALLS_IN_HTML constant on TCPDF configuration file. + // Please use this feature only if you are in control of the HTML content and you are sure that it does not contain any harmful code. + if (!empty($tag['attribute']['data'])) { + $tcpdf_tag_data = $this->unserializeTCPDFtag($tag['attribute']['data']); + if ($this->allowedTCPDFtag($tcpdf_tag_data['m'])) { + call_user_func_array(array($this, $tcpdf_tag_data['m']), $tcpdf_tag_data['p']); } + $this->newline = true; } } break; @@ -21867,25 +21871,23 @@ public function commitTransaction() { * @since 4.5.029 (2009-03-19) */ public function rollbackTransaction($self=false) { - if (isset($this->objcopy)) { - $objcopy = $this->objcopy; - $this->_destroy(true, true); - if ($self) { - $objvars = get_object_vars($objcopy); - foreach ($objvars as $key => $value) { - $this->$key = $value; - } - $objcopy->_destroy(true, true); - /* The unique file_id should not be used during cleanup again */ - $objcopy->file_id = NULL; - unset($objcopy); - return $this; - } - /* The unique file_id should not be used during cleanup again */ - $this->file_id = NULL; - return $objcopy; - } - return $this; + if (!isset($this->objcopy)) { + return $this; + } + $file_id = $this->file_id; + $objcopy = $this->objcopy; + $this->_destroy(true, true); + if ($self) { + $objvars = get_object_vars($objcopy); + foreach ($objvars as $key => $value) { + $this->$key = $value; + } + $objcopy->_destroy(true, true); + unset($objcopy); + return $this; + } + $this->file_id = $file_id; + return $objcopy; } // --- MULTI COLUMNS METHODS ----------------------- diff --git a/tcpdf_autoconfig.php b/tcpdf_autoconfig.php index 6ec9ce83..c813863d 100644 --- a/tcpdf_autoconfig.php +++ b/tcpdf_autoconfig.php @@ -228,6 +228,10 @@ define('K_TCPDF_CALLS_IN_HTML', false); } +if (!defined('K_ALLOWED_TCPDF_TAGS')) { + define('K_ALLOWED_TCPDF_TAGS', array()); +} + if (!defined('K_TCPDF_THROW_EXCEPTION_ERROR')) { define('K_TCPDF_THROW_EXCEPTION_ERROR', false); }