antisamy 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. data/CHANGELOG.rdoc +13 -0
  2. data/LICENSE.txt +20 -20
  3. data/README.rdoc +41 -41
  4. data/lib/antisamy.rb +46 -46
  5. data/lib/antisamy/css/css_filter.rb +187 -187
  6. data/lib/antisamy/css/css_scanner.rb +84 -84
  7. data/lib/antisamy/css/css_validator.rb +128 -128
  8. data/lib/antisamy/csspool/rsac.rb +1 -1
  9. data/lib/antisamy/csspool/rsac/sac.rb +14 -14
  10. data/lib/antisamy/csspool/rsac/sac/conditions.rb +5 -5
  11. data/lib/antisamy/csspool/rsac/sac/conditions/attribute_condition.rb +50 -50
  12. data/lib/antisamy/csspool/rsac/sac/conditions/begin_hyphen_condition.rb +18 -18
  13. data/lib/antisamy/csspool/rsac/sac/conditions/class_condition.rb +18 -18
  14. data/lib/antisamy/csspool/rsac/sac/conditions/combinator_condition.rb +36 -36
  15. data/lib/antisamy/csspool/rsac/sac/conditions/condition.rb +29 -29
  16. data/lib/antisamy/csspool/rsac/sac/conditions/id_condition.rb +23 -23
  17. data/lib/antisamy/csspool/rsac/sac/conditions/one_of_condition.rb +18 -18
  18. data/lib/antisamy/csspool/rsac/sac/conditions/pseudo_class_condition.rb +20 -20
  19. data/lib/antisamy/csspool/rsac/sac/document_handler.rb +66 -66
  20. data/lib/antisamy/csspool/rsac/sac/error_handler.rb +13 -13
  21. data/lib/antisamy/csspool/rsac/sac/generated_parser.rb +1012 -1012
  22. data/lib/antisamy/csspool/rsac/sac/generated_property_parser.rb +9284 -9284
  23. data/lib/antisamy/csspool/rsac/sac/lexeme.rb +27 -27
  24. data/lib/antisamy/csspool/rsac/sac/lexical_unit.rb +201 -201
  25. data/lib/antisamy/csspool/rsac/sac/parse_exception.rb +4 -4
  26. data/lib/antisamy/csspool/rsac/sac/parser.rb +109 -109
  27. data/lib/antisamy/csspool/rsac/sac/property_parser.rb +44 -44
  28. data/lib/antisamy/csspool/rsac/sac/selectors.rb +5 -5
  29. data/lib/antisamy/csspool/rsac/sac/selectors/child_selector.rb +36 -36
  30. data/lib/antisamy/csspool/rsac/sac/selectors/conditional_selector.rb +45 -45
  31. data/lib/antisamy/csspool/rsac/sac/selectors/descendant_selector.rb +36 -36
  32. data/lib/antisamy/csspool/rsac/sac/selectors/element_selector.rb +35 -35
  33. data/lib/antisamy/csspool/rsac/sac/selectors/selector.rb +25 -25
  34. data/lib/antisamy/csspool/rsac/sac/selectors/sibling_selector.rb +35 -35
  35. data/lib/antisamy/csspool/rsac/sac/selectors/simple_selector.rb +21 -21
  36. data/lib/antisamy/csspool/rsac/sac/token.rb +25 -25
  37. data/lib/antisamy/csspool/rsac/sac/tokenizer.rb +185 -185
  38. data/lib/antisamy/csspool/rsac/stylesheet.rb +3 -3
  39. data/lib/antisamy/csspool/rsac/stylesheet/rule.rb +20 -20
  40. data/lib/antisamy/csspool/rsac/stylesheet/stylesheet.rb +76 -76
  41. data/lib/antisamy/html/handler.rb +112 -99
  42. data/lib/antisamy/html/sax_filter.rb +305 -302
  43. data/lib/antisamy/html/scanner.rb +47 -43
  44. data/lib/antisamy/model/attribute.rb +19 -19
  45. data/lib/antisamy/model/css_property.rb +39 -39
  46. data/lib/antisamy/model/tag.rb +31 -31
  47. data/lib/antisamy/policy.rb +577 -545
  48. data/lib/antisamy/scan_results.rb +89 -89
  49. data/spec/antisamy_spec.rb +208 -142
  50. data/spec/spec_helper.rb +12 -12
  51. metadata +79 -81
@@ -1,89 +1,89 @@
1
- module AntiSamy
2
- class ScanError < StandardError; end
3
- # Scan message, it will contain a message key, tag and optionally content, value
4
- class ScanMessage
5
- # error.tag.notfound
6
- ERROR_TAG_NOT_IN_POLICY = "error.tag.notfound"
7
- # error.tag.removed
8
- ERROR_TAG_DISALLOWED = "error.tag.removed"
9
- # error.tag.filtered
10
- ERROR_TAG_FILTERED = "error.tag.filtered"
11
- # error.tag.encoded
12
- ERROR_TAG_ENCODED = "error.tag.encoded"
13
- # error.css.tag.malformed
14
- ERROR_CSS_TAG_MALFORMED = "error.css.tag.malformed"
15
- # error.css.attribute.malformed
16
- ERROR_CSS_ATTRIBUTE_MALFORMED = "error.css.attribute.malformed"
17
- # error.attribute.invalid.filtered
18
- ERROR_ATTRIBUTE_CAUSE_FILTER = "error.attribute.invalid.filtered"
19
- # error.attribute.invalid.encoded
20
- ERROR_ATTRIBUTE_CAUSE_ENCODE = "error.attribute.invalid.encoded"
21
- # error.attribute.invalid.filtered
22
- ERROR_ATTRIBUTE_INVALID_FILTERED = "error.attribute.invalid.filtered"
23
- # error.attribute.invalid.removed
24
- ERROR_ATTRIBUTE_INVALID_REMOVED = "error.attribute.invalid.removed"
25
- # error.attribute.notfound
26
- ERROR_ATTRIBUTE_NOT_IN_POLICY = "error.attribute.notfound"
27
- # error.attribute.invalid
28
- ERROR_ATTRIBUTE_INVALID = "error.attribute.invalid"
29
- # comment removed
30
- ERROR_COMMENT_REMOVED = "error.comment.removed"
31
- # tag rule not found
32
- ERROR_CSS_TAG_RULE_NOTFOUND = "error.css.tag.notfound"
33
- # style sheet nto found
34
- ERROR_STYLESHEET_RULE_NOTFOUND = "error.stylesheet.notfound"
35
- # embedded stylesheets disabled
36
- ERROR_CSS_IMPORT_DISABLED = "error.css.import.disabled"
37
- # bad uri
38
- ERROR_CSS_IMPORT_URL_INVALID = "error.css.import.uri.invalid"
39
- # disallowed selector
40
- ERROR_CSS_TAG_SELECTOR_DISALLOWED = "error.css.tag.removed"
41
- # invalid for style sheet
42
- ERROR_STYLESHEET_SELECTOR_DISALLOWED = "error.style.tag.notallowed"
43
- # invlaid css tag property
44
- ERROR_CSS_TAG_PROPERTY_INVALID = "error.css.property.invalid"
45
- # invid style sheet roperty tag
46
- ERROR_STYLESHEET_PROPERTY_INVALID = "error.stylesheet.css.property.invalid"
47
- # exceed alloted imports
48
- ERROR_CSS_IMPORT_EXCEEDED = "error.import.exceeded.sheets"
49
- # exceede size
50
- ERROR_CSS_IMPORT_INPUT_SIZE = "error.import.exceeded.size"
51
- # Failed to import
52
- ERROR_CSS_IMPORT_FAILURE = "error.import.bad.uri"
53
- # selector not found
54
- ERROR_STYLESHEET_SELECTOR_NOTFOUND = "error.css.stylesheet.selector.notfound"
55
- # selector in css not fond
56
- ERROR_CSS_TAG_SELECTOR_NOTFOUND = "error.css.tag.selector.notfound"
57
-
58
- attr_reader :tag, :content, :value, :msgkey
59
- def initialize(msgkey, tag, content=nil,value=nil)
60
- @msgkey = msgkey
61
- @tag = tag
62
- @content = content
63
- @value = value
64
- end
65
- def to_s
66
- "#{self.msgkey} #{@tag} #{@content} #{@value}"
67
- end
68
- end
69
-
70
- # Container of scan results, provides a list of ScanMessage indicating
71
- # why elements were removed from the resulting html
72
- class ScanResults
73
- attr_reader :scan_start, :scan_end
74
- attr_accessor :messages, :clean_html
75
- def initialize(scan_start,scan_end = nil)
76
- @errors = []
77
- @scan_start = scan_start
78
- @scan_end = scan_end
79
- @clean_html = ''
80
- end
81
-
82
- # Get the calculated scan time
83
- def scan_time
84
- @scan_end ||= Time.now
85
- (@scan_end - @scan_start).round(2)
86
- end
87
-
88
- end
89
- end
1
+ module AntiSamy
2
+ class ScanError < StandardError; end
3
+ # Scan message, it will contain a message key, tag and optionally content, value
4
+ class ScanMessage
5
+ # error.tag.notfound
6
+ ERROR_TAG_NOT_IN_POLICY = "error.tag.notfound"
7
+ # error.tag.removed
8
+ ERROR_TAG_DISALLOWED = "error.tag.removed"
9
+ # error.tag.filtered
10
+ ERROR_TAG_FILTERED = "error.tag.filtered"
11
+ # error.tag.encoded
12
+ ERROR_TAG_ENCODED = "error.tag.encoded"
13
+ # error.css.tag.malformed
14
+ ERROR_CSS_TAG_MALFORMED = "error.css.tag.malformed"
15
+ # error.css.attribute.malformed
16
+ ERROR_CSS_ATTRIBUTE_MALFORMED = "error.css.attribute.malformed"
17
+ # error.attribute.invalid.filtered
18
+ ERROR_ATTRIBUTE_CAUSE_FILTER = "error.attribute.invalid.filtered"
19
+ # error.attribute.invalid.encoded
20
+ ERROR_ATTRIBUTE_CAUSE_ENCODE = "error.attribute.invalid.encoded"
21
+ # error.attribute.invalid.filtered
22
+ ERROR_ATTRIBUTE_INVALID_FILTERED = "error.attribute.invalid.filtered"
23
+ # error.attribute.invalid.removed
24
+ ERROR_ATTRIBUTE_INVALID_REMOVED = "error.attribute.invalid.removed"
25
+ # error.attribute.notfound
26
+ ERROR_ATTRIBUTE_NOT_IN_POLICY = "error.attribute.notfound"
27
+ # error.attribute.invalid
28
+ ERROR_ATTRIBUTE_INVALID = "error.attribute.invalid"
29
+ # comment removed
30
+ ERROR_COMMENT_REMOVED = "error.comment.removed"
31
+ # tag rule not found
32
+ ERROR_CSS_TAG_RULE_NOTFOUND = "error.css.tag.notfound"
33
+ # style sheet nto found
34
+ ERROR_STYLESHEET_RULE_NOTFOUND = "error.stylesheet.notfound"
35
+ # embedded stylesheets disabled
36
+ ERROR_CSS_IMPORT_DISABLED = "error.css.import.disabled"
37
+ # bad uri
38
+ ERROR_CSS_IMPORT_URL_INVALID = "error.css.import.uri.invalid"
39
+ # disallowed selector
40
+ ERROR_CSS_TAG_SELECTOR_DISALLOWED = "error.css.tag.removed"
41
+ # invalid for style sheet
42
+ ERROR_STYLESHEET_SELECTOR_DISALLOWED = "error.style.tag.notallowed"
43
+ # invlaid css tag property
44
+ ERROR_CSS_TAG_PROPERTY_INVALID = "error.css.property.invalid"
45
+ # invid style sheet roperty tag
46
+ ERROR_STYLESHEET_PROPERTY_INVALID = "error.stylesheet.css.property.invalid"
47
+ # exceed alloted imports
48
+ ERROR_CSS_IMPORT_EXCEEDED = "error.import.exceeded.sheets"
49
+ # exceede size
50
+ ERROR_CSS_IMPORT_INPUT_SIZE = "error.import.exceeded.size"
51
+ # Failed to import
52
+ ERROR_CSS_IMPORT_FAILURE = "error.import.bad.uri"
53
+ # selector not found
54
+ ERROR_STYLESHEET_SELECTOR_NOTFOUND = "error.css.stylesheet.selector.notfound"
55
+ # selector in css not fond
56
+ ERROR_CSS_TAG_SELECTOR_NOTFOUND = "error.css.tag.selector.notfound"
57
+
58
+ attr_reader :tag, :content, :value, :msgkey
59
+ def initialize(msgkey, tag, content=nil,value=nil)
60
+ @msgkey = msgkey
61
+ @tag = tag
62
+ @content = content
63
+ @value = value
64
+ end
65
+ def to_s
66
+ "#{self.msgkey} #{@tag} #{@content} #{@value}"
67
+ end
68
+ end
69
+
70
+ # Container of scan results, provides a list of ScanMessage indicating
71
+ # why elements were removed from the resulting html
72
+ class ScanResults
73
+ attr_reader :scan_start, :scan_end
74
+ attr_accessor :messages, :clean_html
75
+ def initialize(scan_start,scan_end = nil)
76
+ @errors = []
77
+ @scan_start = scan_start
78
+ @scan_end = scan_end
79
+ @clean_html = ''
80
+ end
81
+
82
+ # Get the calculated scan time
83
+ def scan_time
84
+ @scan_end ||= Time.now
85
+ (@scan_end - @scan_start).round(2)
86
+ end
87
+
88
+ end
89
+ end
@@ -1,142 +1,208 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
-
3
- module AntiSamy
4
- describe AntiSamy do
5
- let(:policy_file) {"#{File.join(File.dirname(__FILE__), '..', 'policy-examples')}/antisamy-testing.xml"}
6
- let(:strict_policy) {"#{File.join(File.dirname(__FILE__), '..', 'policy-examples')}/antisamy-anythinggoes.xml"}
7
- let(:policy_object) {AntiSamy.policy(policy_file)}
8
-
9
- it "should load a policy" do
10
- p = AntiSamy.policy(policy_file)
11
- p.should_not == nil
12
- end
13
-
14
- it "should scan our sample html and change nothing" do
15
- input = "<p>Hi</p>"
16
- p = AntiSamy.policy(policy_file)
17
- r = AntiSamy.scan(input,p)
18
- r.clean_html.should == input
19
- end
20
-
21
- it "should tak our input and remove the script tags" do
22
- input = "<p style='font-size: 16px'>Hi</p><script> some junk</script>"
23
- expec = "<p>Hi</p>"
24
- p = AntiSamy.policy(policy_file)
25
- r = AntiSamy.scan(input,p)
26
- r.clean_html.should == expec
27
- r.messages.size.should == 2 # error 1 for script tag, error 2 for style tag
28
- end
29
-
30
- # Script attacks
31
- {
32
- "test<script>alert(document.cookie)</script>" => "script",
33
- "<<<><<script src=http://fake-evil.ru/test.js>" => "<script",
34
- "<script<script src=http://fake-evil.ru/test.js>>" => "<script",
35
- "<SCRIPT/XSS SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>" => "<script",
36
- '<BODY onload!#$%&()*~+-_.,:;?@[/|\\]^`=alert(\"XSS\")>' => "onload",
37
- "<BODY ONLOAD=alert('XSS')>" => "alert",
38
- "<iframe src=http://ha.ckers.org/scriptlet.html <" => "<iframe",
39
- "<INPUT TYPE=\"IMAGE\" SRC=\"javascript:alert('XSS');\">" => "src"
40
- }.each_pair do |k,v|
41
- it "should remove #{v} from #{k} for script attacks" do
42
- r = AntiSamy.scan(k,policy_object)
43
- r.clean_html.should_not include(v)
44
- end
45
- end
46
-
47
- #Image Attacks
48
- {
49
- "<img src='http://www.myspace.com/img.gif'>"=>"<img",
50
- "<img src=javascript:alert(document.cookie)>"=>"<img",
51
- "<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>"=>"<img",
52
- "<IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>" => "&amp;",
53
- "<IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>"=>"&amp;",
54
- "<IMG SRC=\"jav&#x0D;ascript:alert('XSS');\">" => "alert",
55
- "<IMG SRC=\"javascript:alert('XSS')\"" => "javascript",
56
- "<IMG LOWSRC=\"javascript:alert('XSS')\">"=>"javascript",
57
- "<BGSOUND SRC=\"javascript:alert('XSS');\">"=>"javascript",
58
- }.each_pair do |k,v|
59
- it "should remove #{v} from #{k} for image attacks" do
60
- r = AntiSamy.scan(k,policy_object)
61
- r.clean_html.should_not include(v)
62
- end
63
- end
64
-
65
- # Css attacks
66
- {
67
- "<div style=\"position:absolute\">" => "position",
68
- "<style>b { position:absolute }</style>" => "position",
69
- "<div style=\"z-index:25\">" => "z-index",
70
- "<style>z-index:25</style>" => "z-index",
71
- "<div style=\"font-family: Geneva, Arial, courier new, sans-serif\">" => "font-family"
72
- }.each_pair do |k,v|
73
- it "should remove #{v} from #{k} for CSS attacks" do
74
- r = AntiSamy.scan(k,policy_object)
75
- r.clean_html.should_not include(v)
76
- end
77
- end
78
-
79
- #href attacks
80
- {
81
- "<LINK REL=\"stylesheet\" HREF=\"javascript:alert('XSS');\">" => "href",
82
- "<LINK REL=\"stylesheet\" HREF=\"http://ha.ckers.org/xss.css\">" => "href",
83
- "<STYLE>@import'http://ha.ckers.org/xss.css';</STYLE>" => "ha.ckers",
84
- "<STYLE>BODY{-moz-binding:url(\"http://ha.ckers.org/xssmoz.xml#xss\")}</STYLE>" => "ha.ckers",
85
- "<STYLE>BODY{-moz-binding:url(\"http://ha.ckers.org/xssmoz.xml#xss\")}</STYLE>" => "xss",
86
- "<STYLE>li {list-style-image: url(\"javascript:alert('XSS')\");}</STYLE><UL><LI>XSS" => "javascript",
87
- "<IMG SRC='vbscript:msgbox(\"XSS\")'>" => "vbscript",
88
- "<a . href=\"http://www.test.com\">" => " . ",
89
- "<a - href=\"http://www.test.com\">" => "-",
90
- "<META HTTP-EQUIV=\"refresh\" CONTENT=\"0; URL=http://;URL=javascript:alert('XSS');\">" => "meta",
91
- "<META HTTP-EQUIV=\"refresh\" CONTENT=\"0;url=javascript:alert('XSS');\">" => "meta",
92
- "<META HTTP-EQUIV=\"refresh\" CONTENT=\"0;url=data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K\">" => "meta",
93
- "<IFRAME SRC=\"javascript:alert('XSS');\"></IFRAME>" => "iframe",
94
- "<FRAMESET><FRAME SRC=\"javascript:alert('XSS');\"></FRAMESET>" => "javascript",
95
- "<TABLE BACKGROUND=\"javascript:alert('XSS')\">" => "background",
96
- "<TABLE><TD BACKGROUND=\"javascript:alert('XSS')\">" => "background",
97
- "<DIV STYLE=\"background-image: url(javascript:alert('XSS'))\">" => "javascript",
98
- "<DIV STYLE=\"width: expression(alert('XSS'));\">" => "alert",
99
- "<IMG STYLE=\"xss:expr/*XSS*/ession(alert('XSS'))\">" => "alert",
100
- "<STYLE>@im\\port'\\ja\\vasc\\ript:alert(\"XSS\")';</STYLE>" => "alert",
101
- "<BASE HREF=\"javascript:alert('XSS');//\">" => "javascript",
102
- "<BaSe hReF=\"http://arbitrary.com/\">" => "base",
103
- "<OBJECT TYPE=\"text/x-scriptlet\" DATA=\"http://ha.ckers.org/scriptlet.html\"></OBJECT>" => "object",
104
- "<OBJECT classid=clsid:ae24fdae-03c6-11d1-8b76-0080c744f389><param name=url value=javascript:alert('XSS')></OBJECT>" => "object",
105
- "<EMBED SRC=\"http://ha.ckers.org/xss.swf\" AllowScriptAccess=\"always\"></EMBED>" => "embed",
106
- "<EMBED SRC=\"data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==\" type=\"image/svg+xml\" AllowScriptAccess=\"always\"></EMBED>" => "embed",
107
- "<SCRIPT a=\">\" SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>" => "script",
108
- "<SCRIPT a=\">\" '' SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>" => "script",
109
- "<SCRIPT a=`>` SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>" => "script",
110
- "<SCRIPT a=\">'>\" SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>" => "script",
111
- "<SCRIPT>document.write(\"<SCRI\");</SCRIPT>PT SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>" => "script",
112
- "<SCRIPT SRC=http://ha.ckers.org/xss.js" => "script",
113
- "<div/style=&#92&#45&#92&#109&#111&#92&#122&#92&#45&#98&#92&#105&#92&#110&#100&#92&#105&#110&#92&#103:&#92&#117&#114&#108&#40&#47&#47&#98&#117&#115&#105&#110&#101&#115&#115&#92&#105&#92&#110&#102&#111&#46&#99&#111&#46&#117&#107&#92&#47&#108&#97&#98&#115&#92&#47&#120&#98&#108&#92&#47&#120&#98&#108&#92&#46&#120&#109&#108&#92&#35&#120&#115&#115&#41&>" => "style",
114
- "<a href='aim: &c:\\windows\\system32\\calc.exe' ini='C:\\Documents and Settings\\All Users\\Start Menu\\Programs\\Startup\\pwnd.bat'>" => "calc.exe",
115
- "<!--\n<A href=\n- --><a href=javascript:alert:document.domain>test-->" => "javascript",
116
- "<a></a style=\"\"xx:expr/**/ession(document.appendChild(document.createElement('script')).src='http://h4k.in/i.js')\">" => "<a style=",
117
- "<a onblur=\"alert(secret)\" href=\"http://www.google.com\">Google</a>" => "blur",
118
- "<b><i>Some Text</b></i>" => "<i />",
119
- "<div style=\"font-family: Geneva, Arial, courier new, sans-serif\">" => "font-family",
120
- "<style type=\"text/css\"><![CDATA[P { margin-bottom: 0.08in; } ]]></style>" => "margin"
121
-
122
- }.each_pair do |k,v|
123
- it "should remove #{v} from #{k} for href attacks" do
124
- r = AntiSamy.scan(k,policy_object)
125
- r.clean_html.should_not include(v)
126
- end
127
- end
128
-
129
- it "shoud import some stylesheets" do
130
- input = "<style>@import url(http://www.owasp.org/skins/monobook/main.css);@import url(http://www.w3schools.com/stdtheme.css);@import url(http://www.google.com/ig/f/t1wcX5O39cc/ig.css); </style>"
131
- r = AntiSamy.scan(input,policy_object)
132
- r.clean_html.should_not be_empty
133
- end
134
-
135
- it "should not touch this url" do
136
- input = "<a href=\"http://www.aspectsecurity.com\">Aspect Security</a>"
137
- r = AntiSamy.scan(input,policy_object)
138
- r.clean_html.should == input
139
- end
140
-
141
- end
142
- end
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ module AntiSamy
4
+ describe AntiSamy do
5
+ let(:policy_file) {"#{File.join(File.dirname(__FILE__), '..', 'policy-examples')}/antisamy-testing.xml"}
6
+ let(:strict_policy) {"#{File.join(File.dirname(__FILE__), '..', 'policy-examples')}/antisamy-anythinggoes.xml"}
7
+ let(:policy_object) {AntiSamy.policy(policy_file)}
8
+
9
+ it "should load a policy" do
10
+ p = AntiSamy.policy(policy_file)
11
+ p.should_not == nil
12
+ end
13
+
14
+ it "should handle a missing head tag in a full document" do
15
+ input =<<-HTML
16
+ <html>
17
+ <body>some text</body>
18
+ </html>
19
+ HTML
20
+ p = AntiSamy.policy(policy_file)
21
+ r = AntiSamy.scan(input,p)
22
+ r.clean_html.gsub(/\n/,'').should == input.gsub(/\t|\n/,'')
23
+ end
24
+
25
+ it "should handle a document and keep the html tag" do
26
+ input =<<-HTML
27
+ <html>
28
+ <head><title>sup</title></head>
29
+ <body>some text</body>
30
+ </html>
31
+ HTML
32
+ p = AntiSamy.policy(policy_file)
33
+ r = AntiSamy.scan(input,p)
34
+ r.clean_html.gsub(/\n/,'').should == input.gsub(/\t|\n/,'')
35
+ end
36
+
37
+ it "should allow empty tags" do
38
+ input =<<-HTML
39
+ <html>
40
+ <head><title>sup</title></head>
41
+ <body>some text<br><div></div></body>
42
+ </html>
43
+ HTML
44
+ p = AntiSamy.policy(policy_file)
45
+ r = AntiSamy.scan(input,p)
46
+ r.clean_html.gsub(/\n/,'').should == input.gsub(/\t|\n/,'')
47
+ end
48
+
49
+ it "shoulw remove an empty tag as per the poilicy" do
50
+ input =<<-HTML
51
+ <html>
52
+ <head><title>sup</title></head>
53
+ <body>some text<br><h2/></body>
54
+ </html>
55
+ HTML
56
+ expect =<<-HTML
57
+ <html>
58
+ <head><title>sup</title></head>
59
+ <body>some text<br></body>
60
+ </html>
61
+ HTML
62
+ p = AntiSamy.policy(policy_file)
63
+ r = AntiSamy.scan(input,p)
64
+ r.clean_html.gsub(/\n/,'').should == expect.gsub(/\t|\n/,'')
65
+ end
66
+
67
+ it "should wrap plain text" do
68
+ input = "Hi"
69
+ p = AntiSamy.policy(policy_file)
70
+ r = AntiSamy.scan(input,p)
71
+ r.clean_html.should == "<p>#{input}</p>"
72
+ end
73
+
74
+ it "should scan our sample html and change nothing" do
75
+ input = "<p>Hi</p>"
76
+ p = AntiSamy.policy(policy_file)
77
+ r = AntiSamy.scan(input,p)
78
+ r.clean_html.should == input
79
+ end
80
+
81
+ it "should tak our input and remove the script tags" do
82
+ input = "<p style='font-size: 16px'>Hi</p><script> some junk</script>"
83
+ expec = "<p>Hi</p>"
84
+ p = AntiSamy.policy(policy_file)
85
+ r = AntiSamy.scan(input,p)
86
+ r.clean_html.should == expec
87
+ r.messages.size.should == 2 # error 1 for script tag, error 2 for style tag
88
+ end
89
+
90
+ # Script attacks
91
+ {
92
+ "test<script>alert(document.cookie)</script>" => "script",
93
+ "<<<><<script src=http://fake-evil.ru/test.js>" => "<script",
94
+ "<script<script src=http://fake-evil.ru/test.js>>" => "<script",
95
+ "<SCRIPT/XSS SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>" => "<script",
96
+ '<BODY onload!#$%&()*~+-_.,:;?@[/|\\]^`=alert(\"XSS\")>' => "onload",
97
+ "<BODY ONLOAD=alert('XSS')>" => "alert",
98
+ "<iframe src=http://ha.ckers.org/scriptlet.html <" => "<iframe",
99
+ "<INPUT TYPE=\"IMAGE\" SRC=\"javascript:alert('XSS');\">" => "src"
100
+ }.each_pair do |k,v|
101
+ it "should remove #{v} from #{k} for script attacks" do
102
+ r = AntiSamy.scan(k,policy_object)
103
+ r.clean_html.should_not include(v)
104
+ end
105
+ end
106
+
107
+ #Image Attacks
108
+ {
109
+ "<img src='http://www.myspace.com/img.gif'>"=>"<img",
110
+ "<img src=javascript:alert(document.cookie)>"=>"<img",
111
+ "<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>"=>"<img",
112
+ "<IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>" => "&amp;",
113
+ "<IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>"=>"&amp;",
114
+ "<IMG SRC=\"jav&#x0D;ascript:alert('XSS');\">" => "alert",
115
+ "<IMG SRC=\"javascript:alert('XSS')\"" => "javascript",
116
+ "<IMG LOWSRC=\"javascript:alert('XSS')\">"=>"javascript",
117
+ "<BGSOUND SRC=\"javascript:alert('XSS');\">"=>"javascript",
118
+ }.each_pair do |k,v|
119
+ it "should remove #{v} from #{k} for image attacks" do
120
+ r = AntiSamy.scan(k,policy_object)
121
+ r.clean_html.should_not include(v)
122
+ end
123
+ end
124
+
125
+ # Css attacks
126
+ {
127
+ "<div style=\"position:absolute\">" => "position",
128
+ "<style>b { position:absolute }</style>" => "position",
129
+ "<div style=\"z-index:25\">" => "z-index",
130
+ "<style>z-index:25</style>" => "z-index",
131
+ "<div style=\"font-family: Geneva, Arial, courier new, sans-serif\">" => "font-family"
132
+ }.each_pair do |k,v|
133
+ it "should remove #{v} from #{k} for CSS attacks" do
134
+ r = AntiSamy.scan(k,policy_object)
135
+ r.clean_html.should_not include(v)
136
+ end
137
+ end
138
+
139
+ #href attacks
140
+ {
141
+ "<LINK REL=\"stylesheet\" HREF=\"javascript:alert('XSS');\">" => "href",
142
+ "<LINK REL=\"stylesheet\" HREF=\"http://ha.ckers.org/xss.css\">" => "href",
143
+ "<STYLE>@import'http://ha.ckers.org/xss.css';</STYLE>" => "ha.ckers",
144
+ "<STYLE>BODY{-moz-binding:url(\"http://ha.ckers.org/xssmoz.xml#xss\")}</STYLE>" => "ha.ckers",
145
+ "<STYLE>BODY{-moz-binding:url(\"http://ha.ckers.org/xssmoz.xml#xss\")}</STYLE>" => "xss",
146
+ "<STYLE>li {list-style-image: url(\"javascript:alert('XSS')\");}</STYLE><UL><LI>XSS" => "javascript",
147
+ "<IMG SRC='vbscript:msgbox(\"XSS\")'>" => "vbscript",
148
+ "<a . href=\"http://www.test.com\">" => " . ",
149
+ "<a - href=\"http://www.test.com\">" => "-",
150
+ "<META HTTP-EQUIV=\"refresh\" CONTENT=\"0; URL=http://;URL=javascript:alert('XSS');\">" => "meta",
151
+ "<META HTTP-EQUIV=\"refresh\" CONTENT=\"0;url=javascript:alert('XSS');\">" => "meta",
152
+ "<META HTTP-EQUIV=\"refresh\" CONTENT=\"0;url=data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K\">" => "meta",
153
+ "<IFRAME SRC=\"javascript:alert('XSS');\"></IFRAME>" => "iframe",
154
+ "<FRAMESET><FRAME SRC=\"javascript:alert('XSS');\"></FRAMESET>" => "javascript",
155
+ "<TABLE BACKGROUND=\"javascript:alert('XSS')\">" => "background",
156
+ "<TABLE><TD BACKGROUND=\"javascript:alert('XSS')\">" => "background",
157
+ "<DIV STYLE=\"background-image: url(javascript:alert('XSS'))\">" => "javascript",
158
+ "<DIV STYLE=\"width: expression(alert('XSS'));\">" => "alert",
159
+ "<IMG STYLE=\"xss:expr/*XSS*/ession(alert('XSS'))\">" => "alert",
160
+ "<STYLE>@im\\port'\\ja\\vasc\\ript:alert(\"XSS\")';</STYLE>" => "alert",
161
+ "<BASE HREF=\"javascript:alert('XSS');//\">" => "javascript",
162
+ "<BaSe hReF=\"http://arbitrary.com/\">" => "base",
163
+ "<OBJECT TYPE=\"text/x-scriptlet\" DATA=\"http://ha.ckers.org/scriptlet.html\"></OBJECT>" => "object",
164
+ "<OBJECT classid=clsid:ae24fdae-03c6-11d1-8b76-0080c744f389><param name=url value=javascript:alert('XSS')></OBJECT>" => "object",
165
+ "<EMBED SRC=\"http://ha.ckers.org/xss.swf\" AllowScriptAccess=\"always\"></EMBED>" => "embed",
166
+ "<EMBED SRC=\"data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==\" type=\"image/svg+xml\" AllowScriptAccess=\"always\"></EMBED>" => "embed",
167
+ "<SCRIPT a=\">\" SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>" => "script",
168
+ "<SCRIPT a=\">\" '' SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>" => "script",
169
+ "<SCRIPT a=`>` SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>" => "script",
170
+ "<SCRIPT a=\">'>\" SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>" => "script",
171
+ "<SCRIPT>document.write(\"<SCRI\");</SCRIPT>PT SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>" => "script",
172
+ "<SCRIPT SRC=http://ha.ckers.org/xss.js" => "script",
173
+ "<div/style=&#92&#45&#92&#109&#111&#92&#122&#92&#45&#98&#92&#105&#92&#110&#100&#92&#105&#110&#92&#103:&#92&#117&#114&#108&#40&#47&#47&#98&#117&#115&#105&#110&#101&#115&#115&#92&#105&#92&#110&#102&#111&#46&#99&#111&#46&#117&#107&#92&#47&#108&#97&#98&#115&#92&#47&#120&#98&#108&#92&#47&#120&#98&#108&#92&#46&#120&#109&#108&#92&#35&#120&#115&#115&#41&>" => "style",
174
+ "<a href='aim: &c:\\windows\\system32\\calc.exe' ini='C:\\Documents and Settings\\All Users\\Start Menu\\Programs\\Startup\\pwnd.bat'>" => "calc.exe",
175
+ "<!--\n<A href=\n- --><a href=javascript:alert:document.domain>test-->" => "javascript",
176
+ "<a></a style=\"\"xx:expr/**/ession(document.appendChild(document.createElement('script')).src='http://h4k.in/i.js')\">" => "<a style=",
177
+ "<a onblur=\"alert(secret)\" href=\"http://www.google.com\">Google</a>" => "blur",
178
+ "<b><i>Some Text</b></i>" => "<i />",
179
+ "<div style=\"font-family: Geneva, Arial, courier new, sans-serif\">" => "font-family",
180
+ "<style type=\"text/css\"><![CDATA[P { margin-bottom: 0.08in; } ]]></style>" => "margin"
181
+
182
+ }.each_pair do |k,v|
183
+ it "should remove #{v} from #{k} for href attacks" do
184
+ r = AntiSamy.scan(k,policy_object)
185
+ r.clean_html.should_not include(v)
186
+ end
187
+ end
188
+
189
+ it "shoud import some stylesheets" do
190
+ input = "<style>@import url(http://www.owasp.org/skins/monobook/main.css);@import url(http://www.w3schools.com/stdtheme.css);@import url(http://www.google.com/ig/f/t1wcX5O39cc/ig.css); </style>"
191
+ r = AntiSamy.scan(input,policy_object)
192
+ r.clean_html.should_not be_empty
193
+ end
194
+
195
+ it "should not touch this url" do
196
+ input = "<a href=\"http://www.aspectsecurity.com\">Aspect Security</a>"
197
+ r = AntiSamy.scan(input,policy_object)
198
+ r.clean_html.should == input
199
+ end
200
+
201
+ it "should accept css3" do
202
+ input = "<style> div{transform:rotate(30deg);} </style>"
203
+ r = AntiSamy.scan(input,policy_object)
204
+ r.clean_html.should == input
205
+ end
206
+
207
+ end
208
+ end