Adding render time filtering of script elements to avoid javascript based security exploits. NIHVIVO-2678
This commit is contained in:
parent
7ce7f7a1ac
commit
22427f694f
11 changed files with 2807 additions and 10 deletions
109
webapp/src/edu/cornell/mannlib/vitro/webapp/web/AntiScript.java
Normal file
109
webapp/src/edu/cornell/mannlib/vitro/webapp/web/AntiScript.java
Normal 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
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue