Adding render time filtering of script elements to avoid javascript based security exploits. NIHVIVO-2678

This commit is contained in:
briancaruso 2011-07-11 23:14:55 +00:00
parent 7ce7f7a1ac
commit 22427f694f
11 changed files with 2807 additions and 10 deletions

View file

@ -0,0 +1,109 @@
package edu.cornell.mannlib.vitro.webapp.web;
import java.net.MalformedURLException;
import java.net.URL;
import javax.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.owasp.validator.html.AntiSamy;
import org.owasp.validator.html.CleanResults;
import org.owasp.validator.html.Policy;
import org.owasp.validator.html.PolicyException;
import org.owasp.validator.html.ScanException;
/**
* This is a class to provide methods to strip bad HTML from user input.
* The primary goal of this is to avoid XSS attacks.
*/
public class AntiScript {
private static final Log log = LogFactory.getLog(AntiScript.class);
private static final String ANTI_SCRIPT_POLICY = "ANTI_SCRIPT_POLICY";
private static final String ANTI_SCRIPT_SCANNER = "ANTI_SCRIPT_SCANNER";
private static String ANTI_SCRIPT_POLICY_FILE = "/WEB-INF/classes/edu/cornell/mannlib/vitro/webapp/web/antisamy-vitro-1.4.4.xml";
/**
* This will attempt to return HTML that has been cleaned up according
* to the policy.
*
* If there is any error during the scan, an error message
* will be returned instead of the HTML. This might not be ideal so
* consider changing it once we see how this works. Other options include
* returning an empty string or some other error message. Returning
* the unscanned HTML is not a secure option as it may contain scripts.
*
* This will return null if dirtyInput is null.
*/
public static String cleanHtml( String dirtyInput, ServletContext context){
if( dirtyInput == null )
return null;
AntiSamy as = getHTMLScanner(context);
CleanResults cr;
try {
cr = as.scan(dirtyInput);
return cr.getCleanHTML();
} catch (ScanException e) {
log.error("Error while scaning HTML" ,e );
} catch (PolicyException e) {
log.error("Error while scanning HTML", e);
}
return "AntiScript: HTML caused scan error.";
}
/**
* Method to clean a URL or URI. Might do the same thing as cleanHTML().
*/
public static String cleanURI( String dirtyInput, ServletContext context){
return cleanHtml(dirtyInput,context);
}
/**
* Try to get the policy from the servlet context, if none exists, create a new one.
* This is a anti-script policy for use with OWASP AntiSamy, not a vivo auth Policy.
* Returns null if no policy can be created.
*/
protected static Policy getAntiScriptPolicy(ServletContext context){
Object obj = context.getAttribute( ANTI_SCRIPT_POLICY );
if( obj == null ){
Policy newPolicy;
try {
String url = ANTI_SCRIPT_POLICY_FILE;
URL policyFile= context.getResource( url );
newPolicy = Policy.getInstance( policyFile );
context.setAttribute(ANTI_SCRIPT_POLICY, newPolicy);
log.debug("anti-script policy loaded successfully");
return newPolicy;
} catch (PolicyException e) {
log.error("Anti-Script policy not setup.", e);
return null;
} catch (MalformedURLException e) {
log.error("Anti-Script policy not setup.", e);
return null;
}
} else {
return (Policy)obj;
}
}
/**
* Try to get an AntiSamy HTML scanner object that is sharied across
* the whole web application. This may return a scanner with a null
* policy if the policy is not setup correctly.
*/
protected static AntiSamy getHTMLScanner( ServletContext context){
Object obj = context.getAttribute( ANTI_SCRIPT_SCANNER );
if( obj == null ){
AntiSamy scanner = new AntiSamy( getAntiScriptPolicy(context));
context.setAttribute( ANTI_SCRIPT_SCANNER , scanner);
log.debug("anti-script scanner loaded successfully");
return scanner;
}else{
return (AntiSamy) obj;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,7 @@ import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap;
import edu.cornell.mannlib.vitro.webapp.web.AntiScript;
public abstract class BaseTemplateModel {
@ -32,6 +33,22 @@ public abstract class BaseTemplateModel {
return UrlBuilder.getUrl(path, params);
}
/**
* Used to do any processing for display of URIs or URLs.
* Currently this only checks for XSS exploits.
*/
protected String cleanURIForDisplay( String dirty ){
return AntiScript.cleanURI(dirty, getServletContext());
}
/**
* Used to do any processing for display of general text.
* Currently this only checks for XSS exploits.
*/
protected String cleanTextForDisplay( String dirty){
return AntiScript.cleanHtml(dirty, getServletContext());
}
public static ServletContext getServletContext() {
return servletContext;
}
@ -39,5 +56,6 @@ public abstract class BaseTemplateModel {
public static void setServletContext(ServletContext context) {
servletContext = context;
}
}

View file

@ -30,7 +30,7 @@ public class LinkTemplateModel extends BaseTemplateModel {
}
public String getUrl() {
return url;
return cleanTextForDisplay( url );
}
protected void setUrl(String path) {
@ -46,7 +46,7 @@ public class LinkTemplateModel extends BaseTemplateModel {
}
public String getText() {
return text;
return cleanTextForDisplay(text);
}
protected void setText(String text) {

View file

@ -36,7 +36,9 @@ public class DataPropertyStatementTemplateModel extends PropertyStatementTemplat
Literal literal, EditingPolicyHelper policyHelper, VitroRequest vreq) {
super(subjectUri, propertyUri, policyHelper, vreq);
this.value = literal.getLexicalForm();
//attempt to strip any odd HTML
this.value = cleanTextForDisplay( literal.getLexicalForm() );
setEditAccess(literal, policyHelper, propertyUri);
}

View file

@ -39,7 +39,7 @@ public class NameStatementTemplateModel extends
EditLiteral literal = iDao.getLabelEditLiteral(subjectUri);
if (literal != null) {
value = literal.getLexicalForm();
value = cleanTextForDisplay( literal.getLexicalForm() );
setEditAccess(literal, policyHelper);
} else {
// If the individual has no rdfs:label, use the local name. It will not be editable. (This replicates previous behavior;

View file

@ -16,7 +16,6 @@ import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatementImpl;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap;
import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao;
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
public class ObjectPropertyStatementTemplateModel extends PropertyStatementTemplateModel {
@ -37,7 +36,7 @@ public class ObjectPropertyStatementTemplateModel extends PropertyStatementTempl
super(subjectUri, propertyUri, policyHelper, vreq);
this.data = data;
this.objectUri = data.get(objectKey);
this.objectUri = cleanURIForDisplay( data.get(objectKey) );
this.templateName = templateName;
setEditAccess(policyHelper);
}
@ -66,7 +65,7 @@ public class ObjectPropertyStatementTemplateModel extends PropertyStatementTempl
/* Access methods for templates */
public Object get(String key) {
return data.get(key);
return cleanTextForDisplay( data.get(key) );
}
public String getEditUrl() {

View file

@ -38,7 +38,7 @@ public abstract class BaseListedIndividual extends BaseTemplateModel {
/* Access methods for templates */
public String getProfileUrl() {
return UrlBuilder.getIndividualProfileUrl(individual, vreq);
return cleanURIForDisplay( UrlBuilder.getIndividualProfileUrl(individual, vreq) );
}
public String getImageUrl() {
@ -52,11 +52,11 @@ public abstract class BaseListedIndividual extends BaseTemplateModel {
}
public String getName() {
return individual.getName();
return cleanTextForDisplay( individual.getName() );
}
public String getUri() {
return individual.getURI();
return cleanURIForDisplay( individual.getURI() );
}
public List<String> getMostSpecificTypes() {