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
BIN
webapp/lib/antisamy-1.4.4.jar
Normal file
BIN
webapp/lib/antisamy-1.4.4.jar
Normal file
Binary file not shown.
BIN
webapp/lib/batik-css.jar
Normal file
BIN
webapp/lib/batik-css.jar
Normal file
Binary file not shown.
BIN
webapp/lib/nekohtml.jar
Normal file
BIN
webapp/lib/nekohtml.jar
Normal file
Binary file not shown.
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.VitroRequest;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
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.controller.freemarker.UrlBuilder.ParamMap;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.web.AntiScript;
|
||||||
|
|
||||||
public abstract class BaseTemplateModel {
|
public abstract class BaseTemplateModel {
|
||||||
|
|
||||||
|
@ -32,6 +33,22 @@ public abstract class BaseTemplateModel {
|
||||||
return UrlBuilder.getUrl(path, params);
|
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() {
|
public static ServletContext getServletContext() {
|
||||||
return servletContext;
|
return servletContext;
|
||||||
}
|
}
|
||||||
|
@ -39,5 +56,6 @@ public abstract class BaseTemplateModel {
|
||||||
public static void setServletContext(ServletContext context) {
|
public static void setServletContext(ServletContext context) {
|
||||||
servletContext = context;
|
servletContext = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ public class LinkTemplateModel extends BaseTemplateModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUrl() {
|
public String getUrl() {
|
||||||
return url;
|
return cleanTextForDisplay( url );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setUrl(String path) {
|
protected void setUrl(String path) {
|
||||||
|
@ -46,7 +46,7 @@ public class LinkTemplateModel extends BaseTemplateModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return text;
|
return cleanTextForDisplay(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setText(String text) {
|
protected void setText(String text) {
|
||||||
|
|
|
@ -36,7 +36,9 @@ public class DataPropertyStatementTemplateModel extends PropertyStatementTemplat
|
||||||
Literal literal, EditingPolicyHelper policyHelper, VitroRequest vreq) {
|
Literal literal, EditingPolicyHelper policyHelper, VitroRequest vreq) {
|
||||||
super(subjectUri, propertyUri, policyHelper, 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);
|
setEditAccess(literal, policyHelper, propertyUri);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ public class NameStatementTemplateModel extends
|
||||||
EditLiteral literal = iDao.getLabelEditLiteral(subjectUri);
|
EditLiteral literal = iDao.getLabelEditLiteral(subjectUri);
|
||||||
|
|
||||||
if (literal != null) {
|
if (literal != null) {
|
||||||
value = literal.getLexicalForm();
|
value = cleanTextForDisplay( literal.getLexicalForm() );
|
||||||
setEditAccess(literal, policyHelper);
|
setEditAccess(literal, policyHelper);
|
||||||
} else {
|
} else {
|
||||||
// If the individual has no rdfs:label, use the local name. It will not be editable. (This replicates previous behavior;
|
// 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.VitroRequest;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
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.controller.freemarker.UrlBuilder.ParamMap;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||||
|
|
||||||
public class ObjectPropertyStatementTemplateModel extends PropertyStatementTemplateModel {
|
public class ObjectPropertyStatementTemplateModel extends PropertyStatementTemplateModel {
|
||||||
|
@ -37,7 +36,7 @@ public class ObjectPropertyStatementTemplateModel extends PropertyStatementTempl
|
||||||
super(subjectUri, propertyUri, policyHelper, vreq);
|
super(subjectUri, propertyUri, policyHelper, vreq);
|
||||||
|
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.objectUri = data.get(objectKey);
|
this.objectUri = cleanURIForDisplay( data.get(objectKey) );
|
||||||
this.templateName = templateName;
|
this.templateName = templateName;
|
||||||
setEditAccess(policyHelper);
|
setEditAccess(policyHelper);
|
||||||
}
|
}
|
||||||
|
@ -66,7 +65,7 @@ public class ObjectPropertyStatementTemplateModel extends PropertyStatementTempl
|
||||||
/* Access methods for templates */
|
/* Access methods for templates */
|
||||||
|
|
||||||
public Object get(String key) {
|
public Object get(String key) {
|
||||||
return data.get(key);
|
return cleanTextForDisplay( data.get(key) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEditUrl() {
|
public String getEditUrl() {
|
||||||
|
|
|
@ -38,7 +38,7 @@ public abstract class BaseListedIndividual extends BaseTemplateModel {
|
||||||
/* Access methods for templates */
|
/* Access methods for templates */
|
||||||
|
|
||||||
public String getProfileUrl() {
|
public String getProfileUrl() {
|
||||||
return UrlBuilder.getIndividualProfileUrl(individual, vreq);
|
return cleanURIForDisplay( UrlBuilder.getIndividualProfileUrl(individual, vreq) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getImageUrl() {
|
public String getImageUrl() {
|
||||||
|
@ -52,11 +52,11 @@ public abstract class BaseListedIndividual extends BaseTemplateModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return individual.getName();
|
return cleanTextForDisplay( individual.getName() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUri() {
|
public String getUri() {
|
||||||
return individual.getURI();
|
return cleanURIForDisplay( individual.getURI() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getMostSpecificTypes() {
|
public List<String> getMostSpecificTypes() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue