| 1 31 package org.blojsom.plugin.filter; 32 33 import org.apache.commons.logging.Log; 34 import org.apache.commons.logging.LogFactory; 35 import org.blojsom.blog.Blog; 36 import org.blojsom.blog.Entry; 37 import org.blojsom.event.Event; 38 import org.blojsom.event.EventBroadcaster; 39 import org.blojsom.event.Listener; 40 import org.blojsom.plugin.Plugin; 41 import org.blojsom.plugin.PluginException; 42 import org.blojsom.plugin.admin.event.ProcessEntryEvent; 43 import org.blojsom.plugin.comment.event.CommentResponseSubmissionEvent; 44 import org.blojsom.util.BlojsomUtils; 45 46 import javax.servlet.http.HttpServletRequest ; 47 import javax.servlet.http.HttpServletResponse ; 48 import java.util.Map ; 49 import java.util.regex.Matcher ; 50 import java.util.regex.Pattern ; 51 52 59 public class XSSFilterPlugin implements Plugin, Listener { 60 61 private Log _logger = LogFactory.getLog(XSSFilterPlugin.class); 62 63 private static final String [] DEFAULT_ALLOWED_BALANCED_TAGS = {"b", "strong", "i", "em", "u", "s", "blockquote", "pre", "ul", "li", "ol"}; 65 private static final String [] DEFAULT_ALLOWED_UNBALANCED_TAGS = {"br", "img"}; 66 67 private static final String XSS_FILTER_ALLOWED_BALANCED_TAGS_IP = "plugin-xss-filter-allowed-balanced-tags"; 69 private static final String XSS_FILTER_ALLOWED_UNBALANCED_TAGS_IP = "plugin-xss-filter-allowed-unbalanced-tags"; 70 private static final String XSS_FILTER_ALLOW_LINKS_IP = "plugin-xss-filter-allow-links"; 71 private static final String XSS_FILTER_PROCESS_ENTRIES_IP = "plugin-xss-filter-process-entries"; 72 73 private static final String XSS_FILTER_ALLOWED_BALANCED_TAGS = "XSS_FILTER_ALLOWED_BALANCED_TAGS"; 75 private static final String XSS_FILTER_ALLOWED_UNBALANCED_TAGS = "XSS_FILTER_ALLOWED_UNBALANCED_TAGS"; 76 private static final String XSS_FILTER_ALLOW_LINKS = "XSS_FILTER_ALLOW_LINKS"; 77 78 private EventBroadcaster _eventBroadcaster; 79 80 85 public void setEventBroadcaster(EventBroadcaster eventBroadcaster) { 86 _eventBroadcaster = eventBroadcaster; 87 } 88 89 95 public void init() throws PluginException { 96 _eventBroadcaster.addListener(this); 97 } 98 99 110 public Entry[] process(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Blog blog, Map context, Entry[] entries) throws PluginException { 111 String allowedBalancedTagsIP = blog.getProperty(XSS_FILTER_ALLOWED_BALANCED_TAGS_IP); 113 String [] allowedBalancedTags = DEFAULT_ALLOWED_BALANCED_TAGS; 114 if (!BlojsomUtils.checkNullOrBlank(allowedBalancedTagsIP)) { 115 allowedBalancedTags = BlojsomUtils.parseCommaList(allowedBalancedTagsIP); 116 } 117 context.put(XSS_FILTER_ALLOWED_BALANCED_TAGS, allowedBalancedTags); 118 119 String allowedUnbalancedTagsIP = blog.getProperty(XSS_FILTER_ALLOWED_UNBALANCED_TAGS_IP); 120 String [] allowedUnbalancedTags = DEFAULT_ALLOWED_UNBALANCED_TAGS; 121 if (!BlojsomUtils.checkNullOrBlank(allowedUnbalancedTagsIP)) { 122 allowedUnbalancedTags = BlojsomUtils.parseCommaList(allowedUnbalancedTagsIP); 123 } 124 context.put(XSS_FILTER_ALLOWED_UNBALANCED_TAGS, allowedUnbalancedTags); 125 126 String allowLinksIP = blog.getProperty(XSS_FILTER_ALLOW_LINKS_IP); 127 Boolean allowLinks = Boolean.TRUE; 128 if (!BlojsomUtils.checkNullOrBlank(allowLinksIP)) { 129 allowLinks = Boolean.valueOf(allowLinksIP); 130 } 131 context.put(XSS_FILTER_ALLOW_LINKS, allowLinks); 132 133 return entries; 134 } 135 136 142 public void cleanup() throws PluginException { 143 } 144 145 151 public void destroy() throws PluginException { 152 } 153 154 159 public void handleEvent(Event event) { 160 } 161 162 167 public void processEvent(Event event) { 168 if (event instanceof CommentResponseSubmissionEvent) { 169 if (_logger.isDebugEnabled()) { 170 _logger.debug("Processing comment response submission event"); 171 } 172 173 CommentResponseSubmissionEvent commentEvent = (CommentResponseSubmissionEvent) event; 174 175 String commentText = commentEvent.getContent(); 176 commentText = processContent(commentText, commentEvent.getBlog()); 177 178 commentEvent.setContent(commentText); 180 } else if (event instanceof ProcessEntryEvent) { 181 ProcessEntryEvent entryEvent = (ProcessEntryEvent) event; 182 Blog blog = entryEvent.getBlog(); 183 184 if (Boolean.valueOf(blog.getProperty(XSS_FILTER_PROCESS_ENTRIES_IP)).booleanValue()) { 186 if (_logger.isDebugEnabled()) { 187 _logger.debug("Processing process blog entry event"); 188 } 189 190 if (entryEvent.getEntry() != null) { 191 String entryText = entryEvent.getEntry().getDescription(); 192 entryText = processContent(entryText, entryEvent.getBlog()); 193 194 entryEvent.getEntry().setDescription(entryText); 196 197 String entryTitle = entryEvent.getEntry().getTitle(); 198 entryTitle = processContent(entryTitle, entryEvent.getBlog()); 199 200 entryEvent.getEntry().setTitle(entryTitle); 202 } 203 } 204 } 205 } 206 207 214 protected String processContent(String content, Blog blog) { 215 String allowedBalancedTagsIP = blog.getProperty(XSS_FILTER_ALLOWED_BALANCED_TAGS_IP); 217 String [] allowedBalancedTags = DEFAULT_ALLOWED_BALANCED_TAGS; 218 if (!BlojsomUtils.checkNullOrBlank(allowedBalancedTagsIP)) { 219 allowedBalancedTags = BlojsomUtils.parseCommaList(allowedBalancedTagsIP); 220 } 221 222 String allowedUnbalancedTagsIP = blog.getProperty(XSS_FILTER_ALLOWED_UNBALANCED_TAGS_IP); 223 String [] allowedUnbalancedTags = DEFAULT_ALLOWED_UNBALANCED_TAGS; 224 if (!BlojsomUtils.checkNullOrBlank(allowedUnbalancedTagsIP)) { 225 allowedUnbalancedTags = BlojsomUtils.parseCommaList(allowedUnbalancedTagsIP); 226 } 227 228 String allowLinksIP = blog.getProperty(XSS_FILTER_ALLOW_LINKS_IP); 229 boolean allowLinks = true; 230 if (!BlojsomUtils.checkNullOrBlank(allowLinksIP)) { 231 allowLinks = Boolean.valueOf(allowLinksIP).booleanValue(); 232 } 233 234 content = BlojsomUtils.escapeStringSimple(content); 235 236 if (content != null) { 237 for (int i = 0; i < allowedBalancedTags.length; i++) { 239 String allowedBalancedTag = allowedBalancedTags[i]; 240 241 content = replaceBalancedTag(content, allowedBalancedTag); 242 } 243 244 for (int i = 0; i < allowedUnbalancedTags.length; i++) { 246 String allowedUnbalancedTag = allowedUnbalancedTags[i]; 247 248 content = replaceUnbalancedTag(content, allowedUnbalancedTag); 249 } 250 251 if (allowLinks) { 253 content = processLinks(content); 254 } 255 256 content = processImgTags(content); 257 258 content = content.replaceAll("&lt;", "<"); 260 content = content.replaceAll("&gt;", ">"); 261 content = content.replaceAll("&#", "&#"); 262 } 263 264 return content; 265 } 266 267 274 private String replaceBalancedTag(String input, String tag) { 275 Pattern openingPattern = Pattern.compile("<" + tag + ">", Pattern.CASE_INSENSITIVE); 276 Pattern closingPattern = Pattern.compile("</" + tag + ">", Pattern.CASE_INSENSITIVE); 277 278 Matcher openingMatcher = openingPattern.matcher(input); 279 input = openingMatcher.replaceAll("<" + tag + ">"); 280 281 Matcher closingMatcher = closingPattern.matcher(input); 282 input = closingMatcher.replaceAll("</" + tag + ">"); 283 284 return input; 285 } 286 287 294 private String replaceUnbalancedTag(String input, String tag) { 295 Pattern unbalancedPattern = Pattern.compile("<" + tag + "\\s*/*>", Pattern.CASE_INSENSITIVE); 296 297 Matcher unbalancedMatcher = unbalancedPattern.matcher(input); 298 input = unbalancedMatcher.replaceAll("<" + tag + " />"); 299 300 return input; 301 } 302 303 309 private String processLinks(String input) { 310 Pattern openingLinkPattern = Pattern.compile("<a HREF=.*?>", Pattern.CASE_INSENSITIVE); 311 Pattern closingLinkPattern = Pattern.compile("</a>", Pattern.CASE_INSENSITIVE); 312 313 Matcher closingMatcher = closingLinkPattern.matcher(input); 314 input = closingMatcher.replaceAll("</a>"); 315 316 Matcher openingMatcher = openingLinkPattern.matcher(input); 317 while (openingMatcher.find()) { 318 int start = openingMatcher.start(); 319 int end = openingMatcher.end(); 320 String link = input.substring(start, end); 321 link = "<" + link.substring(4, link.length() - 4) + ">"; 322 input = input.substring(0, start) + link + input.substring(end, input.length()); 323 openingMatcher = openingLinkPattern.matcher(input); 324 } 325 326 return input; 327 } 328 329 335 private String processImgTags(String input) { 336 Pattern imgPattern = Pattern.compile("(<)(\\s*img\\s?.*?\\s*/*)(>)", Pattern.CASE_INSENSITIVE); 337 Matcher imgMatcher = imgPattern.matcher(input); 338 339 StringBuffer buffer = new StringBuffer (); 341 while (imgMatcher.find()) { 342 imgMatcher.appendReplacement(buffer, "<" + imgMatcher.group(2) + ">"); 344 } 345 346 imgMatcher.appendTail(buffer); 347 348 return buffer.toString(); 349 } 350 } | Popular Tags |