KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > detect > FindSqlInjection


1 /*
2  * FindBugs - Find bugs in Java programs
3  * Copyright (C) 2004,2005 University of Maryland
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */

19
20 package edu.umd.cs.findbugs.detect;
21
22 import java.util.Iterator JavaDoc;
23
24 import org.apache.bcel.classfile.JavaClass;
25 import org.apache.bcel.classfile.Method;
26 import org.apache.bcel.generic.ConstantPoolGen;
27 import org.apache.bcel.generic.GETSTATIC;
28 import org.apache.bcel.generic.INVOKEINTERFACE;
29 import org.apache.bcel.generic.INVOKEVIRTUAL;
30 import org.apache.bcel.generic.Instruction;
31 import org.apache.bcel.generic.InstructionHandle;
32 import org.apache.bcel.generic.LDC;
33 import org.apache.bcel.generic.MethodGen;
34
35 import edu.umd.cs.findbugs.BugInstance;
36 import edu.umd.cs.findbugs.BugReporter;
37 import edu.umd.cs.findbugs.Detector;
38 import edu.umd.cs.findbugs.ba.CFG;
39 import edu.umd.cs.findbugs.ba.CFGBuilderException;
40 import edu.umd.cs.findbugs.ba.ClassContext;
41 import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
42 import edu.umd.cs.findbugs.ba.Location;
43 import edu.umd.cs.findbugs.ba.constant.Constant;
44 import edu.umd.cs.findbugs.ba.constant.ConstantDataflow;
45 import edu.umd.cs.findbugs.ba.constant.ConstantFrame;
46
47 /**
48  * Find potential SQL injection vulnerabilities.
49  *
50  * @author David Hovemeyer
51  * @author Bill Pugh
52  */

53 public class FindSqlInjection implements Detector {
54
55     BugReporter bugReporter;
56     
57     public FindSqlInjection(BugReporter bugReporter) {
58         this.bugReporter = bugReporter;
59     }
60     
61     private boolean prescreen(ClassContext classContext, Method method) {
62         return true;
63     }
64     
65     public void visitClassContext(ClassContext classContext) {
66         JavaClass javaClass = classContext.getJavaClass();
67         Method[] methodList = javaClass.getMethods();
68
69         for (Method method : methodList) {
70             MethodGen methodGen = classContext.getMethodGen(method);
71             if (methodGen == null)
72                 continue;
73
74             if (!prescreen(classContext, method))
75                 continue;
76
77             try {
78                 analyzeMethod(classContext, method);
79             } catch (DataflowAnalysisException e) {
80                 bugReporter.logError("FindSqlInjection caught exception while analyzing " + methodGen, e);
81             } catch (CFGBuilderException e) {
82                 bugReporter.logError("FindSqlInjection caught exception while analyzing " + methodGen, e);
83             }
84         }
85     }
86     
87     private void analyzeMethod(ClassContext classContext, Method method)
88             throws DataflowAnalysisException, CFGBuilderException {
89         
90         JavaClass javaClass = classContext.getJavaClass();
91         MethodGen methodGen = classContext.getMethodGen(method);
92         if (methodGen == null) return;
93         ConstantPoolGen cpg = methodGen.getConstantPool();
94         try {
95         CFG cfg = classContext.getCFG(method);
96             ConstantDataflow dataflow
97             = classContext.getConstantDataflow(method);
98         boolean sawOpenQuote = false;
99         boolean sawCloseQuote = false;
100         boolean sawComma = false;
101         boolean sawAppend = false;
102         boolean sawUnsafeAppend = false;
103         for (Iterator JavaDoc<Location> i = cfg.locationIterator(); i.hasNext(); ) {
104                 Location location = i.next();
105                 Instruction ins = location.getHandle().getInstruction();
106                 if (ins instanceof LDC) {
107                     LDC load = (LDC) ins;
108                     Object JavaDoc value = load.getValue(cpg);
109                     if (value instanceof String JavaDoc) {
110                         String JavaDoc stringValue = ((String JavaDoc)value).trim();
111                         if (stringValue.startsWith(",") || stringValue.endsWith(","))
112                             sawComma = true;
113                         if (stringValue.endsWith("'"))
114                             sawOpenQuote = true;
115                         if (stringValue.startsWith("'"))
116                             sawCloseQuote = true;
117                     }
118                 } else if (ins instanceof INVOKEVIRTUAL) {
119                     INVOKEVIRTUAL invoke = (INVOKEVIRTUAL) ins;
120
121                     if (invoke.getMethodName(cpg).equals("append")
122                         && invoke.getClassName(cpg).startsWith("java.lang.StringB")) {
123                         sawAppend = true;
124                         InstructionHandle prev = location.getHandle().getPrev();
125                         if (prev != null) {
126                             Instruction prevIns = prev.getInstruction();
127                             if (!(prevIns instanceof LDC || prevIns instanceof GETSTATIC))
128                                 sawUnsafeAppend = true;
129                         }
130                         else sawUnsafeAppend = true;
131                     }
132                 }
133         }
134                 
135         for (Iterator JavaDoc<Location> i = cfg.locationIterator(); i.hasNext(); ) {
136             Location location = i.next();
137             
138             Instruction ins = location.getHandle().getInstruction();
139             if (!(ins instanceof INVOKEINTERFACE)) continue;
140             INVOKEINTERFACE invoke = (INVOKEINTERFACE) ins;
141
142             String JavaDoc methodName = invoke.getMethodName(cpg);
143             String JavaDoc interfaceName = invoke.getClassName(cpg);
144             if (methodName.equals("prepareStatement") && interfaceName.equals("java.sql.Connection")
145                     || methodName.startsWith("execute") && interfaceName.equals("java.sql.Statement")) {
146             ConstantFrame frame = dataflow.getFactAtLocation(location);
147                 Constant value = frame.getStackValue(0);
148             
149             if (!value.isConstantString()) {
150                 int priority = LOW_PRIORITY;
151                 if (sawAppend && sawOpenQuote && sawCloseQuote) priority = HIGH_PRIORITY;
152                 else if (sawAppend && sawComma) priority = NORMAL_PRIORITY;
153                 if (!sawUnsafeAppend) priority+=2;
154                 bugReporter.reportBug(
155                 new BugInstance(this,
156                         methodName.equals("prepareStatement")
157                         ? "SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING"
158                                 : "SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE",
159                  priority)
160                 .addClassAndMethod(methodGen, javaClass.getSourceFileName())
161                 .addSourceLine(classContext, methodGen, javaClass.getSourceFileName(), location.getHandle()));
162             }
163             }
164
165
166             }
167     } catch (RuntimeException JavaDoc e) {
168         System.out.println("Exception while checking for SQL injection in "
169                 + methodGen + " in " + javaClass.getSourceFileName());
170         e.printStackTrace(System.out);
171         }
172             
173     }
174     
175     
176     public void report() {
177     }
178 }
179
180 //vim:ts=4
181
Popular Tags