All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gdssecurity.pmd.rules.BaseSecurityRule Maven / Gradle / Ivy

Go to download

Custom ruleset for the open source static analysis tool PMD. The ruleset contains rules intended to identify security violations that map to the 2013 OWASP Top 10

The newest version!
/*
(C) Copyright  2014-2015 Alberto Fernández 
(C) Copyright  2012      Gotham Digital Science, LLC -- All Rights Reserved
 
Unless explicitly acquired and licensed from Licensor under another
license, the contents of this file are subject to the Reciprocal Public
License ("RPL") Version 1.5, or subsequent versions as allowed by the RPL,
and You may not copy or use this file in either source code or executable
form, except in compliance with the terms and conditions of the RPL.

All software distributed under the RPL is provided strictly on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, AND
LICENSOR HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, QUIET ENJOYMENT, OR NON-INFRINGEMENT. See the RPL for specific
language governing rights and limitations under the RPL. 

This code is licensed under the Reciprocal Public License 1.5 (RPL1.5)
http://www.opensource.org/licenses/rpl1.5

*/


package com.gdssecurity.pmd.rules;




import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;

import com.gdssecurity.pmd.SecurityRuleViolation;

import net.sourceforge.pmd.Report;
import net.sourceforge.pmd.Rule;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.RuleViolation;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTType;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.properties.PropertyDescriptor;
import net.sourceforge.pmd.properties.PropertyFactory;



public class BaseSecurityRule extends AbstractJavaRule {

	protected Set sources = null;	
	protected Set sourceTypes = null;
    protected Set unsafeTypes = null;
    protected Set safeTypes = null;
	
    private final PropertyDescriptor> sourceDescriptor = 
    		PropertyFactory.stringListProperty("sources")
    		.delim('|')
    		.desc("sources of posibble dangerous data")
    		.defaultValues(
    			"javax.servlet.ServletRequest.getParameter",
    			"javax.servlet.ServletRequest.getParameterMap",
    			"javax.servlet.ServletRequest.getParameterNames",
    			"javax.servlet.ServletRequest.getParameterValues",
    			"javax.servlet.http.HttpServletRequest.getParameter",
    			"javax.servlet.http.HttpServletRequest.getParameterMap",
    			"javax.servlet.http.HttpServletRequest.getParameterNames",
    			"javax.servlet.http.HttpServletRequest.getParameterValues",
    			"javax.servlet.http.HttpServletRequest.getHeader",
    			"javax.servlet.http.HttpServletRequest.getHeaders",
    			"javax.servlet.http.HttpServletRequest.getHeaderNames"
    		)
    		.build();
    
    private final PropertyDescriptor> sourceTypesDescriptor = 
    		PropertyFactory.stringListProperty("sourceTypes")
    		.delim('|')
    		.desc("sources (classes) of posibble dangerous data")
    		.defaultValues(
    			"javax.servlet.ServletRequest",
    			"javax.servlet.http.HttpServletRequest"
    		)
    		.build();
    
   
    private final PropertyDescriptor> unsafeTypesDescriptor = 
    		PropertyFactory.stringListProperty("unsafeTypes").delim('|')
    		.defaultValues(
    			"java.lang.String", 
            	"java.lang.StringBuilder", 
            	"java.lang.StringBuffer",
            	"java.lang.AbstractStringBuilder")
    		.desc("types that could create a potential SQLi exposure when concatenated to a SQL statement")
    		.build(); 

    // Ignoring Numeric types by default
    private final PropertyDescriptor> safeTypesDescriptor =
    		PropertyFactory.stringListProperty("safeTypes").delim('|')
    		.defaultValues(
    				"java.lang.Byte",
                	"java.lang.Short",            	
                	"java.lang.Integer", 
                	"java.lang.Long",
                	"java.lang.Float",
                	"java.lang.Double",
                	"java.lang.Boolean",
                	"byte",
                	"short",
                	"int",
                	"long",
                	"float",
                	"double",
                	"boolean"
    				)
    		.desc("types that may be considered safe to ignore.")
    		.build();
    
    private boolean initialized = false;
	
	public BaseSecurityRule() {
		super();
		definePropertyDescriptor(this.sourceDescriptor);
		definePropertyDescriptor(this.sourceTypesDescriptor);
    	definePropertyDescriptor(this.unsafeTypesDescriptor);
    	definePropertyDescriptor(this.safeTypesDescriptor);    	
	}



	protected void init() {
		if (!this.initialized) {
			this.sources = getConfig(this.sourceDescriptor);
			this.sourceTypes = getConfig(this.sourceTypesDescriptor);
			this.unsafeTypes = getConfig(this.unsafeTypesDescriptor);
			this.safeTypes = getConfig(this.safeTypesDescriptor);
			this.initialized = true;
		}
	}
	
	protected final Set getConfig(PropertyDescriptor> descriptor) {
		Set ret = new HashSet();
		List props = getProperty(descriptor);
		for (String value: props) {
			if (!StringUtils.isBlank(value)) {
				ret.add(value.trim());
			}
		}
		
		return ret;
	}
    
    
    protected boolean isSafeType(ASTType type) {
    	 if (type == null) {
    		 return false;
    	 }
    	 return isSafeType(type.getType());
    }
    protected boolean isSafeType(Class type) {
    	if (type == null) {
    		return false;
    	}
    	if (type.isArray()) {
    		return isSafeType(type.getComponentType().getCanonicalName());
    	}
    	return isSafeType(type.getCanonicalName());
    }
    protected boolean isSafeType(String type) {
    	if (type == null) {
    		return false;
    	}
    	return this.safeTypes.contains(type);
    }

    
    protected boolean isUnsafeType(ASTType type) {
    	if (type == null) {
    		return true;
    	}
    	return isUnsafeType(type.getType());
    }
    protected boolean isUnsafeType(Class type) {
    	if (type == null) {
    		return true;
    	}
    	if (type.isArray()) {
    		return isUnsafeType(type.getComponentType().getCanonicalName());
    	}
    	return isUnsafeType(type.getCanonicalName());
    }
    protected boolean isUnsafeType(String type) {
    	if (type == null) {
    		return true;
    	}
    	return this.unsafeTypes.contains(type);
    }
    
    protected boolean isSource(String type, String method) {
    	return 
    			this.sources.contains(type + "." + method) || 
    			this.sources.contains ("*." + method) || 
    			this.sources.contains(type + ".*");
    }
    
    protected boolean isSource(String type) {
    	return this.sourceTypes.contains(type);
    }
    
    @Override
	public void start(RuleContext ctx) {
    	init();
    	super.start(ctx);
    }
	
	@Override
	public void apply(List list, RuleContext rulecontext) {
		init();
        super.apply(list, rulecontext);
    }


    
    protected final void addSecurityViolation(Rule rule, RuleContext ctx, Node simpleNode, String message, String variableName) {
        Report rpt = ctx.getReport();       
        boolean isNewSecurityViolation = true;
    	

        for (Iterator i = rpt.iterator(); i.hasNext();) {
            RuleViolation ruleViolation = i.next();
    		
            if (ruleViolation != null && ruleViolation.getClass() == SecurityRuleViolation.class) {
                SecurityRuleViolation secRuleViolation = (SecurityRuleViolation) ruleViolation;	    		
		        	
                if (rule.getName().equals(secRuleViolation.getRule().getName())
                        && ctx.getSourceCodeFile().getAbsolutePath().equals(secRuleViolation.getJavaFileName())
                        && simpleNode.getBeginLine() == secRuleViolation.getJavaBeginLine()
                        && simpleNode.getEndLine()  == secRuleViolation.getJavaEndLine()) {
                    isNewSecurityViolation = false;
                }
            }
        }   

    	
        if (isNewSecurityViolation) {            
            rpt.addRuleViolation(new SecurityRuleViolation(rule, ctx, simpleNode, message, variableName));
        } 	
    }
   
    
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy