Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
a546b9fb
Commit
a546b9fb
authored
Jul 03, 2019
by
Guillaume Grossetie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Prevent excessive sanitization of AsciiDoc ouptut
parent
dece8406
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
326 additions
and
113 deletions
+326
-113
app/assets/stylesheets/framework.scss
app/assets/stylesheets/framework.scss
+0
-1
app/assets/stylesheets/framework/asciidoctor.scss
app/assets/stylesheets/framework/asciidoctor.scss
+0
-27
app/assets/stylesheets/framework/typography.scss
app/assets/stylesheets/framework/typography.scss
+64
-1
changelogs/unreleased/63298-prevent-excessive-sanitization-asciidoc.yml
...eleased/63298-prevent-excessive-sanitization-asciidoc.yml
+5
-0
lib/banzai/filter/ascii_doc_sanitization_filter.rb
lib/banzai/filter/ascii_doc_sanitization_filter.rb
+62
-0
lib/banzai/filter/base_sanitization_filter.rb
lib/banzai/filter/base_sanitization_filter.rb
+96
-0
lib/banzai/filter/sanitization_filter.rb
lib/banzai/filter/sanitization_filter.rb
+4
-78
lib/banzai/pipeline/ascii_doc_pipeline.rb
lib/banzai/pipeline/ascii_doc_pipeline.rb
+1
-1
spec/lib/gitlab/asciidoc_spec.rb
spec/lib/gitlab/asciidoc_spec.rb
+94
-5
No files found.
app/assets/stylesheets/framework.scss
View file @
a546b9fb
...
@@ -9,7 +9,6 @@
...
@@ -9,7 +9,6 @@
@import
'framework/animations'
;
@import
'framework/animations'
;
@import
'framework/vue_transitions'
;
@import
'framework/vue_transitions'
;
@import
'framework/asciidoctor'
;
@import
'framework/banner'
;
@import
'framework/banner'
;
@import
'framework/blocks'
;
@import
'framework/blocks'
;
@import
'framework/buttons'
;
@import
'framework/buttons'
;
...
...
app/assets/stylesheets/framework/asciidoctor.scss
deleted
100644 → 0
View file @
dece8406
.admonitionblock
td
.icon
{
width
:
1%
;
[
class
^=
'fa icon-'
]
{
@extend
.fa-2x
;
}
.icon-note
{
@extend
.fa-thumb-tack
;
}
.icon-tip
{
@extend
.fa-lightbulb-o
;
}
.icon-warning
{
@extend
.fa-exclamation-triangle
;
}
.icon-caution
{
@extend
.fa-fire
;
}
.icon-important
{
@extend
.fa-exclamation-circle
;
}
}
app/assets/stylesheets/framework/typography.scss
View file @
a546b9fb
/**
/**
* Apply Mark
down
typography
* Apply Mark
up (Markdown/AsciiDoc)
typography
*
*
*/
*/
.md
:not
(
.use-csslab
)
{
.md
:not
(
.use-csslab
)
{
...
@@ -245,6 +245,21 @@
...
@@ -245,6 +245,21 @@
}
}
}
}
ul
.checklist
,
ul
.none
,
ol
.none
,
ul
.no-bullet
,
ol
.no-bullet
,
ol
.unnumbered
,
ul
.unstyled
,
ol
.unstyled
{
list-style-type
:
none
;
li
{
margin-left
:
0
;
}
}
li
{
li
{
line-height
:
1
.6em
;
line-height
:
1
.6em
;
margin-left
:
25px
;
margin-left
:
25px
;
...
@@ -321,6 +336,54 @@
...
@@ -321,6 +336,54 @@
visibility
:
visible
;
visibility
:
visible
;
}
}
}
}
.big
{
font-size
:
larger
;
}
.small
{
font-size
:
smaller
;
}
.underline
{
text-decoration
:
underline
;
}
.overline
{
text-decoration
:
overline
;
}
.line-through
{
text-decoration
:
line-through
;
}
.admonitionblock
td
.icon
{
width
:
1%
;
[
class
^=
'fa icon-'
]
{
@extend
.fa-2x
;
}
.icon-note
{
@extend
.fa-thumb-tack
;
}
.icon-tip
{
@extend
.fa-lightbulb-o
;
}
.icon-warning
{
@extend
.fa-exclamation-triangle
;
}
.icon-caution
{
@extend
.fa-fire
;
}
.icon-important
{
@extend
.fa-exclamation-circle
;
}
}
}
}
...
...
changelogs/unreleased/63298-prevent-excessive-sanitization-asciidoc.yml
0 → 100644
View file @
a546b9fb
---
title
:
"
Prevent
excessive
sanitization
of
AsciiDoc
ouptut"
merge_request
:
30290
author
:
Guillaume Grossetie
type
:
added
\ No newline at end of file
lib/banzai/filter/ascii_doc_sanitization_filter.rb
0 → 100644
View file @
a546b9fb
# frozen_string_literal: true
module
Banzai
module
Filter
# Sanitize HTML produced by AsciiDoc/Asciidoctor.
#
# Extends Banzai::Filter::BaseSanitizationFilter with specific rules.
class
AsciiDocSanitizationFilter
<
Banzai
::
Filter
::
BaseSanitizationFilter
# Classes used by Asciidoctor to style components
ADMONITION_CLASSES
=
%w(fa icon-note icon-tip icon-warning icon-caution icon-important)
.
freeze
CALLOUT_CLASSES
=
[
'conum'
].
freeze
CHECKLIST_CLASSES
=
%w(fa fa-check-square-o fa-square-o)
.
freeze
LIST_CLASSES
=
%w(checklist none no-bullet unnumbered unstyled)
.
freeze
ELEMENT_CLASSES_WHITELIST
=
{
span:
%w(big small underline overline line-through)
.
freeze
,
div:
[
'admonitionblock'
].
freeze
,
td:
[
'icon'
].
freeze
,
i:
ADMONITION_CLASSES
+
CALLOUT_CLASSES
+
CHECKLIST_CLASSES
,
ul:
LIST_CLASSES
,
ol:
LIST_CLASSES
}.
freeze
def
customize_whitelist
(
whitelist
)
# Allow marks
whitelist
[
:elements
].
push
(
'mark'
)
# Allow any classes in `span`, `i`, `div`, `td`, `ul` and `ol` elements
# but then remove any unknown classes
whitelist
[
:attributes
][
'span'
]
=
%w(class)
whitelist
[
:attributes
][
'div'
].
push
(
'class'
)
whitelist
[
:attributes
][
'td'
]
=
%w(class)
whitelist
[
:attributes
][
'i'
]
=
%w(class)
whitelist
[
:attributes
][
'ul'
]
=
%w(class)
whitelist
[
:attributes
][
'ol'
]
=
%w(class)
whitelist
[
:transformers
].
push
(
self
.
class
.
remove_element_classes
)
whitelist
end
class
<<
self
def
remove_element_classes
lambda
do
|
env
|
node
=
env
[
:node
]
return
unless
(
classes_whitelist
=
ELEMENT_CLASSES_WHITELIST
[
node
.
name
.
to_sym
])
return
unless
node
.
has_attribute?
(
'class'
)
classes
=
node
[
'class'
].
strip
.
split
(
' '
)
allowed_classes
=
(
classes
&
classes_whitelist
)
if
allowed_classes
.
empty?
node
.
remove_attribute
(
'class'
)
else
node
[
'class'
]
=
allowed_classes
.
join
(
' '
)
end
end
end
end
end
end
end
lib/banzai/filter/base_sanitization_filter.rb
0 → 100644
View file @
a546b9fb
# frozen_string_literal: true
module
Banzai
module
Filter
# Sanitize HTML produced by markup languages (Markdown, AsciiDoc...).
# Specific rules are implemented in dedicated filters:
#
# - Banzai::Filter::SanitizationFilter (Markdown)
# - Banzai::Filter::AsciiDocSanitizationFilter (AsciiDoc/Asciidoctor)
#
# Extends HTML::Pipeline::SanitizationFilter with common rules.
class
BaseSanitizationFilter
<
HTML
::
Pipeline
::
SanitizationFilter
include
Gitlab
::
Utils
::
StrongMemoize
UNSAFE_PROTOCOLS
=
%w(data javascript vbscript)
.
freeze
def
whitelist
strong_memoize
(
:whitelist
)
do
whitelist
=
super
.
deep_dup
# Allow span elements
whitelist
[
:elements
].
push
(
'span'
)
# Allow data-math-style attribute in order to support LaTeX formatting
whitelist
[
:attributes
][
'code'
]
=
%w(data-math-style)
whitelist
[
:attributes
][
'pre'
]
=
%w(data-math-style)
# Allow html5 details/summary elements
whitelist
[
:elements
].
push
(
'details'
)
whitelist
[
:elements
].
push
(
'summary'
)
# Allow abbr elements with title attribute
whitelist
[
:elements
].
push
(
'abbr'
)
whitelist
[
:attributes
][
'abbr'
]
=
%w(title)
# Disallow `name` attribute globally, allow on `a`
whitelist
[
:attributes
][
:all
].
delete
(
'name'
)
whitelist
[
:attributes
][
'a'
].
push
(
'name'
)
# Allow any protocol in `a` elements
# and then remove links with unsafe protocols
whitelist
[
:protocols
].
delete
(
'a'
)
whitelist
[
:transformers
].
push
(
self
.
class
.
remove_unsafe_links
)
# Remove `rel` attribute from `a` elements
whitelist
[
:transformers
].
push
(
self
.
class
.
remove_rel
)
customize_whitelist
(
whitelist
)
end
end
def
customize_whitelist
(
whitelist
)
raise
NotImplementedError
end
class
<<
self
def
remove_unsafe_links
lambda
do
|
env
|
node
=
env
[
:node
]
return
unless
node
.
name
==
'a'
return
unless
node
.
has_attribute?
(
'href'
)
begin
node
[
'href'
]
=
node
[
'href'
].
strip
uri
=
Addressable
::
URI
.
parse
(
node
[
'href'
])
return
unless
uri
.
scheme
# Remove all invalid scheme characters before checking against the
# list of unsafe protocols.
#
# See https://tools.ietf.org/html/rfc3986#section-3.1
scheme
=
uri
.
scheme
.
strip
.
downcase
.
gsub
(
/[^A-Za-z0-9\+\.\-]+/
,
''
)
node
.
remove_attribute
(
'href'
)
if
UNSAFE_PROTOCOLS
.
include?
(
scheme
)
rescue
Addressable
::
URI
::
InvalidURIError
node
.
remove_attribute
(
'href'
)
end
end
end
def
remove_rel
lambda
do
|
env
|
if
env
[
:node_name
]
==
'a'
env
[
:node
].
remove_attribute
(
'rel'
)
end
end
end
end
end
end
end
lib/banzai/filter/sanitization_filter.rb
View file @
a546b9fb
...
@@ -2,23 +2,13 @@
...
@@ -2,23 +2,13 @@
module
Banzai
module
Banzai
module
Filter
module
Filter
# Sanitize HTML
# Sanitize HTML
produced by Markdown.
#
#
# Extends HTML::Pipeline::SanitizationFilter with a custom whitelist.
# Extends Banzai::Filter::BaseSanitizationFilter with specific rules.
class
SanitizationFilter
<
HTML
::
Pipeline
::
SanitizationFilter
class
SanitizationFilter
<
Banzai
::
Filter
::
BaseSanitizationFilter
include
Gitlab
::
Utils
::
StrongMemoize
# Styles used by Markdown for table alignment
UNSAFE_PROTOCOLS
=
%w(data javascript vbscript)
.
freeze
TABLE_ALIGNMENT_PATTERN
=
/text-align: (?<alignment>center|left|right)/
.
freeze
TABLE_ALIGNMENT_PATTERN
=
/text-align: (?<alignment>center|left|right)/
.
freeze
def
whitelist
strong_memoize
(
:whitelist
)
do
customize_whitelist
(
super
.
deep_dup
)
end
end
private
def
customize_whitelist
(
whitelist
)
def
customize_whitelist
(
whitelist
)
# Allow table alignment; we whitelist specific text-align values in a
# Allow table alignment; we whitelist specific text-align values in a
# transformer below
# transformer below
...
@@ -26,36 +16,9 @@ module Banzai
...
@@ -26,36 +16,9 @@ module Banzai
whitelist
[
:attributes
][
'td'
]
=
%w(style)
whitelist
[
:attributes
][
'td'
]
=
%w(style)
whitelist
[
:css
]
=
{
properties:
[
'text-align'
]
}
whitelist
[
:css
]
=
{
properties:
[
'text-align'
]
}
# Allow span elements
whitelist
[
:elements
].
push
(
'span'
)
# Allow data-math-style attribute in order to support LaTeX formatting
whitelist
[
:attributes
][
'code'
]
=
%w(data-math-style)
whitelist
[
:attributes
][
'pre'
]
=
%w(data-math-style)
# Allow html5 details/summary elements
whitelist
[
:elements
].
push
(
'details'
)
whitelist
[
:elements
].
push
(
'summary'
)
# Allow abbr elements with title attribute
whitelist
[
:elements
].
push
(
'abbr'
)
whitelist
[
:attributes
][
'abbr'
]
=
%w(title)
# Allow the 'data-sourcepos' from CommonMark on all elements
# Allow the 'data-sourcepos' from CommonMark on all elements
whitelist
[
:attributes
][
:all
].
push
(
'data-sourcepos'
)
whitelist
[
:attributes
][
:all
].
push
(
'data-sourcepos'
)
# Disallow `name` attribute globally, allow on `a`
whitelist
[
:attributes
][
:all
].
delete
(
'name'
)
whitelist
[
:attributes
][
'a'
].
push
(
'name'
)
# Allow any protocol in `a` elements
# and then remove links with unsafe protocols
whitelist
[
:protocols
].
delete
(
'a'
)
whitelist
[
:transformers
].
push
(
self
.
class
.
remove_unsafe_links
)
# Remove `rel` attribute from `a` elements
whitelist
[
:transformers
].
push
(
self
.
class
.
remove_rel
)
# Remove any `style` properties not required for table alignment
# Remove any `style` properties not required for table alignment
whitelist
[
:transformers
].
push
(
self
.
class
.
remove_unsafe_table_style
)
whitelist
[
:transformers
].
push
(
self
.
class
.
remove_unsafe_table_style
)
...
@@ -69,43 +32,6 @@ module Banzai
...
@@ -69,43 +32,6 @@ module Banzai
end
end
class
<<
self
class
<<
self
def
remove_unsafe_links
lambda
do
|
env
|
node
=
env
[
:node
]
return
unless
node
.
name
==
'a'
return
unless
node
.
has_attribute?
(
'href'
)
begin
node
[
'href'
]
=
node
[
'href'
].
strip
uri
=
Addressable
::
URI
.
parse
(
node
[
'href'
])
return
unless
uri
.
scheme
# Remove all invalid scheme characters before checking against the
# list of unsafe protocols.
#
# See https://tools.ietf.org/html/rfc3986#section-3.1
scheme
=
uri
.
scheme
.
strip
.
downcase
.
gsub
(
/[^A-Za-z0-9\+\.\-]+/
,
''
)
node
.
remove_attribute
(
'href'
)
if
UNSAFE_PROTOCOLS
.
include?
(
scheme
)
rescue
Addressable
::
URI
::
InvalidURIError
node
.
remove_attribute
(
'href'
)
end
end
end
def
remove_rel
lambda
do
|
env
|
if
env
[
:node_name
]
==
'a'
env
[
:node
].
remove_attribute
(
'rel'
)
end
end
end
def
remove_unsafe_table_style
def
remove_unsafe_table_style
lambda
do
|
env
|
lambda
do
|
env
|
node
=
env
[
:node
]
node
=
env
[
:node
]
...
...
lib/banzai/pipeline/ascii_doc_pipeline.rb
View file @
a546b9fb
...
@@ -5,7 +5,7 @@ module Banzai
...
@@ -5,7 +5,7 @@ module Banzai
class
AsciiDocPipeline
<
BasePipeline
class
AsciiDocPipeline
<
BasePipeline
def
self
.
filters
def
self
.
filters
FilterArray
[
FilterArray
[
Filter
::
SanitizationFilter
,
Filter
::
AsciiDoc
SanitizationFilter
,
Filter
::
SyntaxHighlightFilter
,
Filter
::
SyntaxHighlightFilter
,
Filter
::
ExternalLinkFilter
,
Filter
::
ExternalLinkFilter
,
Filter
::
PlantumlFilter
,
Filter
::
PlantumlFilter
,
...
...
spec/lib/gitlab/asciidoc_spec.rb
View file @
a546b9fb
...
@@ -45,28 +45,117 @@ module Gitlab
...
@@ -45,28 +45,117 @@ module Gitlab
end
end
context
"XSS"
do
context
"XSS"
do
link
s
=
{
item
s
=
{
'link
s
'
=>
{
'link
with extra attribute
'
=>
{
input:
'link:mylink"onmouseover="alert(1)[Click Here]'
,
input:
'link:mylink"onmouseover="alert(1)[Click Here]'
,
output:
"<div>
\n
<p><a href=
\"
mylink
\"
>Click Here</a></p>
\n
</div>"
output:
"<div>
\n
<p><a href=
\"
mylink
\"
>Click Here</a></p>
\n
</div>"
},
},
'images'
=>
{
'link with unsafe scheme'
=>
{
input:
'link:data://danger[Click Here]'
,
output:
"<div>
\n
<p><a>Click Here</a></p>
\n
</div>"
},
'image with onerror'
=>
{
input:
'image:https://localhost.com/image.png[Alt text" onerror="alert(7)]'
,
input:
'image:https://localhost.com/image.png[Alt text" onerror="alert(7)]'
,
output:
"<div>
\n
<p><span><img src=
\"
https://localhost.com/image.png
\"
alt='Alt text
\"
onerror=
\"
alert(7)'></span></p>
\n
</div>"
output:
"<div>
\n
<p><span><img src=
\"
https://localhost.com/image.png
\"
alt='Alt text
\"
onerror=
\"
alert(7)'></span></p>
\n
</div>"
},
},
'
pre
'
=>
{
'
fenced code with inline script
'
=>
{
input:
'```mypre"><script>alert(3)</script>'
,
input:
'```mypre"><script>alert(3)</script>'
,
output:
"<div>
\n
<div>
\n
<pre class=
\"
code highlight js-syntax-highlight plaintext
\"
lang=
\"
plaintext
\"
v-pre=
\"
true
\"
><code><span id=
\"
LC1
\"
class=
\"
line
\"
lang=
\"
plaintext
\"
>
\"
></span></code></pre>
\n
</div>
\n
</div>"
output:
"<div>
\n
<div>
\n
<pre class=
\"
code highlight js-syntax-highlight plaintext
\"
lang=
\"
plaintext
\"
v-pre=
\"
true
\"
><code><span id=
\"
LC1
\"
class=
\"
line
\"
lang=
\"
plaintext
\"
>
\"
></span></code></pre>
\n
</div>
\n
</div>"
}
}
}
}
link
s
.
each
do
|
name
,
data
|
item
s
.
each
do
|
name
,
data
|
it
"does not convert dangerous
#{
name
}
into HTML"
do
it
"does not convert dangerous
#{
name
}
into HTML"
do
expect
(
render
(
data
[
:input
],
context
)).
to
include
(
data
[
:output
])
expect
(
render
(
data
[
:input
],
context
)).
to
include
(
data
[
:output
])
end
end
end
end
end
end
context
'with admonition'
do
it
'preserves classes'
do
input
=
<<~
ADOC
NOTE: An admonition paragraph, like this note, grabs the reader’s attention.
ADOC
output
=
<<~
HTML
<div class="admonitionblock">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td>
An admonition paragraph, like this note, grabs the reader’s attention.
</td>
</tr>
</table>
</div>
HTML
expect
(
render
(
input
,
context
)).
to
include
(
output
.
strip
)
end
end
context
'with checklist'
do
it
'preserves classes'
do
input
=
<<~
ADOC
* [x] checked
* [ ] not checked
ADOC
output
=
<<~
HTML
<div>
<ul class="checklist">
<li>
<p><i class="fa fa-check-square-o"></i> checked</p>
</li>
<li>
<p><i class="fa fa-square-o"></i> not checked</p>
</li>
</ul>
</div>
HTML
expect
(
render
(
input
,
context
)).
to
include
(
output
.
strip
)
end
end
context
'with marks'
do
it
'preserves classes'
do
input
=
<<~
ADOC
Werewolves are allergic to #cassia cinnamon#.
Did the werewolves read the [.small]#small print#?
Where did all the [.underline.small]#cores# run off to?
We need [.line-through]#ten# make that twenty VMs.
[.big]##O##nce upon an infinite loop.
ADOC
output
=
<<~
HTML
<div>
<p>Werewolves are allergic to <mark>cassia cinnamon</mark>.</p>
</div>
<div>
<p>Did the werewolves read the <span class="small">small print</span>?</p>
</div>
<div>
<p>Where did all the <span class="underline small">cores</span> run off to?</p>
</div>
<div>
<p>We need <span class="line-through">ten</span> make that twenty VMs.</p>
</div>
<div>
<p><span class="big">O</span>nce upon an infinite loop.</p>
</div>
HTML
expect
(
render
(
input
,
context
)).
to
include
(
output
.
strip
)
end
end
context
'with fenced block'
do
context
'with fenced block'
do
it
'highlights syntax'
do
it
'highlights syntax'
do
input
=
<<~
ADOC
input
=
<<~
ADOC
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment