Adding anti XSS NIHVIVO-3379
This commit is contained in:
parent
dac5d91478
commit
36a99486f6
12 changed files with 400 additions and 41 deletions
|
@ -38,6 +38,7 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.SelectListGeneratorV
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.FieldVTwo;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.FieldVTwo;
|
||||||
import edu.cornell.mannlib.vitro.webapp.web.MiscWebUtils;
|
import edu.cornell.mannlib.vitro.webapp.web.MiscWebUtils;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.DefaultAddMissingIndividualFormModelPreprocessor;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.DefaultAddMissingIndividualFormModelPreprocessor;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.validators.AntiXssValidation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the edit configuration for a default property form.
|
* Generates the edit configuration for a default property form.
|
||||||
|
@ -116,6 +117,9 @@ public class DefaultAddMissingIndividualFormGenerator implements EditConfigurati
|
||||||
//default obj property form.populateTemplate or some such method
|
//default obj property form.populateTemplate or some such method
|
||||||
//Select from existing also set within template itself
|
//Select from existing also set within template itself
|
||||||
setTemplate(editConfiguration, vreq);
|
setTemplate(editConfiguration, vreq);
|
||||||
|
|
||||||
|
editConfiguration.addValidator(new AntiXssValidation());
|
||||||
|
|
||||||
//edit key now set in the edit request dispatch controller
|
//edit key now set in the edit request dispatch controller
|
||||||
return editConfiguration;
|
return editConfiguration;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUti
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.FieldVTwo;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.FieldVTwo;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.DefaultDataPropEmptyField;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.DefaultDataPropEmptyField;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.validators.AntiXssValidation;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.processEdit.RdfLiteralHash;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.processEdit.RdfLiteralHash;
|
||||||
|
|
||||||
public class DefaultDataPropertyFormGenerator extends BaseEditConfigurationGenerator implements EditConfigurationGenerator {
|
public class DefaultDataPropertyFormGenerator extends BaseEditConfigurationGenerator implements EditConfigurationGenerator {
|
||||||
|
@ -82,6 +83,8 @@ public class DefaultDataPropertyFormGenerator extends BaseEditConfigurationGener
|
||||||
|
|
||||||
editConfiguration.addField( literalField );
|
editConfiguration.addField( literalField );
|
||||||
|
|
||||||
|
editConfiguration.addValidator(new AntiXssValidation());
|
||||||
|
|
||||||
// An empty field on an update gets special treatment
|
// An empty field on an update gets special treatment
|
||||||
if( update ) {
|
if( update ) {
|
||||||
// on update, allow an empty field and deal with it in DefaultDataPropEmptyField
|
// on update, allow an empty field and deal with it in DefaultDataPropEmptyField
|
||||||
|
|
|
@ -26,6 +26,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.FieldVTwo;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.FieldVTwo;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.validators.AntiXssValidation;
|
||||||
import edu.cornell.mannlib.vitro.webapp.search.beans.ProhibitedFromSearch;
|
import edu.cornell.mannlib.vitro.webapp.search.beans.ProhibitedFromSearch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -110,6 +111,9 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene
|
||||||
//default obj property form.populateTemplate or some such method
|
//default obj property form.populateTemplate or some such method
|
||||||
//Select from existing also set within template itself
|
//Select from existing also set within template itself
|
||||||
setTemplate(editConfiguration, vreq);
|
setTemplate(editConfiguration, vreq);
|
||||||
|
|
||||||
|
editConfiguration.addValidator(new AntiXssValidation());
|
||||||
|
|
||||||
//Set edit key
|
//Set edit key
|
||||||
setEditKey(editConfiguration, vreq);
|
setEditKey(editConfiguration, vreq);
|
||||||
//Adding additional data, specifically edit mode
|
//Adding additional data, specifically edit mode
|
||||||
|
|
|
@ -34,6 +34,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.Field;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.Field;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.validators.AntiXssValidation;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.processEdit.RdfLiteralHash;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.processEdit.RdfLiteralHash;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditN3GeneratorVTwo;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditN3GeneratorVTwo;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.SelectListGeneratorVTwo;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.SelectListGeneratorVTwo;
|
||||||
|
@ -96,6 +97,7 @@ public class NewIndividualFormGenerator implements EditConfigurationGenerator {
|
||||||
|
|
||||||
prepareForUpdate(vreq, session, editConfiguration);
|
prepareForUpdate(vreq, session, editConfiguration);
|
||||||
|
|
||||||
|
editConfiguration.addValidator(new AntiXssValidation());
|
||||||
|
|
||||||
//Form title and submit label now moved to edit configuration template
|
//Form title and submit label now moved to edit configuration template
|
||||||
//TODO: check if edit configuration template correct place to set those or whether
|
//TODO: check if edit configuration template correct place to set those or whether
|
||||||
|
|
|
@ -31,6 +31,7 @@ import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.Field;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.Field;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.validators.AntiXssValidation;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.processEdit.RdfLiteralHash;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.processEdit.RdfLiteralHash;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditN3GeneratorVTwo;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditN3GeneratorVTwo;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.SelectListGeneratorVTwo;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.SelectListGeneratorVTwo;
|
||||||
|
@ -100,6 +101,8 @@ public class RDFSLabelGenerator implements EditConfigurationGenerator {
|
||||||
//placing in session depends on having edit key which is handled in edit request dispatch controller
|
//placing in session depends on having edit key which is handled in edit request dispatch controller
|
||||||
prepareForUpdate(vreq, session, editConfiguration);
|
prepareForUpdate(vreq, session, editConfiguration);
|
||||||
|
|
||||||
|
editConfiguration.addValidator(new AntiXssValidation());
|
||||||
|
|
||||||
//Form title and submit label now moved to edit configuration template
|
//Form title and submit label now moved to edit configuration template
|
||||||
setTemplate(editConfiguration, vreq);
|
setTemplate(editConfiguration, vreq);
|
||||||
//Set edit key
|
//Set edit key
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.validators;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.owasp.validator.html.AntiSamy;
|
||||||
|
import org.owasp.validator.html.CleanResults;
|
||||||
|
import org.owasp.validator.html.PolicyException;
|
||||||
|
import org.owasp.validator.html.ScanException;
|
||||||
|
|
||||||
|
import com.hp.hpl.jena.rdf.model.Literal;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.MultiValueEditSubmission;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.N3ValidatorVTwo;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.web.AntiScript;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the submitted text has potential XSS problems.
|
||||||
|
* Error messages from this validator always start with XSS_ERROR_MESSAGE
|
||||||
|
*
|
||||||
|
* @author bdc34
|
||||||
|
*/
|
||||||
|
public class AntiXssValidation implements N3ValidatorVTwo{
|
||||||
|
List<String> fieldNamesToValidate;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate all fields on submission.
|
||||||
|
*/
|
||||||
|
public AntiXssValidation(){
|
||||||
|
this.fieldNamesToValidate = ALL_FIELDS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate only fields specified in fieldNamesToValidate.
|
||||||
|
*/
|
||||||
|
public AntiXssValidation(List<String> fieldNamesToValidate){
|
||||||
|
this.fieldNamesToValidate = fieldNamesToValidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> validate(EditConfigurationVTwo editConfig,
|
||||||
|
MultiValueEditSubmission editSub) {
|
||||||
|
|
||||||
|
if( editSub == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String,String>varToErrMsg = new HashMap<String,String>();
|
||||||
|
if( fieldNamesToValidate == null ){
|
||||||
|
if( editSub.getLiteralsFromForm() != null ){
|
||||||
|
for( String name : editSub.getLiteralsFromForm().keySet()){
|
||||||
|
varToErrMsg.putAll( checkSubmissionForField( name, editSub));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( editSub.getUrisFromForm() != null ){
|
||||||
|
for( String name : editSub.getUrisFromForm().keySet()){
|
||||||
|
varToErrMsg.putAll( checkSubmissionForField( name, editSub));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
for( String fieldName : fieldNamesToValidate){
|
||||||
|
varToErrMsg.putAll( checkSubmissionForField(fieldName, editSub));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( varToErrMsg.isEmpty() )
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
return varToErrMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for XSS for a single field. Returns NO_ERROR if there
|
||||||
|
* are no errors so it can be added to a map with putAll()
|
||||||
|
*/
|
||||||
|
protected Map<String,String> checkSubmissionForField(
|
||||||
|
String fieldName, MultiValueEditSubmission editSub){
|
||||||
|
|
||||||
|
if( fieldName == null || fieldName.isEmpty() || editSub == null)
|
||||||
|
return NO_ERROR;
|
||||||
|
|
||||||
|
if( editSub.getLiteralsFromForm() != null &&
|
||||||
|
editSub.getLiteralsFromForm().containsKey(fieldName) ){
|
||||||
|
|
||||||
|
String error = null;
|
||||||
|
try {
|
||||||
|
error = literalHasXSS( editSub.getLiteralsFromForm().get(fieldName) );
|
||||||
|
} catch (ScanException e) {
|
||||||
|
error = e.getMessage();
|
||||||
|
} catch (PolicyException e) {
|
||||||
|
error = e.getMessage();
|
||||||
|
}
|
||||||
|
if( error != null ){
|
||||||
|
return Collections.singletonMap(fieldName, XSS_ERROR_MESSAGE + " " + error);
|
||||||
|
}else{
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (editSub.getUrisFromForm() != null &&
|
||||||
|
editSub.getUrisFromForm().containsKey(fieldName)){
|
||||||
|
|
||||||
|
String error;
|
||||||
|
try {
|
||||||
|
error = uriHasXSS( editSub.getUrisFromForm().get(fieldName));
|
||||||
|
} catch (ScanException e) {
|
||||||
|
error = e.getMessage();
|
||||||
|
} catch (PolicyException e) {
|
||||||
|
error = e.getMessage();
|
||||||
|
}
|
||||||
|
if( error != null ){
|
||||||
|
return Collections.singletonMap(fieldName, XSS_ERROR_MESSAGE + " " + error);
|
||||||
|
}else{
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
}else{
|
||||||
|
//field wasn't in submission
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a list of URIs has any XSS problems.
|
||||||
|
* Return null if there are none and return an error message if there are problems.
|
||||||
|
*/
|
||||||
|
private String uriHasXSS(List<String> uriList) throws ScanException, PolicyException {
|
||||||
|
AntiSamy antiSamy = AntiScript.getAntiSamyScanner();
|
||||||
|
ArrayList errorMsgs = new ArrayList();
|
||||||
|
|
||||||
|
for( String uri : uriList ){
|
||||||
|
CleanResults cr = antiSamy.scan( uri );
|
||||||
|
errorMsgs.addAll( cr.getErrorMessages() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( errorMsgs.isEmpty() ){
|
||||||
|
return null;
|
||||||
|
}else{
|
||||||
|
return StringUtils.join(errorMsgs, ", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a List of Literals has any XSS problems.
|
||||||
|
* Return null if there are none and return an error message if there are problems.
|
||||||
|
*/
|
||||||
|
private String literalHasXSS(List<Literal> list) throws ScanException, PolicyException {
|
||||||
|
AntiSamy antiSamy = AntiScript.getAntiSamyScanner();
|
||||||
|
|
||||||
|
ArrayList errorMsgs = new ArrayList();
|
||||||
|
for( Literal literal : list ){
|
||||||
|
CleanResults cr = antiSamy.scan(literal.getLexicalForm());
|
||||||
|
errorMsgs.addAll( cr.getErrorMessages() );
|
||||||
|
|
||||||
|
String dt = literal.getDatatypeURI();
|
||||||
|
if( dt != null ){
|
||||||
|
cr = antiSamy.scan( dt );
|
||||||
|
errorMsgs.addAll( cr.getErrorMessages() );
|
||||||
|
}
|
||||||
|
|
||||||
|
String lang = literal.getLanguage() ;
|
||||||
|
if( lang != null ){
|
||||||
|
cr = antiSamy.scan( lang );
|
||||||
|
errorMsgs.addAll( cr.getErrorMessages() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( errorMsgs.isEmpty() )
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
return StringUtils.join(errorMsgs,", ");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All error messages will start with this string.
|
||||||
|
*/
|
||||||
|
public static String XSS_ERROR_MESSAGE = "Field contains unacceptable markup";
|
||||||
|
|
||||||
|
private static final Map<String,String>NO_ERROR = Collections.emptyMap();
|
||||||
|
|
||||||
|
//value indicates that all fields should be validated.
|
||||||
|
private static final List<String> ALL_FIELDS = null;
|
||||||
|
}
|
|
@ -29,9 +29,7 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.Field;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.processEdit.EditSubmission;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.processEdit.EditSubmission;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User: bdc34
|
*
|
||||||
* Date: Jan 24, 2008
|
|
||||||
* Time: 1:55:39 PM
|
|
||||||
*/
|
*/
|
||||||
public class BasicValidation {
|
public class BasicValidation {
|
||||||
|
|
||||||
|
@ -271,7 +269,7 @@ public class BasicValidation {
|
||||||
static final List<String> basicValidations;
|
static final List<String> basicValidations;
|
||||||
static{
|
static{
|
||||||
basicValidations = Arrays.asList(
|
basicValidations = Arrays.asList(
|
||||||
"nonempty","isDate","dateNotPast","httpUrl" );
|
"nonempty","isDate","dateNotPast","httpUrl" ,"anti-xss");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Log log = LogFactory.getLog(BasicValidation.class);
|
private Log log = LogFactory.getLog(BasicValidation.class);
|
||||||
|
|
|
@ -372,6 +372,7 @@ public class EditRequestDispatchController extends FreemarkerHttpServlet {
|
||||||
if(EditConfigurationVTwoGenerator == null){
|
if(EditConfigurationVTwoGenerator == null){
|
||||||
throw new Error("Could not find EditConfigurationVTwoGenerator " + editConfGeneratorName);
|
throw new Error("Could not find EditConfigurationVTwoGenerator " + editConfGeneratorName);
|
||||||
} else {
|
} else {
|
||||||
|
log.debug("Created EditConfiguration using " + editConfGeneratorName);
|
||||||
return EditConfigurationVTwoGenerator.getEditConfiguration(vreq, session);
|
return EditConfigurationVTwoGenerator.getEditConfiguration(vreq, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,11 @@ public class AntiScript {
|
||||||
|
|
||||||
private static final Log log = LogFactory.getLog(AntiScript.class);
|
private static final Log log = LogFactory.getLog(AntiScript.class);
|
||||||
|
|
||||||
|
private static Policy policy;
|
||||||
private static final String ANTI_SCRIPT_POLICY = "ANTI_SCRIPT_POLICY";
|
private static AntiSamy antiSamy;
|
||||||
|
|
||||||
private static final String ANTI_SCRIPT_SCANNER = "ANTI_SCRIPT_SCANNER";
|
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";
|
private static String ANTI_SCRIPT_POLICY_FILE = "/edu/cornell/mannlib/vitro/webapp/web/antisamy-vitro-1.4.4.xml";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This will attempt to return HTML that has been cleaned up according
|
* This will attempt to return HTML that has been cleaned up according
|
||||||
|
@ -41,11 +42,11 @@ public class AntiScript {
|
||||||
*
|
*
|
||||||
* This will return null if dirtyInput is null.
|
* This will return null if dirtyInput is null.
|
||||||
*/
|
*/
|
||||||
public static String cleanText( String dirtyInput, ServletContext context){
|
public static String cleanText( String dirtyInput ){
|
||||||
if( dirtyInput == null )
|
if( dirtyInput == null )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
AntiSamy as = getHTMLScanner(context);
|
AntiSamy as = getAntiSamyScanner();
|
||||||
CleanResults cr;
|
CleanResults cr;
|
||||||
try {
|
try {
|
||||||
cr = as.scan(dirtyInput);
|
cr = as.scan(dirtyInput);
|
||||||
|
@ -61,62 +62,59 @@ public class AntiScript {
|
||||||
/**
|
/**
|
||||||
* Method to clean a URL or URI.
|
* Method to clean a URL or URI.
|
||||||
*/
|
*/
|
||||||
public static String cleanURI( String dirtyInput, ServletContext context){
|
public static String cleanURI( String dirtyInput ){
|
||||||
return cleanText(dirtyInput,context);
|
return cleanText(dirtyInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to clean all of the values in a map where the values are of
|
* Method to clean all of the values in a map where the values are of
|
||||||
* type String.
|
* type String.
|
||||||
*/
|
*/
|
||||||
public static <T> void cleanMapValues( Map<T,String> map, ServletContext context){
|
public static <T> void cleanMapValues( Map<T,String> map ){
|
||||||
for( T key : map.keySet() ){
|
for( T key : map.keySet() ){
|
||||||
map.put(key, cleanText(map.get(key), context));
|
map.put(key, cleanText(map.get(key)) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to get the policy from the servlet context, if none exists, create a new one.
|
* Try to get the static policy, if none exists, create a new one.
|
||||||
* This is a anti-script policy for use with OWASP AntiSamy, not a vivo auth Policy.
|
* This is a anti-script policy for use with OWASP AntiSamy, not a vivo auth Policy.
|
||||||
* Returns null if no policy can be created.
|
* Returns null if no policy can be created.
|
||||||
*/
|
*/
|
||||||
protected static Policy getAntiScriptPolicy(ServletContext context){
|
protected static Policy getAntiScriptPolicy( ){
|
||||||
Object obj = context.getAttribute( ANTI_SCRIPT_POLICY );
|
|
||||||
if( obj == null ){
|
if( policy == null ){
|
||||||
Policy newPolicy;
|
Policy newPolicy;
|
||||||
try {
|
try {
|
||||||
String url = ANTI_SCRIPT_POLICY_FILE;
|
String url = ANTI_SCRIPT_POLICY_FILE;
|
||||||
URL policyFile= context.getResource( url );
|
URL policyFile= AntiScript.class.getResource( url );
|
||||||
newPolicy = Policy.getInstance( policyFile );
|
newPolicy = Policy.getInstance( policyFile );
|
||||||
context.setAttribute(ANTI_SCRIPT_POLICY, newPolicy);
|
|
||||||
log.debug("anti-script policy loaded successfully");
|
log.debug("anti-script policy loaded successfully");
|
||||||
return newPolicy;
|
policy = newPolicy;
|
||||||
} catch (PolicyException e) {
|
} catch (PolicyException e) {
|
||||||
log.error("Anti-Script policy not setup.", e);
|
log.error("Anti-Script policy not setup.", e);
|
||||||
return null;
|
return null;
|
||||||
} catch (MalformedURLException e) {
|
} catch (Throwable e) {
|
||||||
log.error("Anti-Script policy not setup.", e);
|
log.error("Anti-Script policy not setup.", e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
return (Policy)obj;
|
|
||||||
}
|
return policy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to get an AntiSamy HTML scanner object that is sharied across
|
* Try to get a static AntiSamy HTML scanner object that is shared the
|
||||||
* the whole web application. This may return a scanner with a null
|
* whole application. This may return a scanner with a null
|
||||||
* policy if the policy is not setup correctly.
|
* policy if the policy is not setup correctly.
|
||||||
*/
|
*/
|
||||||
protected static AntiSamy getHTMLScanner( ServletContext context){
|
public static AntiSamy getAntiSamyScanner( ){
|
||||||
Object obj = context.getAttribute( ANTI_SCRIPT_SCANNER );
|
|
||||||
if( obj == null ){
|
if( antiSamy == null ){
|
||||||
AntiSamy scanner = new AntiSamy( getAntiScriptPolicy(context));
|
antiSamy = new AntiSamy( getAntiScriptPolicy() );
|
||||||
context.setAttribute( ANTI_SCRIPT_SCANNER , scanner);
|
log.debug("anti-script scanner loaded successfully");
|
||||||
log.debug("anti-script scanner loaded successfully");
|
}
|
||||||
return scanner;
|
|
||||||
}else{
|
return antiSamy;
|
||||||
return (AntiSamy) obj;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,9 @@ public abstract class BaseTemplateModel {
|
||||||
* that shouldn't be in a URI.
|
* that shouldn't be in a URI.
|
||||||
*/
|
*/
|
||||||
protected String cleanURIForDisplay( String dirty ){
|
protected String cleanURIForDisplay( String dirty ){
|
||||||
|
if( dirty == null )
|
||||||
|
return null;
|
||||||
|
|
||||||
StringBuilder clean = new StringBuilder(dirty.length());
|
StringBuilder clean = new StringBuilder(dirty.length());
|
||||||
for (char ch: dirty.toCharArray()) {
|
for (char ch: dirty.toCharArray()) {
|
||||||
if (URI_CHARACTERS.indexOf(ch) != -1) {
|
if (URI_CHARACTERS.indexOf(ch) != -1) {
|
||||||
|
@ -59,7 +62,7 @@ public abstract class BaseTemplateModel {
|
||||||
* Currently this only checks for XSS exploits.
|
* Currently this only checks for XSS exploits.
|
||||||
*/
|
*/
|
||||||
protected String cleanTextForDisplay( String dirty){
|
protected String cleanTextForDisplay( String dirty){
|
||||||
return AntiScript.cleanText(dirty, getServletContext());
|
return AntiScript.cleanText(dirty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,7 +70,7 @@ public abstract class BaseTemplateModel {
|
||||||
* a map. Map may be modified.
|
* a map. Map may be modified.
|
||||||
*/
|
*/
|
||||||
protected <T> void cleanMapValuesForDisplay( Map<T,String> map){
|
protected <T> void cleanMapValuesForDisplay( Map<T,String> map){
|
||||||
AntiScript.cleanMapValues(map, getServletContext());
|
AntiScript.cleanMapValues(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static ServletContext getServletContext() {
|
protected static ServletContext getServletContext() {
|
||||||
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.validators;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.FieldVTwo;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.MultiValueEditSubmission;
|
||||||
|
|
||||||
|
public class AntiXssValidationTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLiteral( ){
|
||||||
|
//test all fields constructor
|
||||||
|
AntiXssValidation validator =new AntiXssValidation();
|
||||||
|
|
||||||
|
EditConfigurationVTwo eConf = new EditConfigurationVTwo();
|
||||||
|
eConf.setEditKey("fakeEditKey");
|
||||||
|
eConf.addField( new FieldVTwo().setName("X") );
|
||||||
|
eConf.setLiteralsOnForm( Arrays.asList("X") );
|
||||||
|
|
||||||
|
Map<String, String[]> params = new HashMap<String,String[]>();
|
||||||
|
String[] vals= { "some sort of string" };
|
||||||
|
params.put("X", vals);
|
||||||
|
|
||||||
|
MultiValueEditSubmission mvEditSub =
|
||||||
|
new MultiValueEditSubmission(params,eConf);
|
||||||
|
|
||||||
|
Map<String, String> res = validator.validate(eConf, mvEditSub);
|
||||||
|
Assert.assertEquals(null, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAllURI( ){
|
||||||
|
//test all fields constructor
|
||||||
|
AntiXssValidation validator =new AntiXssValidation();
|
||||||
|
|
||||||
|
EditConfigurationVTwo eConf = new EditConfigurationVTwo();
|
||||||
|
eConf.setEditKey("fakeEditKey");
|
||||||
|
eConf.setUrisOnform( Arrays.asList("X","Y","Z"));
|
||||||
|
|
||||||
|
Map<String, String[]> params = new HashMap<String,String[]>();
|
||||||
|
String[] strings0 = {"no problem 0"};
|
||||||
|
params.put("X", strings0 );
|
||||||
|
String[] strings1 = {"no problem 1"};
|
||||||
|
params.put("Y", strings1 );
|
||||||
|
String[] strings2 = {"no problem 2"};
|
||||||
|
params.put("Z", strings2 );
|
||||||
|
|
||||||
|
MultiValueEditSubmission mvEditSub =
|
||||||
|
new MultiValueEditSubmission(params,eConf);
|
||||||
|
|
||||||
|
Map<String, String> res = validator.validate(eConf, mvEditSub);
|
||||||
|
Assert.assertNull( res );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<String, String> testURI( String ... strings){
|
||||||
|
|
||||||
|
AntiXssValidation validator =
|
||||||
|
new AntiXssValidation(Arrays.asList("X"));
|
||||||
|
|
||||||
|
EditConfigurationVTwo eConf = new EditConfigurationVTwo();
|
||||||
|
eConf.setEditKey("fakeEditKey");
|
||||||
|
eConf.setUrisOnform( Arrays.asList("X"));
|
||||||
|
|
||||||
|
Map<String, String[]> params = new HashMap<String,String[]>();
|
||||||
|
params.put("X", strings );
|
||||||
|
|
||||||
|
MultiValueEditSubmission mvEditSub =
|
||||||
|
new MultiValueEditSubmission(params,eConf);
|
||||||
|
|
||||||
|
return validator.validate(eConf, mvEditSub);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testURIValidation(){
|
||||||
|
Map<String, String> result = testURI("http://this.should.be.fine.com/xyz#lskd?junk=a&bkeck=%23");
|
||||||
|
Assert.assertNull(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testURIValidationWithScriptTagLevel1(){
|
||||||
|
Map<String, String> result = null;
|
||||||
|
result = testURI("http:<SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT>//bad.news.com");
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
|
||||||
|
result = testURI("http:<IMG SRC=JaVaScRiPt:alert('XSS')>//bad.news.com");
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
|
||||||
|
result = testURI("http:<IMG SRC=javascript:alert('XSS')>//bad.news.com");
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
|
||||||
|
result = testURI("http:<IMG SRC=javascript:alert("XSS")>//bad.news.com");
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
|
||||||
|
result = testURI("http:<IMG SRC=\"jav\tascript:alert('XSS');\">//bad.news.com");
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testURIValidationWithScriptTagLevel2(){
|
||||||
|
Map<String, String> result = null;
|
||||||
|
result = testURI("http:<IMG SRC=javascript:alert('XSS')>//bad.news.com");
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
|
||||||
|
result = testURI("http:<IMG SRC=javascript:alert('XSS')>//bad.news.com");
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
|
||||||
|
result = testURI("http:<IMG SRC=javascript:alert('XSS')>//bad.news.com");
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
|
||||||
|
result = testURI("http:<<SCRIPT>alert(\"XSS\");//<</SCRIPT>//bad.news.com");
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
|
||||||
|
result = testURI("http:<IMG SRC=javascript:alert('XSS')>//bad.news.com");
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
|
||||||
|
result = testURI("http:<IMG SRC=javascript:alert('XSS')>//bad.news.com");
|
||||||
|
Assert.assertNotNull(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.web.templatemodels;
|
||||||
|
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class BaseTemplateModelTest {
|
||||||
|
|
||||||
|
private static String value;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCleanURIofNull(){
|
||||||
|
|
||||||
|
BaseTemplateModel btm = new BaseTemplateModel(){};
|
||||||
|
//should not throw NPE
|
||||||
|
value = btm.cleanURIForDisplay( null );
|
||||||
|
|
||||||
|
//should not throw NPE
|
||||||
|
value = btm.cleanTextForDisplay( null );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue