001: /*
002: * FindBugs - Find bugs in Java programs
003: * Copyright (C) 2004-2006 University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: package edu.umd.cs.findbugs.detect;
021:
022: import java.util.HashMap;
023: import java.util.Map;
024:
025: import org.apache.bcel.classfile.Code;
026:
027: import edu.umd.cs.findbugs.BugAccumulator;
028: import edu.umd.cs.findbugs.BugInstance;
029: import edu.umd.cs.findbugs.BugReporter;
030: import edu.umd.cs.findbugs.OpcodeStack;
031: import edu.umd.cs.findbugs.Priorities;
032: import edu.umd.cs.findbugs.ba.XMethod;
033: import edu.umd.cs.findbugs.bcel.OpcodeStackDetector;
034:
035: public class CrossSiteScripting extends OpcodeStackDetector {
036:
037: BugReporter bugReporter;
038:
039: BugAccumulator accumulator;
040:
041: public CrossSiteScripting(BugReporter bugReporter) {
042: this .bugReporter = bugReporter;
043: accumulator = new BugAccumulator(bugReporter);
044: }
045:
046: Map<String, OpcodeStack.Item> map = new HashMap<String, OpcodeStack.Item>();
047:
048: OpcodeStack.Item top = null;
049:
050: @Override
051: public void visit(Code code) {
052: super .visit(code);
053: map.clear();
054: accumulator.reportAccumulatedBugs();
055: }
056:
057: /*
058: * (non-Javadoc)
059: *
060: * @see edu.umd.cs.findbugs.bcel.OpcodeStackDetector#sawOpcode(int)
061: */
062: @Override
063: public void sawOpcode(int seen) {
064: if (seen == INVOKEINTERFACE) {
065: String calledClassName = getClassConstantOperand();
066: String calledMethodName = getNameConstantOperand();
067: String calledMethodSig = getSigConstantOperand();
068: if (calledClassName
069: .equals("javax/servlet/http/HttpSession")
070: && calledMethodName.equals("setAttribute")) {
071: OpcodeStack.Item value = stack.getStackItem(0);
072: OpcodeStack.Item name = stack.getStackItem(1);
073: Object nameConstant = name.getConstant();
074: if (nameConstant instanceof String)
075: map.put((String) nameConstant, value);
076: } else if (calledClassName
077: .equals("javax/servlet/http/HttpSession")
078: && calledMethodName.equals("getAttribute")) {
079: OpcodeStack.Item name = stack.getStackItem(0);
080: Object nameConstant = name.getConstant();
081: if (nameConstant instanceof String)
082: top = map.get((String) nameConstant);
083: } else
084: top = null;
085: } else if (seen == INVOKEVIRTUAL) {
086: String calledClassName = getClassConstantOperand();
087: String calledMethodName = getNameConstantOperand();
088: String calledMethodSig = getSigConstantOperand();
089: // System.out.println(calledClassName + "." + calledMethodName);
090: if (calledMethodName.startsWith("print")
091: && calledClassName
092: .equals("javax/servlet/jsp/JspWriter")
093: && (calledMethodSig.equals("(Ljava/lang/Object;)V") || calledMethodSig
094: .equals("(Ljava/lang/String;)V"))) {
095: OpcodeStack.Item writing = stack.getStackItem(0);
096: XMethod method = writing.getReturnValueOf();
097: if (isTainted(writing))
098: accumulator.accumulateBug(new BugInstance(this ,
099: "XSS_REQUEST_PARAMETER_TO_JSP_WRITER",
100: Priorities.HIGH_PRIORITY)
101: .addClassAndMethod(this ), this );
102:
103: else if (isTainted(top))
104: accumulator.accumulateBug(new BugInstance(this ,
105: "XSS_REQUEST_PARAMETER_TO_JSP_WRITER",
106: Priorities.NORMAL_PRIORITY)
107: .addClassAndMethod(this ), this );
108: } else if (calledMethodName.startsWith("print")
109: && calledClassName.equals("java/io/PrintWriter")
110: && (calledMethodSig.equals("(Ljava/lang/Object;)V") || calledMethodSig
111: .equals("(Ljava/lang/String;)V"))) {
112: OpcodeStack.Item writing = stack.getStackItem(0);
113: OpcodeStack.Item writingTo = stack.getStackItem(1);
114: if (isTainted(writing) && isServletWriter(writingTo))
115: accumulator.accumulateBug(new BugInstance(this ,
116: "XSS_REQUEST_PARAMETER_TO_SERVLET_WRITER",
117: Priorities.HIGH_PRIORITY)
118: .addClassAndMethod(this ), this );
119: else if (isTainted(top) && isServletWriter(writingTo))
120: accumulator.accumulateBug(new BugInstance(this ,
121: "XSS_REQUEST_PARAMETER_TO_SERVLET_WRITER",
122: Priorities.NORMAL_PRIORITY)
123: .addClassAndMethod(this ), this );
124:
125: }
126: top = null;
127: } else
128: top = null;
129: }
130:
131: private boolean isTainted(OpcodeStack.Item writing) {
132: if (writing == null)
133: return false;
134: XMethod method = writing.getReturnValueOf();
135: return method != null
136: && method.getName().equals("getParameter")
137: && method.getClassName().equals(
138: "javax.servlet.http.HttpServletRequest");
139: }
140:
141: private boolean isServletWriter(OpcodeStack.Item writingTo) {
142: XMethod writingToSource = writingTo.getReturnValueOf();
143:
144: return writingToSource != null
145: && writingToSource.getClassName().equals(
146: "javax.servlet.http.HttpServletResponse")
147: && writingToSource.getName().equals("getWriter");
148: }
149:
150: }
|