diff options
author | tcitworld <tcit@tcit.fr> | 2014-05-20 11:55:20 +0200 |
---|---|---|
committer | tcitworld <tcit@tcit.fr> | 2014-05-20 11:55:20 +0200 |
commit | 88f0e316225a3e9c98f5dbcf0ee8749d8eab55a5 (patch) | |
tree | 237c4f0b59423694b0b0820e009a6264927588a3 /inc | |
parent | 04b43dc097c3d69fd42d724b2cf082aff86d7272 (diff) | |
parent | 38eecef26ba33a052475c52dead699e434b2362a (diff) | |
download | wallabag-88f0e316225a3e9c98f5dbcf0ee8749d8eab55a5.tar.gz wallabag-88f0e316225a3e9c98f5dbcf0ee8749d8eab55a5.tar.zst wallabag-88f0e316225a3e9c98f5dbcf0ee8749d8eab55a5.zip |
Merge pull request #703 from tcitworld/images_security
Security fixes for downloaded images (thanks @leblanc-simon)
Diffstat (limited to 'inc')
-rwxr-xr-x | inc/poche/config.inc.default.php | 3 | ||||
-rw-r--r-- | inc/poche/pochePictures.php | 58 |
2 files changed, 55 insertions, 6 deletions
diff --git a/inc/poche/config.inc.default.php b/inc/poche/config.inc.default.php index edc42fc9..ffcd205d 100755 --- a/inc/poche/config.inc.default.php +++ b/inc/poche/config.inc.default.php | |||
@@ -30,7 +30,8 @@ | |||
30 | 30 | ||
31 | @define ('MODE_DEMO', FALSE); | 31 | @define ('MODE_DEMO', FALSE); |
32 | @define ('DEBUG_POCHE', FALSE); | 32 | @define ('DEBUG_POCHE', FALSE); |
33 | @define ('DOWNLOAD_PICTURES', FALSE); | 33 | @define ('DOWNLOAD_PICTURES', FALSE); # This can slow down the process of adding articles |
34 | @define ('REGENERATE_PICTURES_QUALITY', 75); | ||
34 | @define ('CONVERT_LINKS_FOOTNOTES', FALSE); | 35 | @define ('CONVERT_LINKS_FOOTNOTES', FALSE); |
35 | @define ('REVERT_FORCED_PARAGRAPH_ELEMENTS', FALSE); | 36 | @define ('REVERT_FORCED_PARAGRAPH_ELEMENTS', FALSE); |
36 | @define ('SHARE_TWITTER', TRUE); | 37 | @define ('SHARE_TWITTER', TRUE); |
diff --git a/inc/poche/pochePictures.php b/inc/poche/pochePictures.php index e4b0b160..7c319a85 100644 --- a/inc/poche/pochePictures.php +++ b/inc/poche/pochePictures.php | |||
@@ -14,6 +14,7 @@ | |||
14 | function filtre_picture($content, $url, $id) | 14 | function filtre_picture($content, $url, $id) |
15 | { | 15 | { |
16 | $matches = array(); | 16 | $matches = array(); |
17 | $processing_pictures = array(); // list of processing image to avoid processing the same pictures twice | ||
17 | preg_match_all('#<\s*(img)[^>]+src="([^"]*)"[^>]*>#Si', $content, $matches, PREG_SET_ORDER); | 18 | preg_match_all('#<\s*(img)[^>]+src="([^"]*)"[^>]*>#Si', $content, $matches, PREG_SET_ORDER); |
18 | foreach($matches as $i => $link) { | 19 | foreach($matches as $i => $link) { |
19 | $link[1] = trim($link[1]); | 20 | $link[1] = trim($link[1]); |
@@ -22,8 +23,17 @@ function filtre_picture($content, $url, $id) | |||
22 | $filename = basename(parse_url($absolute_path, PHP_URL_PATH)); | 23 | $filename = basename(parse_url($absolute_path, PHP_URL_PATH)); |
23 | $directory = create_assets_directory($id); | 24 | $directory = create_assets_directory($id); |
24 | $fullpath = $directory . '/' . $filename; | 25 | $fullpath = $directory . '/' . $filename; |
25 | download_pictures($absolute_path, $fullpath); | 26 | |
26 | $content = str_replace($matches[$i][2], $fullpath, $content); | 27 | if (in_array($absolute_path, $processing_pictures) === true) { |
28 | // replace picture's URL only if processing is OK : already processing -> go to next picture | ||
29 | continue; | ||
30 | } | ||
31 | |||
32 | if (download_pictures($absolute_path, $fullpath) === true) { | ||
33 | $content = str_replace($matches[$i][2], $fullpath, $content); | ||
34 | } | ||
35 | |||
36 | $processing_pictures[] = $absolute_path; | ||
27 | } | 37 | } |
28 | 38 | ||
29 | } | 39 | } |
@@ -64,17 +74,55 @@ function get_absolute_link($relative_link, $url) { | |||
64 | 74 | ||
65 | /** | 75 | /** |
66 | * Téléchargement des images | 76 | * Téléchargement des images |
77 | * | ||
78 | * @return bool true if the download and processing is OK, false else | ||
67 | */ | 79 | */ |
68 | function download_pictures($absolute_path, $fullpath) | 80 | function download_pictures($absolute_path, $fullpath) |
69 | { | 81 | { |
70 | $rawdata = Tools::getFile($absolute_path); | 82 | $rawdata = Tools::getFile($absolute_path); |
83 | $fullpath = urldecode($fullpath); | ||
71 | 84 | ||
72 | if(file_exists($fullpath)) { | 85 | if(file_exists($fullpath)) { |
73 | unlink($fullpath); | 86 | unlink($fullpath); |
74 | } | 87 | } |
75 | $fp = fopen($fullpath, 'x'); | 88 | |
76 | fwrite($fp, $rawdata); | 89 | // check extension |
77 | fclose($fp); | 90 | $file_ext = strrchr($fullpath, '.'); |
91 | $whitelist = array(".jpg",".jpeg",".gif",".png"); | ||
92 | if (!(in_array($file_ext, $whitelist))) { | ||
93 | Tools::logm('processed image with not allowed extension. Skipping ' . $fullpath); | ||
94 | return false; | ||
95 | } | ||
96 | |||
97 | // check headers | ||
98 | $imageinfo = getimagesize($absolute_path); | ||
99 | if ($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg'&& $imageinfo['mime'] != 'image/jpg'&& $imageinfo['mime'] != 'image/png') { | ||
100 | Tools::logm('processed image with bad header. Skipping ' . $fullpath); | ||
101 | return false; | ||
102 | } | ||
103 | |||
104 | // regenerate image | ||
105 | $im = imagecreatefromstring($rawdata); | ||
106 | if ($im === false) { | ||
107 | Tools::logm('error while regenerating image ' . $fullpath); | ||
108 | return false; | ||
109 | } | ||
110 | |||
111 | switch ($imageinfo['mime']) { | ||
112 | case 'image/gif': | ||
113 | $result = imagegif($im, $fullpath); | ||
114 | break; | ||
115 | case 'image/jpeg': | ||
116 | case 'image/jpg': | ||
117 | $result = imagejpeg($im, $fullpath, REGENERATE_PICTURES_QUALITY); | ||
118 | break; | ||
119 | case 'image/png': | ||
120 | $result = imagepng($im, $fullpath, ceil(REGENERATE_PICTURES_QUALITY / 100 * 9)); | ||
121 | break; | ||
122 | } | ||
123 | imagedestroy($im); | ||
124 | |||
125 | return $result; | ||
78 | } | 126 | } |
79 | 127 | ||
80 | /** | 128 | /** |