Skip to content

Commit f93e818

Browse files
committed
add new Security service, that can be overridden, add some doc about new Security service, fix security issue on scheme for cert html tag attributes, fix UTF8 example
1 parent e66a9a9 commit f93e818

File tree

10 files changed

+290
-49
lines changed

10 files changed

+290
-49
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [5.3.1](https://github.com/spipu/html2pdf/compare/v5.3.0...v5.3.1) - 2025-02-26
6+
7+
* add new Security service, that can be overridden
8+
* add some doc about new Security service
9+
* fix security issue on scheme for cert html tag attributes - thanks to [Positive Technologies](https://www.ptsecurity.com)
10+
* fix UTF8 example
11+
512
## [5.3.0](https://github.com/spipu/html2pdf/compare/v5.2.8...v5.3.0) - 2025-01-08
613

714
* bump supported phpversion from **5.6 -> 8.2** to **7.2 -> 8.4**

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ Html2Pdf is a HTML to PDF converter written in PHP, and compatible with PHP **7.
44

55
It allows the conversion of valid HTML in PDF format, to generate documents like invoices, documentation, ...
66

7-
You have to write a code of HTML for Html2Pdf, and not try to convert directly an already existing html page.
7+
You have to write specific cleaned HTML code for Html2Pdf.
8+
Do not try to convert directly an already existing html page, or HTML code coming from WYSIWYG, no help will be provided in this case.
89

910
Specific tags have been implemented, to adapt the html standard to a PDF usage.
1011

doc/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616
* [Exceptions](./exception.md)
1717
* [Useful Methods](./methods.md)
1818
* [Tcpdf Methods](./tcpdf_methods.md)
19+
* [Security / Blind SSRF](./security.md)
1920

2021
## Recommandations
2122

2223
* It is very important to provide valid HTML 4.01 to the converter, but only what is in the `<body>`.
24+
* You have to write specific cleaned HTML code for Html2Pdf. Do not try to convert directly an already existing html page, or HTML code coming from WYSIWYG, no help will be provided in this case.
2325
* Use the `<page>` tag. Does not use the `<html>` or `<body>` tag.
2426
* for borders: it is advised that they are like `solid 1mm #000000`
2527
* for padding, they are applicable only on tags `table`, `th`, `td`, `div`, `li`

doc/security.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Security
2+
3+
[back](./README.md)
4+
5+
Html2Pdf is using the default [Security](../src/Security/Security.php) service to protect the external included files (CSS, images, ...).
6+
7+
It allows :
8+
9+
* HTTP/HTTPS external files
10+
* Local Files
11+
12+
It does **not** protect again **Blind SSRF**. This means that the library loads external resources
13+
without validating the destination address before sending an HTTP request.
14+
15+
This is not the responsibility of this library.
16+
17+
You must ensure that the HTML you want to convert is secure, **especially if it is generated from uncontrolled data contributed by users**.
18+
In such cases, an attacker could send requests to both external servers and restricted-access servers (e.g., within a local network).
19+
20+
If you need additional security, you can implement the [SecurityInterface](../src/Security/SecurityInterface.php),
21+
and call the method `setSecurityService` on the Html2Pdf object to use it.

examples/res/utf8.txt

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
Sentences that contain all letters commonly used in a language
2+
--------------------------------------------------------------
3+
4+
This file is UTF-8 encoded.
5+
6+
Czech (cz)
7+
---------
8+
9+
Příšerně žluťoučký kůň úpěl ďábelské ódy.
10+
Hleď, toť přízračný kůň v mátožné póze šíleně úpí.
11+
Zvlášť zákeřný učeň s ďolíčky běží podél zóny úlů.
12+
Loď čeří kýlem tůň obzvlášť v Grónské úžině.
13+
Ó, náhlý déšť již zvířil prach a čilá laň teď běží s houfcem gazel k úkrytům.
14+
15+
Danish (da)
16+
---------
17+
18+
Quizdeltagerne spiste jordbær med fløde, mens cirkusklovnen
19+
Wolther spillede på xylofon.
20+
(= Quiz contestants were eating strawbery with cream while Wolther
21+
the circus clown played on xylophone.)
22+
23+
German (de)
24+
-----------
25+
26+
Falsches Üben von Xylophonmusik quält jeden größeren Zwerg
27+
(= Wrongful practicing of xylophone music tortures every larger dwarf)
28+
29+
Zwölf Boxkämpfer jagten Eva quer über den Sylter Deich
30+
(= Twelve boxing fighters hunted Eva across the dike of Sylt)
31+
32+
Heizölrückstoßabdämpfung
33+
(= fuel oil recoil absorber)
34+
(jqvwxy missing, but all non-ASCII letters in one word)
35+
36+
English (en)
37+
------------
38+
39+
The quick brown fox jumps over the lazy dog
40+
41+
Spanish (es)
42+
------------
43+
44+
El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y
45+
frío, añoraba a su querido cachorro.
46+
(Contains every letter and every accent, but not every combination
47+
of vowel + acute.)
48+
49+
French (fr)
50+
-----------
51+
52+
Portez ce vieux whisky au juge blond qui fume sur son île intérieure, à
53+
côté de l'alcôve ovoïde, où les bûches se consument dans l'âtre, ce
54+
qui lui permet de penser à la cænogenèse de l'être dont il est question
55+
dans la cause ambiguë entendue à Moÿ, dans un capharnaüm qui,
56+
pense-t-il, diminue çà et là la qualité de son œuvre.
57+
58+
l'île exiguë
59+
Où l'obèse jury mûr
60+
Fête l'haï volapük,
61+
Âne ex aéquo au whist,
62+
Ôtez ce vœu déçu.
63+
64+
Le cœur déçu mais l'âme plutôt naïve, Louÿs rêva de crapaüter en
65+
canoë au delà des îles, près du mälström où brûlent les novæ.
66+
67+
Irish Gaelic (ga)
68+
-----------------
69+
70+
D'fhuascail Íosa, Úrmhac na hÓighe Beannaithe, pór Éava agus Ádhaimh
71+
72+
Hungarian (hu)
73+
--------------
74+
75+
Árvíztűrő tükörfúrógép
76+
(= flood-proof mirror-drilling machine, only all non-ASCII letters)
77+
78+
Icelandic (is)
79+
--------------
80+
81+
Kæmi ný öxi hér ykist þjófum nú bæði víl og ádrepa
82+
83+
Sævör grét áðan því úlpan var ónýt
84+
(some ASCII letters missing)
85+
86+
Greek (el)
87+
-------------
88+
89+
Γαζέες καὶ μυρτιὲς δὲν θὰ βρῶ πιὰ στὸ χρυσαφὶ ξέφωτο
90+
(= No more shall I see acacias or myrtles in the golden clearing)
91+
92+
Ξεσκεπάζω τὴν ψυχοφθόρα βδελυγμία
93+
(= I uncover the soul-destroying abhorrence)
94+
95+
Hebrew (iw)
96+
-----------
97+
98+
? דג סקרן שט בים מאוכזב ולפתע מצא לו חברה איך הקליטה
99+
100+
Polish (pl)
101+
-----------
102+
103+
Pchnąć w tę łódź jeża lub osiem skrzyń fig
104+
(= To push a hedgehog or eight bins of figs in this boat)
105+
106+
Zażółć gęślą jaźń
107+
108+
Russian (ru)
109+
------------
110+
111+
В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!
112+
(= Would a citrus live in the bushes of south? Yes, but only a fake one!)
113+
114+
Thai (th)
115+
---------
116+
117+
[--------------------------|------------------------]
118+
๏ เป็นมนุษย์สุดประเสริฐเลิศคุณค่า กว่าบรรดาฝูงสัตว์เดรัจฉาน
119+
จงฝ่าฟันพัฒนาวิชาการ อย่าล้างผลาญฤๅเข่นฆ่าบีฑาใคร
120+
ไม่ถือโทษโกรธแช่งซัดฮึดฮัดด่า หัดอภัยเหมือนกีฬาอัชฌาสัย
121+
ปฏิบัติประพฤติกฎกำหนดใจ พูดจาให้จ๊ะๆ จ๋าๆ น่าฟังเอย ฯ
122+
123+
[The copyright for the Thai example is owned by The Computer
124+
Association of Thailand under the Royal Patronage of His Majesty the
125+
King.]
126+
127+
Example is coming from https://github.com/tecnickcom/TCPDF/blob/main/examples/data/utf8test.txt

examples/utf8.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
try {
2020
$html2pdf = new Html2Pdf('P', 'A4', 'fr');
2121

22-
$content = file_get_contents(K_PATH_MAIN.'examples/data/utf8test.txt');
22+
$content = file_get_contents(dirname(__FILE__) . '/res/utf8.txt');
2323
$content = '<page style="font-family: freeserif"><br />'.nl2br($content).'</page>';
2424

2525
$html2pdf->pdf->SetDisplayMode('real');

src/Html2Pdf.php

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
use Spipu\Html2Pdf\Parsing\Node;
2424
use Spipu\Html2Pdf\Parsing\TagParser;
2525
use Spipu\Html2Pdf\Parsing\TextParser;
26+
use Spipu\Html2Pdf\Security\Security;
27+
use Spipu\Html2Pdf\Security\SecurityInterface;
2628
use Spipu\Html2Pdf\Tag\TagInterface;
2729
use Spipu\Html2Pdf\Debug\DebugInterface;
2830
use Spipu\Html2Pdf\Debug\Debug;
@@ -69,6 +71,11 @@ class Html2Pdf
6971
*/
7072
private $svgDrawer;
7173

74+
/**
75+
* @var SecurityInterface
76+
*/
77+
private $security;
78+
7279
protected $_langue = 'fr'; // locale of the messages
7380
protected $_orientation = 'P'; // page orientation : Portrait ou Landscape
7481
protected $_format = 'A4'; // page format : A4, A3, ...
@@ -199,13 +206,18 @@ public function __construct(
199206
// load the Locale
200207
Locale::load($this->_langue);
201208

202-
// create the myPdf object
209+
$this->security = new Security();
203210
$this->pdf = new MyPdf($orientation, 'mm', $format, $unicode, $encoding, false, $pdfa);
204211

205-
// init the CSS parsing object
206212
$this->cssConverter = new CssConverter();
207213
$textParser = new TextParser($encoding);
208-
$this->parsingCss = new Parsing\Css($this->pdf, new TagParser($textParser), $this->cssConverter);
214+
215+
$this->parsingCss = new Parsing\Css(
216+
$this->pdf,
217+
new TagParser($textParser),
218+
$this->cssConverter,
219+
$this->security
220+
);
209221
$this->parsingCss->fontSet();
210222
$this->_defList = array();
211223

@@ -247,7 +259,7 @@ public function getVersionAsArray()
247259
return array(
248260
'major' => 5,
249261
'minor' => 3,
250-
'revision' => 0
262+
'revision' => 1,
251263
);
252264
}
253265

@@ -275,6 +287,19 @@ public function __clone()
275287
$this->parsingCss->setPdfParent($this->pdf);
276288
}
277289

290+
/**
291+
* Use a specific security interface
292+
* @param SecurityInterface $security
293+
* @return $this
294+
*/
295+
public function setSecurityService(SecurityInterface $security): self
296+
{
297+
$this->security = $security;
298+
$this->parsingCss->setSecurityService($security);
299+
300+
return $this;
301+
}
302+
278303
/**
279304
* Set the max number of lines for a sentence
280305
*
@@ -1509,14 +1534,14 @@ protected function _makeBreakLine($h, $curr = null)
15091534
protected function _drawImage($src, $subLi = false)
15101535
{
15111536
// get the size of the image
1512-
// WARNING : if URL, "allow_url_fopen" must turned to "on" in php.ini
1537+
// WARNING : if URL, "allow_url_fopen" must turn to "on" in php.ini
15131538

15141539
if (strpos($src,'data:') === 0) {
15151540
$src = base64_decode( preg_replace('#^data:image/[^;]+;base64,#', '', $src) );
15161541
$infos = @getimagesizefromstring($src);
15171542
$src = "@{$src}";
15181543
} else {
1519-
$this->parsingCss->checkValidPath($src);
1544+
$this->security->checkValidPath((string) $src);
15201545
$infos = @getimagesize($src);
15211546
}
15221547

@@ -5806,13 +5831,15 @@ protected function _tag_open_CERT($param)
58065831
}
58075832

58085833
// set certificate file
5809-
$certificate = $param['src'];
5834+
$certificate = (string) $param['src'];
5835+
$this->security->checkValidPath($certificate);
58105836
if(!file_exists($certificate)) {
58115837
return true;
58125838
}
58135839

58145840
// Set private key
5815-
$privkey = $param['privkey'];
5841+
$privkey = (string) $param['privkey'];
5842+
$this->security->checkValidPath($privkey);
58165843
if(strlen($privkey)==0 || !file_exists($privkey)) {
58175844
$privkey = $certificate;
58185845
}

0 commit comments

Comments
 (0)