1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
require 'action_view/helpers/tag_helper'
require 'html/document'
module ActionView
module Helpers #:nodoc:
# The SanitizeHelper module provides a set of methods for scrubbing text of undesired HTML elements.
# These helper methods extend ActionView making them callable within your template files.
module SanitizeHelper
def self.included(base)
base.extend(ClassMethods)
end
# This +sanitize+ helper will html encode all tags and strip all attributes that aren't specifically allowed.
# It also strips href/src tags with invalid protocols, like javascript: especially. It does its best to counter any
# tricks that hackers may use, like throwing in unicode/ascii/hex values to get past the javascript: filters. Check out
# the extensive test suite.
#
# <%= sanitize @article.body %>
#
# You can add or remove tags/attributes if you want to customize it a bit. See ActionView::Base for full docs on the
# available options. You can add tags/attributes for single uses of +sanitize+ by passing either the <tt>:attributes</tt> or <tt>:tags</tt> options:
#
# Normal Use
#
# <%= sanitize @article.body %>
#
# Custom Use (only the mentioned tags and attributes are allowed, nothing else)
#
# <%= sanitize @article.body, :tags => %w(table tr td), :attributes => %w(id class style)
#
# Add table tags to the default allowed tags
#
# Rails::Initializer.run do |config|
# config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td'
# end
#
# Remove tags to the default allowed tags
#
# Rails::Initializer.run do |config|
# config.after_initialize do
# ActionView::Base.sanitized_allowed_tags.delete 'div'
# end
# end
#
# Change allowed default attributes
#
# Rails::Initializer.run do |config|
# config.action_view.sanitized_allowed_attributes = 'id', 'class', 'style'
# end
#
# Please note that sanitizing user-provided text does not guarantee that the
# resulting markup is valid (conforming to a document type) or even well-formed.
# The output may still contain e.g. unescaped '<', '>', '&' characters and
# confuse browsers.
#
def sanitize(html, options = {})
self.class.white_list_sanitizer.sanitize(html, options)
end
# Sanitizes a block of CSS code. Used by +sanitize+ when it comes across a style attribute.
def sanitize_css(style)
self.class.white_list_sanitizer.sanitize_css(style)
end
# Strips all HTML tags from the +html+, including comments. This uses the
# html-scanner tokenizer and so its HTML parsing ability is limited by
# that of html-scanner.
#
# ==== Examples
#
# strip_tags("Strip <i>these</i> tags!")
# # => Strip these tags!
#
# strip_tags("<b>Bold</b> no more! <a href='more.html'>See more here</a>...")
# # => Bold no more! See more here...
#
# strip_tags("<div id='top-bar'>Welcome to my website!</div>")
# # => Welcome to my website!
def strip_tags(html)
self.class.full_sanitizer.sanitize(html)
end
# Strips all link tags from +text+ leaving just the link text.
#
# ==== Examples
# strip_links('<a href="http://www.rubyonrails.org">Ruby on Rails</a>')
# # => Ruby on Rails
#
# strip_links('Please e-mail me at <a href="mailto:me@email.com">me@email.com</a>.')
# # => Please e-mail me at me@email.com.
#
# strip_links('Blog: <a href="http://www.myblog.com/" class="nav" target=\"_blank\">Visit</a>.')
# # => Blog: Visit
def strip_links(html)
self.class.link_sanitizer.sanitize(html)
end
module ClassMethods #:nodoc:
def self.extended(base)
class << base
attr_writer :full_sanitizer, :link_sanitizer, :white_list_sanitizer
# we want these to be class methods on ActionView::Base, they'll get mattr_readers for these below.
helper_def = [:sanitized_protocol_separator, :sanitized_uri_attributes, :sanitized_bad_tags, :sanitized_allowed_tags,
:sanitized_allowed_attributes, :sanitized_allowed_css_properties, :sanitized_allowed_css_keywords,
:sanitized_shorthand_css_properties, :sanitized_allowed_protocols, :sanitized_protocol_separator=].collect! do |prop|
prop = prop.to_s
"def #{prop}(#{:value if prop =~ /=$/}) white_list_sanitizer.#{prop.sub /sanitized_/, ''} #{:value if prop =~ /=$/} end"
end.join("\n")
eval helper_def
end
end
# Gets the HTML::FullSanitizer instance used by +strip_tags+. Replace with
# any object that responds to +sanitize+.
#
# Rails::Initializer.run do |config|
# config.action_view.full_sanitizer = MySpecialSanitizer.new
# end
#
def full_sanitizer
@full_sanitizer ||= HTML::FullSanitizer.new
end
# Gets the HTML::LinkSanitizer instance used by +strip_links+. Replace with
# any object that responds to +sanitize+.
#
# Rails::Initializer.run do |config|
# config.action_view.link_sanitizer = MySpecialSanitizer.new
# end
#
def link_sanitizer
@link_sanitizer ||= HTML::LinkSanitizer.new
end
# Gets the HTML::WhiteListSanitizer instance used by sanitize and +sanitize_css+.
# Replace with any object that responds to +sanitize+.
#
# Rails::Initializer.run do |config|
# config.action_view.white_list_sanitizer = MySpecialSanitizer.new
# end
#
def white_list_sanitizer
@white_list_sanitizer ||= HTML::WhiteListSanitizer.new
end
# Adds valid HTML attributes that the +sanitize+ helper checks for URIs.
#
# Rails::Initializer.run do |config|
# config.action_view.sanitized_uri_attributes = 'lowsrc', 'target'
# end
#
def sanitized_uri_attributes=(attributes)
HTML::WhiteListSanitizer.uri_attributes.merge(attributes)
end
# Adds to the Set of 'bad' tags for the +sanitize+ helper.
#
# Rails::Initializer.run do |config|
# config.action_view.sanitized_bad_tags = 'embed', 'object'
# end
#
def sanitized_bad_tags=(attributes)
HTML::WhiteListSanitizer.bad_tags.merge(attributes)
end
# Adds to the Set of allowed tags for the +sanitize+ helper.
#
# Rails::Initializer.run do |config|
# config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td'
# end
#
def sanitized_allowed_tags=(attributes)
HTML::WhiteListSanitizer.allowed_tags.merge(attributes)
end
# Adds to the Set of allowed HTML attributes for the +sanitize+ helper.
#
# Rails::Initializer.run do |config|
# config.action_view.sanitized_allowed_attributes = 'onclick', 'longdesc'
# end
#
def sanitized_allowed_attributes=(attributes)
HTML::WhiteListSanitizer.allowed_attributes.merge(attributes)
end
# Adds to the Set of allowed CSS properties for the #sanitize and +sanitize_css+ heleprs.
#
# Rails::Initializer.run do |config|
# config.action_view.sanitized_allowed_css_properties = 'expression'
# end
#
def sanitized_allowed_css_properties=(attributes)
HTML::WhiteListSanitizer.allowed_css_properties.merge(attributes)
end
# Adds to the Set of allowed CSS keywords for the +sanitize+ and +sanitize_css+ helpers.
#
# Rails::Initializer.run do |config|
# config.action_view.sanitized_allowed_css_keywords = 'expression'
# end
#
def sanitized_allowed_css_keywords=(attributes)
HTML::WhiteListSanitizer.allowed_css_keywords.merge(attributes)
end
# Adds to the Set of allowed shorthand CSS properties for the +sanitize+ and +sanitize_css+ helpers.
#
# Rails::Initializer.run do |config|
# config.action_view.sanitized_shorthand_css_properties = 'expression'
# end
#
def sanitized_shorthand_css_properties=(attributes)
HTML::WhiteListSanitizer.shorthand_css_properties.merge(attributes)
end
# Adds to the Set of allowed protocols for the +sanitize+ helper.
#
# Rails::Initializer.run do |config|
# config.action_view.sanitized_allowed_protocols = 'ssh', 'feed'
# end
#
def sanitized_allowed_protocols=(attributes)
HTML::WhiteListSanitizer.allowed_protocols.merge(attributes)
end
end
end
end
end
|