diff options
author | ArthurHoaro <arthur@hoa.ro> | 2020-10-06 17:30:18 +0200 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2020-10-06 17:30:18 +0200 |
commit | 72fbbcd6794facea2cf06d9742359d190257b00f (patch) | |
tree | a4d6f446ec861f9a7591edb31f322e2a846b2bac /application | |
parent | df25b28dcd3cde54d42c18a55a810daa82bf5727 (diff) | |
download | Shaarli-72fbbcd6794facea2cf06d9742359d190257b00f.tar.gz Shaarli-72fbbcd6794facea2cf06d9742359d190257b00f.tar.zst Shaarli-72fbbcd6794facea2cf06d9742359d190257b00f.zip |
Security: fix multiple XSS vulnerabilities + fix search tags with special chars
XSS vulnerabilities fixed in editlink, linklist, tag.cloud and tag.list.
Also fixed tag search with special characters: urlencode function needs to be applied on raw data, before espaping, otherwise the rendered URL is wrong.
Diffstat (limited to 'application')
-rw-r--r-- | application/Utils.php | 4 | ||||
-rw-r--r-- | application/formatter/BookmarkFormatter.php | 26 | ||||
-rw-r--r-- | application/front/controller/admin/ManageShaareController.php | 10 | ||||
-rw-r--r-- | application/front/controller/admin/ManageTagController.php | 4 | ||||
-rw-r--r-- | application/front/controller/visitor/BookmarkListController.php | 7 | ||||
-rw-r--r-- | application/front/controller/visitor/TagCloudController.php | 12 | ||||
-rw-r--r-- | application/render/PageBuilder.php | 2 |
7 files changed, 50 insertions, 15 deletions
diff --git a/application/Utils.php b/application/Utils.php index 9c9eaaa2..bcfda65c 100644 --- a/application/Utils.php +++ b/application/Utils.php | |||
@@ -95,14 +95,14 @@ function escape($input) | |||
95 | return null; | 95 | return null; |
96 | } | 96 | } |
97 | 97 | ||
98 | if (is_bool($input)) { | 98 | if (is_bool($input) || is_int($input) || is_float($input) || $input instanceof DateTimeInterface) { |
99 | return $input; | 99 | return $input; |
100 | } | 100 | } |
101 | 101 | ||
102 | if (is_array($input)) { | 102 | if (is_array($input)) { |
103 | $out = array(); | 103 | $out = array(); |
104 | foreach ($input as $key => $value) { | 104 | foreach ($input as $key => $value) { |
105 | $out[$key] = escape($value); | 105 | $out[escape($key)] = escape($value); |
106 | } | 106 | } |
107 | return $out; | 107 | return $out; |
108 | } | 108 | } |
diff --git a/application/formatter/BookmarkFormatter.php b/application/formatter/BookmarkFormatter.php index 22ba7aae..0042dafe 100644 --- a/application/formatter/BookmarkFormatter.php +++ b/application/formatter/BookmarkFormatter.php | |||
@@ -58,7 +58,9 @@ abstract class BookmarkFormatter | |||
58 | $out['title'] = $this->formatTitle($bookmark); | 58 | $out['title'] = $this->formatTitle($bookmark); |
59 | $out['description'] = $this->formatDescription($bookmark); | 59 | $out['description'] = $this->formatDescription($bookmark); |
60 | $out['thumbnail'] = $this->formatThumbnail($bookmark); | 60 | $out['thumbnail'] = $this->formatThumbnail($bookmark); |
61 | $out['urlencoded_taglist'] = $this->formatUrlEncodedTagList($bookmark); | ||
61 | $out['taglist'] = $this->formatTagList($bookmark); | 62 | $out['taglist'] = $this->formatTagList($bookmark); |
63 | $out['urlencoded_tags'] = $this->formatUrlEncodedTagString($bookmark); | ||
62 | $out['tags'] = $this->formatTagString($bookmark); | 64 | $out['tags'] = $this->formatTagString($bookmark); |
63 | $out['sticky'] = $bookmark->isSticky(); | 65 | $out['sticky'] = $bookmark->isSticky(); |
64 | $out['private'] = $bookmark->isPrivate(); | 66 | $out['private'] = $bookmark->isPrivate(); |
@@ -182,6 +184,18 @@ abstract class BookmarkFormatter | |||
182 | } | 184 | } |
183 | 185 | ||
184 | /** | 186 | /** |
187 | * Format Url Encoded Tags | ||
188 | * | ||
189 | * @param Bookmark $bookmark instance | ||
190 | * | ||
191 | * @return array formatted Tags | ||
192 | */ | ||
193 | protected function formatUrlEncodedTagList($bookmark) | ||
194 | { | ||
195 | return array_map('urlencode', $this->filterTagList($bookmark->getTags())); | ||
196 | } | ||
197 | |||
198 | /** | ||
185 | * Format TagString | 199 | * Format TagString |
186 | * | 200 | * |
187 | * @param Bookmark $bookmark instance | 201 | * @param Bookmark $bookmark instance |
@@ -194,6 +208,18 @@ abstract class BookmarkFormatter | |||
194 | } | 208 | } |
195 | 209 | ||
196 | /** | 210 | /** |
211 | * Format TagString | ||
212 | * | ||
213 | * @param Bookmark $bookmark instance | ||
214 | * | ||
215 | * @return string formatted TagString | ||
216 | */ | ||
217 | protected function formatUrlEncodedTagString($bookmark) | ||
218 | { | ||
219 | return implode(' ', $this->formatUrlEncodedTagList($bookmark)); | ||
220 | } | ||
221 | |||
222 | /** | ||
197 | * Format Class | 223 | * Format Class |
198 | * Used to add specific CSS class for a link | 224 | * Used to add specific CSS class for a link |
199 | * | 225 | * |
diff --git a/application/front/controller/admin/ManageShaareController.php b/application/front/controller/admin/ManageShaareController.php index 59ba2de9..bb083486 100644 --- a/application/front/controller/admin/ManageShaareController.php +++ b/application/front/controller/admin/ManageShaareController.php | |||
@@ -78,13 +78,13 @@ class ManageShaareController extends ShaarliAdminController | |||
78 | $title = $this->container->conf->get('general.default_note_title', t('Note: ')); | 78 | $title = $this->container->conf->get('general.default_note_title', t('Note: ')); |
79 | } | 79 | } |
80 | 80 | ||
81 | $link = escape([ | 81 | $link = [ |
82 | 'title' => $title, | 82 | 'title' => $title, |
83 | 'url' => $url ?? '', | 83 | 'url' => $url ?? '', |
84 | 'description' => $description ?? '', | 84 | 'description' => $description ?? '', |
85 | 'tags' => $tags ?? '', | 85 | 'tags' => $tags ?? '', |
86 | 'private' => $private, | 86 | 'private' => $private, |
87 | ]); | 87 | ]; |
88 | } else { | 88 | } else { |
89 | $formatter = $this->container->formatterFactory->getFormatter('raw'); | 89 | $formatter = $this->container->formatterFactory->getFormatter('raw'); |
90 | $link = $formatter->format($bookmark); | 90 | $link = $formatter->format($bookmark); |
@@ -345,14 +345,14 @@ class ManageShaareController extends ShaarliAdminController | |||
345 | $tags[BookmarkMarkdownFormatter::NO_MD_TAG] = 1; | 345 | $tags[BookmarkMarkdownFormatter::NO_MD_TAG] = 1; |
346 | } | 346 | } |
347 | 347 | ||
348 | $data = [ | 348 | $data = escape([ |
349 | 'link' => $link, | 349 | 'link' => $link, |
350 | 'link_is_new' => $isNew, | 350 | 'link_is_new' => $isNew, |
351 | 'http_referer' => escape($this->container->environment['HTTP_REFERER'] ?? ''), | 351 | 'http_referer' => $this->container->environment['HTTP_REFERER'] ?? '', |
352 | 'source' => $request->getParam('source') ?? '', | 352 | 'source' => $request->getParam('source') ?? '', |
353 | 'tags' => $tags, | 353 | 'tags' => $tags, |
354 | 'default_private_links' => $this->container->conf->get('privacy.default_private_links', false), | 354 | 'default_private_links' => $this->container->conf->get('privacy.default_private_links', false), |
355 | ]; | 355 | ]); |
356 | 356 | ||
357 | $this->executePageHooks('render_editlink', $data, TemplatePage::EDIT_LINK); | 357 | $this->executePageHooks('render_editlink', $data, TemplatePage::EDIT_LINK); |
358 | 358 | ||
diff --git a/application/front/controller/admin/ManageTagController.php b/application/front/controller/admin/ManageTagController.php index 0380ef1f..2065c3e2 100644 --- a/application/front/controller/admin/ManageTagController.php +++ b/application/front/controller/admin/ManageTagController.php | |||
@@ -41,8 +41,8 @@ class ManageTagController extends ShaarliAdminController | |||
41 | 41 | ||
42 | $isDelete = null !== $request->getParam('deletetag') && null === $request->getParam('renametag'); | 42 | $isDelete = null !== $request->getParam('deletetag') && null === $request->getParam('renametag'); |
43 | 43 | ||
44 | $fromTag = escape(trim($request->getParam('fromtag') ?? '')); | 44 | $fromTag = trim($request->getParam('fromtag') ?? ''); |
45 | $toTag = escape(trim($request->getParam('totag') ?? '')); | 45 | $toTag = trim($request->getParam('totag') ?? ''); |
46 | 46 | ||
47 | if (0 === strlen($fromTag) || false === $isDelete && 0 === strlen($toTag)) { | 47 | if (0 === strlen($fromTag) || false === $isDelete && 0 === strlen($toTag)) { |
48 | $this->saveWarningMessage(t('Invalid tags provided.')); | 48 | $this->saveWarningMessage(t('Invalid tags provided.')); |
diff --git a/application/front/controller/visitor/BookmarkListController.php b/application/front/controller/visitor/BookmarkListController.php index 2988bee6..18368751 100644 --- a/application/front/controller/visitor/BookmarkListController.php +++ b/application/front/controller/visitor/BookmarkListController.php | |||
@@ -34,7 +34,7 @@ class BookmarkListController extends ShaarliVisitorController | |||
34 | $formatter = $this->container->formatterFactory->getFormatter(); | 34 | $formatter = $this->container->formatterFactory->getFormatter(); |
35 | $formatter->addContextData('base_path', $this->container->basePath); | 35 | $formatter->addContextData('base_path', $this->container->basePath); |
36 | 36 | ||
37 | $searchTags = escape(normalize_spaces($request->getParam('searchtags') ?? '')); | 37 | $searchTags = normalize_spaces($request->getParam('searchtags') ?? ''); |
38 | $searchTerm = escape(normalize_spaces($request->getParam('searchterm') ?? ''));; | 38 | $searchTerm = escape(normalize_spaces($request->getParam('searchterm') ?? ''));; |
39 | 39 | ||
40 | // Filter bookmarks according search parameters. | 40 | // Filter bookmarks according search parameters. |
@@ -104,8 +104,9 @@ class BookmarkListController extends ShaarliVisitorController | |||
104 | 'page_current' => $page, | 104 | 'page_current' => $page, |
105 | 'page_max' => $pageCount, | 105 | 'page_max' => $pageCount, |
106 | 'result_count' => count($linksToDisplay), | 106 | 'result_count' => count($linksToDisplay), |
107 | 'search_term' => $searchTerm, | 107 | 'search_term' => escape($searchTerm), |
108 | 'search_tags' => $searchTags, | 108 | 'search_tags' => escape($searchTags), |
109 | 'search_tags_url' => array_map('urlencode', explode(' ', $searchTags)), | ||
109 | 'visibility' => $visibility, | 110 | 'visibility' => $visibility, |
110 | 'links' => $linkDisp, | 111 | 'links' => $linkDisp, |
111 | ] | 112 | ] |
diff --git a/application/front/controller/visitor/TagCloudController.php b/application/front/controller/visitor/TagCloudController.php index f9c529bc..76ed7690 100644 --- a/application/front/controller/visitor/TagCloudController.php +++ b/application/front/controller/visitor/TagCloudController.php | |||
@@ -66,10 +66,18 @@ class TagCloudController extends ShaarliVisitorController | |||
66 | $tags = $this->formatTagsForCloud($tags); | 66 | $tags = $this->formatTagsForCloud($tags); |
67 | } | 67 | } |
68 | 68 | ||
69 | $tagsUrl = []; | ||
70 | foreach ($tags as $tag => $value) { | ||
71 | $tagsUrl[escape($tag)] = urlencode((string) $tag); | ||
72 | } | ||
73 | |||
69 | $searchTags = implode(' ', escape($filteringTags)); | 74 | $searchTags = implode(' ', escape($filteringTags)); |
75 | $searchTagsUrl = urlencode(implode(' ', $filteringTags)); | ||
70 | $data = [ | 76 | $data = [ |
71 | 'search_tags' => $searchTags, | 77 | 'search_tags' => escape($searchTags), |
72 | 'tags' => $tags, | 78 | 'search_tags_url' => $searchTagsUrl, |
79 | 'tags' => escape($tags), | ||
80 | 'tags_url' => $tagsUrl, | ||
73 | ]; | 81 | ]; |
74 | $this->executePageHooks('render_tag' . $type, $data, 'tag.' . $type); | 82 | $this->executePageHooks('render_tag' . $type, $data, 'tag.' . $type); |
75 | $this->assignAllView($data); | 83 | $this->assignAllView($data); |
diff --git a/application/render/PageBuilder.php b/application/render/PageBuilder.php index c52e3b76..41b357dd 100644 --- a/application/render/PageBuilder.php +++ b/application/render/PageBuilder.php | |||
@@ -137,7 +137,7 @@ class PageBuilder | |||
137 | $this->tpl->assign('language', $this->conf->get('translation.language')); | 137 | $this->tpl->assign('language', $this->conf->get('translation.language')); |
138 | 138 | ||
139 | if ($this->bookmarkService !== null) { | 139 | if ($this->bookmarkService !== null) { |
140 | $this->tpl->assign('tags', $this->bookmarkService->bookmarksCountPerTag()); | 140 | $this->tpl->assign('tags', escape($this->bookmarkService->bookmarksCountPerTag())); |
141 | } | 141 | } |
142 | 142 | ||
143 | $this->tpl->assign( | 143 | $this->tpl->assign( |