Restructured the baseline to remove extra src/main directory structure. Added eclipes project file

git-svn-id: http://webgoat.googlecode.com/svn/branches/webgoat-6.0@485 4033779f-a91e-0410-96ef-6bf7bf53c507
This commit is contained in:
mayhew64@gmail.com
2012-11-19 23:57:51 +00:00
parent fb938e0933
commit 6a96547ef0
1204 changed files with 85 additions and 2 deletions

View File

@ -0,0 +1,57 @@
package org.owasp.webgoat.lessons.instructor.CrossSiteScripting;
import java.util.regex.Pattern;
import org.owasp.webgoat.lessons.CrossSiteScripting.FindProfile;
import org.owasp.webgoat.lessons.GoatHillsFinancial.GoatHillsFinancial;
import org.owasp.webgoat.lessons.GoatHillsFinancial.LessonAction;
import org.owasp.webgoat.session.ParameterNotFoundException;
import org.owasp.webgoat.session.ValidationException;
import org.owasp.webgoat.session.WebSession;
// STAGE 5 FIXES
// Solution Summary: Edit FindProfile.java and change getRequestParameter().
// Modify getRequestParameter() with lines denoted by // STAGE 5 - FIX.
// Solution Steps:
// 1. Talk about the different parser methods. We could have used the parser method that takes a
// regular expression.
// 2. Call validate on the request parameter.
// return validate(s.getParser().getRawParameter(name), (Pattern) patterns.get(name));
//
// Note: patterns.get(name) is used to fetch the XSS validation pattern that is defined
// in FindProfile.Java
//
// protected static Map patterns = new HashMap();
// static
// {
// patterns.put(CrossSiteScripting.SEARCHNAME, Pattern.compile("[a-zA-Z ]{0,20}"));
// }
public class FindProfile_i extends FindProfile
{
public FindProfile_i(GoatHillsFinancial lesson, String lessonName, String actionName, LessonAction chainedAction)
{
super(lesson, lessonName, actionName, chainedAction);
}
protected String getRequestParameter(WebSession s, String name) throws ParameterNotFoundException,
ValidationException
{
// NOTE:
//
// In order for this to work generically, the name of the parameter and the name
// of the regular expression validation patter must be the same.
//
// Another way this could be done is to use the reguler expression method in the
// ParameterParser class
// STAGE 5 - FIX
return validate(s.getParser().getRawParameter(name), (Pattern) patterns.get(name));
// Note the design goal here...
// return s.getParser().getStringParameter(name), (Pattern) patterns.get(name));
}
}

View File

@ -0,0 +1,112 @@
package org.owasp.webgoat.lessons.instructor.CrossSiteScripting;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.owasp.webgoat.lessons.CrossSiteScripting.CrossSiteScripting;
import org.owasp.webgoat.lessons.CrossSiteScripting.UpdateProfile;
import org.owasp.webgoat.lessons.GoatHillsFinancial.GoatHillsFinancial;
import org.owasp.webgoat.lessons.GoatHillsFinancial.LessonAction;
import org.owasp.webgoat.session.Employee;
import org.owasp.webgoat.session.ParameterNotFoundException;
import org.owasp.webgoat.session.ParameterParser;
import org.owasp.webgoat.session.ValidationException;
import org.owasp.webgoat.session.WebSession;
// STAGE 2 FIXES
// Solution Summary: Edit UpdateProfile.java and change parseEmployeeProfile().
// Modify parseEmployeeProfile() with lines denoted by // STAGE 2 - FIX.
// Solution Steps:
// 1. Talk about the different parser methods.
// a. parseEmployeeProfile(subjectId, s.getRequest())
// - uses the request object directly.
// - calling validate() on the appropriate parameter
// b. parseEmployeeProfile(subjectId, s.getParser())
// - uses the parser object to pull request data (centralized mechanism)
//
// 2. Fix the request object version of the call // STAGE 2 - FIX
// Replace the call to:
// String address1 = request.getParameter(CrossSiteScripting.ADDRESS1);
//
// With:
// final Pattern PATTERN_ADDRESS1 = Pattern.compile("[a-zA-Z0-9,\\.\\- ]{0,80}"); // STAGE 2 - FIX
// String address1 = validate(request.getParameter(CrossSiteScripting.ADDRESS1), PATTERN_ADDRESS1);
// // STAGE 2 - FIX
//
//
// 3. Fix the parser version of the call. // STAGE 2 - ALTERNATE FIX
// Change all calls in parseEmployeeProfile(subjectId, s.getParser()) to use
// the appropriate parser.method() call
//
public class UpdateProfile_i extends UpdateProfile
{
public UpdateProfile_i(GoatHillsFinancial lesson, String lessonName, String actionName, LessonAction chainedAction)
{
super(lesson, lessonName, actionName, chainedAction);
}
protected Employee parseEmployeeProfile(int subjectId, WebSession s) throws ParameterNotFoundException,
ValidationException
{
HttpServletRequest request = s.getRequest();
String firstName = request.getParameter(CrossSiteScripting.FIRST_NAME);
String lastName = request.getParameter(CrossSiteScripting.LAST_NAME);
String ssn = request.getParameter(CrossSiteScripting.SSN);
String title = request.getParameter(CrossSiteScripting.TITLE);
String phone = request.getParameter(CrossSiteScripting.PHONE_NUMBER);
// Validate this parameter against a regular expression pattern designed for street
// addresses.
// STAGE 2 - FIX
final Pattern PATTERN_ADDRESS1 = Pattern.compile("[a-zA-Z0-9,\\.\\- ]{0,80}");
String address1 = validate(request.getParameter(CrossSiteScripting.ADDRESS1), PATTERN_ADDRESS1);
String address2 = request.getParameter(CrossSiteScripting.ADDRESS2);
int manager = Integer.parseInt(request.getParameter(CrossSiteScripting.MANAGER));
String startDate = request.getParameter(CrossSiteScripting.START_DATE);
int salary = Integer.parseInt(request.getParameter(CrossSiteScripting.SALARY));
String ccn = request.getParameter(CrossSiteScripting.CCN);
int ccnLimit = Integer.parseInt(request.getParameter(CrossSiteScripting.CCN_LIMIT));
String disciplinaryActionDate = request.getParameter(CrossSiteScripting.DISCIPLINARY_DATE);
String disciplinaryActionNotes = request.getParameter(CrossSiteScripting.DISCIPLINARY_NOTES);
String personalDescription = request.getParameter(CrossSiteScripting.DESCRIPTION);
Employee employee = new Employee(subjectId, firstName, lastName, ssn, title, phone, address1, address2,
manager, startDate, salary, ccn, ccnLimit, disciplinaryActionDate, disciplinaryActionNotes,
personalDescription);
return employee;
}
protected Employee parseEmployeeProfile(int subjectId, ParameterParser parser) throws ParameterNotFoundException,
ValidationException
{
// STAGE 2 - ALTERNATE FIX
String firstName = parser.getStrictAlphaParameter(CrossSiteScripting.FIRST_NAME, 20);
String lastName = parser.getStrictAlphaParameter(CrossSiteScripting.LAST_NAME, 20);
String ssn = parser.getSsnParameter(CrossSiteScripting.SSN);
String title = parser.getStrictAlphaParameter(CrossSiteScripting.TITLE, 20);
String phone = parser.getPhoneParameter(CrossSiteScripting.PHONE_NUMBER);
String address1 = parser.getStringParameter(CrossSiteScripting.ADDRESS1);
String address2 = parser.getStringParameter(CrossSiteScripting.ADDRESS2);
int manager = parser.getIntParameter(CrossSiteScripting.MANAGER);
String startDate = parser.getDateParameter(CrossSiteScripting.START_DATE);
int salary = parser.getIntParameter(CrossSiteScripting.SALARY);
String ccn = parser.getCcnParameter(CrossSiteScripting.CCN);
int ccnLimit = parser.getIntParameter(CrossSiteScripting.CCN_LIMIT);
String disciplinaryActionDate = parser.getDateParameter(CrossSiteScripting.DISCIPLINARY_DATE);
String disciplinaryActionNotes = parser.getStrictAlphaParameter(CrossSiteScripting.DISCIPLINARY_NOTES, 60);
String personalDescription = parser.getStrictAlphaParameter(CrossSiteScripting.DESCRIPTION, 60);
Employee employee = new Employee(subjectId, firstName, lastName, ssn, title, phone, address1, address2,
manager, startDate, salary, ccn, ccnLimit, disciplinaryActionDate, disciplinaryActionNotes,
personalDescription);
return employee;
}
}

View File

@ -0,0 +1,22 @@
package org.owasp.webgoat.lessons.instructor.CrossSiteScripting;
import org.owasp.webgoat.lessons.CrossSiteScripting.ViewProfile;
import org.owasp.webgoat.lessons.GoatHillsFinancial.GoatHillsFinancial;
// STAGE 4 FIXES
//
//Solution Summary: Look in the WebContent/lesson/CrossSiteScripting/ViewProfile.jsp
//
//Look for the <-- STAGE 4 - FIX in the ViewProfile.jsp
//
//
public class ViewProfile_i extends ViewProfile
{
public ViewProfile_i(GoatHillsFinancial lesson, String lessonName, String actionName)
{
super(lesson, lessonName, actionName);
}
}

View File

@ -0,0 +1,17 @@
using System.Data.SqlTypes;
using System.Text.RegularExpressions;
using Microsoft.SqlServer.Server;
public static partial class UserDefinedFunctions
{
public static readonly RegexOptions Options =
RegexOptions.IgnorePatternWhitespace |
RegexOptions.Compiled | RegexOptions.Singleline;
[SqlFunction]
public static SqlBoolean RegexMatch( SqlChars input, SqlString pattern )
{
Regex regex = new Regex( pattern.Value, Options );
return regex.IsMatch( new string( input.Value ) );
}
}

View File

@ -0,0 +1,138 @@
package org.owasp.webgoat.lessons.instructor.DBCrossSiteScripting;
import org.owasp.webgoat.lessons.GoatHillsFinancial.LessonAction;
import org.owasp.webgoat.lessons.CrossSiteScripting.UpdateProfile;
import org.owasp.webgoat.lessons.GoatHillsFinancial.GoatHillsFinancial;
/* STAGE 2 FIXES
Solution Summary (1. or 2.)
1. Modify the UPDATE_EMPLOYEE stored procedure in the database and add
a validation step. Oracle 10G now supports regular expressions.
2. Apply a column constraint can also work IFF the existing data is clean
Solution Steps:
1. Talk about the different database approaches.
a. Apply validation in the UPDATE stored proc
- Possible to bypass by not using that stored proc
b. Apply a table column constraint
- Cannot be bypassed. The DB enforces the constraint under all conditions
2. Fix the stored proc
Define the pattern.
Validate the field against the pattern.
Raise an exception if invalid.
CREATE OR REPLACE PROCEDURE UPDATE_EMPLOYEE(
v_userid IN employee.userid%type,
v_first_name IN employee.first_name%type,
v_last_name IN employee.last_name%type,
v_ssn IN employee.ssn%type,
v_title IN employee.title%type,
v_phone IN employee.phone%type,
v_address1 IN employee.address1%type,
v_address2 IN employee.address2%type,
v_manager IN employee.manager%type,
v_start_date IN employee.start_date%type,
v_salary IN employee.salary%type,
v_ccn IN employee.ccn%type,
v_ccn_limit IN employee.ccn_limit%type,
v_disciplined_date IN employee.disciplined_date%type,
v_disciplined_notes IN employee.disciplined_notes%type,
v_personal_description IN employee.personal_description%type
)
AS
P_ADDRESS1 VARCHAR2(100) := '^[a-zA-Z0-9,\. ]{0,80}$';
BEGIN
IF NOT REGEXP_LIKE(v_address1, P_ADDRESS1) THEN
RAISE VALUE_ERROR;
END IF;
UPDATE EMPLOYEE
SET
first_name = v_first_name,
last_name = v_last_name,
ssn = v_ssn,
title = v_title,
phone = v_phone,
address1 = v_address1,
address2 = v_address2,
manager = v_manager,
start_date = v_Start_date,
salary = v_salary,
ccn = v_ccn,
ccn_limit = v_ccn_limit,
disciplined_date = v_disciplined_date,
disciplined_notes = v_disciplined_notes,
personal_description = v_personal_description
WHERE
userid = v_userid;
END;
/
3. Apply a table column constraint
ALTER TABLE EMPLOYEE
ADD CONSTRAINT address1_ck CHECK (REGEXP_LIKE(address1, '^[a-zA-Z0-9,\. ]{0,80}$'));
FOR SQL SERVER, the following is required:
DROP PROCEDURE webgoat_guest.UPDATE_EMPLOYEE
GO
CREATE PROCEDURE webgoat_guest.UPDATE_EMPLOYEE
@v_userid INT,
@v_first_name VARCHAR(20),
@v_last_name VARCHAR(20),
@v_ssn VARCHAR(12),
@v_title VARCHAR(20),
@v_phone VARCHAR(13),
@v_address1 VARCHAR(80),
@v_address2 VARCHAR(80),
@v_manager INT,
@v_start_date CHAR(8),
@v_salary INT,
@v_ccn VARCHAR(30),
@v_ccn_limit INT,
@v_disciplined_date CHAR(8),
@v_disciplined_notes VARCHAR(60),
@v_personal_description VARCHAR(60)
AS
IF [webgoat_guest].RegexMatch(@v_address1, N'^[a-zA-Z0-9,\. ]{0,80}$') = 0
BEGIN
RAISERROR('Illegal characters in address1', 11, 1)
RETURN
END
UPDATE EMPLOYEE
SET
first_name = @v_first_name,
last_name = @v_last_name,
ssn = @v_ssn,
title = @v_title,
phone = @v_phone,
address1 = @v_address1,
address2 = @v_address2,
manager = @v_manager,
start_date = @v_Start_date,
salary = @v_salary,
ccn = @v_ccn,
ccn_limit = @v_ccn_limit,
disciplined_date = @v_disciplined_date,
disciplined_notes = @v_disciplined_notes,
personal_description = @v_personal_description
WHERE
userid = @v_userid;
GO
*/
public class UpdateProfile_i extends UpdateProfile
{
public UpdateProfile_i(GoatHillsFinancial lesson, String lessonName, String actionName, LessonAction chainedAction)
{
super(lesson, lessonName, actionName, chainedAction);
}
}

View File

@ -0,0 +1,45 @@
package org.owasp.webgoat.lessons.instructor.DBSQLInjection;
/*
* The solution is to choose Neville's userid, and enter a password like:
* ' OR '1'='1
* Modify the Stored function LOGIN_EMPLOYEE to use fixed statements or bind variables
*
*
* For ORACLE:
CREATE OR REPLACE FUNCTION WEBGOAT_guest.EMPLOYEE_LOGIN(v_id NUMBER, v_password VARCHAR) RETURN NUMBER AS
cnt NUMBER;
BEGIN
SELECT COUNT(*) INTO cnt FROM EMPLOYEE
WHERE USERID = v_id
AND PASSWORD = v_password;
RETURN cnt;
END;
/
* OR
CREATE OR REPLACE FUNCTION WEBGOAT_guest.EMPLOYEE_LOGIN(v_id NUMBER, v_password VARCHAR) RETURN NUMBER AS
stmt VARCHAR(32767); cnt NUMBER;
BEGIN
stmt := 'SELECT COUNT (*) FROM EMPLOYEE WHERE USERID = :1 AND PASSWORD = :2';
EXECUTE IMMEDIATE stmt INTO cnt USING v_id, v_password;
RETURN cnt;
END;
/
* For SQL SERVER
CREATE FUNCTION webgoat_guest.EMPLOYEE_LOGIN (
@v_id INT,
@v_password VARCHAR(100)
) RETURNS INTEGER
AS
BEGIN
DECLARE @count int
SELECT @count = COUNT(*) FROM EMPLOYEE WHERE USERID = @v_id AND PASSWORD = @v_password;
return @count
END
*/

View File

@ -0,0 +1,53 @@
package org.owasp.webgoat.lessons.instructor.RoleBasedAccessControl;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.owasp.webgoat.lessons.GoatHillsFinancial.GoatHillsFinancial;
import org.owasp.webgoat.lessons.GoatHillsFinancial.LessonAction;
import org.owasp.webgoat.lessons.RoleBasedAccessControl.DeleteProfile;
import org.owasp.webgoat.lessons.RoleBasedAccessControl.RoleBasedAccessControl;
import org.owasp.webgoat.session.UnauthorizedException;
import org.owasp.webgoat.session.WebSession;
public class DeleteProfile_i extends DeleteProfile
{
public DeleteProfile_i(GoatHillsFinancial lesson, String lessonName, String actionName, LessonAction chainedAction)
{
super(lesson, lessonName, actionName, chainedAction);
}
public void doDeleteEmployeeProfile(WebSession s, int userId, int employeeId) throws UnauthorizedException
{
if (s.isAuthorizedInLesson(userId, RoleBasedAccessControl.DELETEPROFILE_ACTION)) // FIX
{
try
{
String query = "DELETE FROM employee WHERE userid = " + employeeId;
// System.out.println("Query: " + query);
try
{
Statement statement = WebSession.getConnection(s)
.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
statement.executeUpdate(query);
} catch (SQLException sqle)
{
s.setMessage("Error deleting employee profile");
sqle.printStackTrace();
}
} catch (Exception e)
{
s.setMessage("Error deleting employee profile");
e.printStackTrace();
}
}
else
{
throw new UnauthorizedException(); // FIX
}
}
}

View File

@ -0,0 +1,101 @@
package org.owasp.webgoat.lessons.instructor.RoleBasedAccessControl;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.owasp.webgoat.lessons.GoatHillsFinancial.GoatHillsFinancial;
import org.owasp.webgoat.lessons.RoleBasedAccessControl.EditProfile;
import org.owasp.webgoat.lessons.RoleBasedAccessControl.RoleBasedAccessControl;
import org.owasp.webgoat.session.Employee;
import org.owasp.webgoat.session.UnauthorizedException;
import org.owasp.webgoat.session.WebSession;
/**
* Copyright (c) 2006 Free Software Foundation developed under the custody of the Open Web
* Application Security Project (http://www.owasp.org) This software package org.owasp.webgoat.is
* published by OWASP under the GPL. You should read and accept the LICENSE before you use, modify
* and/or redistribute this software.
*
*/
/*************************************************/
/* */
/* This file is not currently used in the course */
/* */
/*************************************************/
public class EditProfile_i extends EditProfile
{
public EditProfile_i(GoatHillsFinancial lesson, String lessonName, String actionName)
{
super(lesson, lessonName, actionName);
}
public Employee getEmployeeProfile(WebSession s, int userId, int subjectUserId) throws UnauthorizedException
{
// Query the database to determine if this employee has access to this function
// Query the database for the profile data of the given employee if "owned" by the given
// user
Employee profile = null;
if (s.isAuthorizedInLesson(userId, RoleBasedAccessControl.EDITPROFILE_ACTION)) // FIX
{
// Query the database for the profile data of the given employee
try
{
String query = "SELECT * FROM employee WHERE userid = ?";
try
{
PreparedStatement answer_statement = WebSession.getConnection(s)
.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
answer_statement.setInt(1, subjectUserId);
ResultSet answer_results = answer_statement.executeQuery();
if (answer_results.next())
{
// Note: Do NOT get the password field.
profile = new Employee(
answer_results.getInt("userid"),
answer_results.getString("first_name"),
answer_results.getString("last_name"),
answer_results.getString("ssn"),
answer_results.getString("title"),
answer_results.getString("phone"),
answer_results.getString("address1"),
answer_results.getString("address2"),
answer_results.getInt("manager"),
answer_results.getString("start_date"),
answer_results.getInt("salary"),
answer_results.getString("ccn"),
answer_results.getInt("ccn_limit"),
answer_results.getString("disciplined_date"),
answer_results.getString("disciplined_notes"),
answer_results.getString("personal_description"));
/*
* System.out.println("Retrieved employee from db: " +
* profile.getFirstName() + " " + profile.getLastName() + " (" +
* profile.getId() + ")");
*/}
} catch (SQLException sqle)
{
s.setMessage("Error getting employee profile");
sqle.printStackTrace();
}
} catch (Exception e)
{
s.setMessage("Error getting employee profile");
e.printStackTrace();
}
}
else
{
throw new UnauthorizedException(); // FIX
}
return profile;
}
}

View File

@ -0,0 +1,176 @@
package org.owasp.webgoat.lessons.instructor.RoleBasedAccessControl;
import org.apache.ecs.ElementContainer;
import org.owasp.webgoat.lessons.GoatHillsFinancial.DefaultLessonAction;
import org.owasp.webgoat.lessons.GoatHillsFinancial.GoatHillsFinancial;
import org.owasp.webgoat.lessons.GoatHillsFinancial.LessonAction;
import org.owasp.webgoat.lessons.RoleBasedAccessControl.RoleBasedAccessControl;
import org.owasp.webgoat.session.ParameterNotFoundException;
import org.owasp.webgoat.session.UnauthenticatedException;
import org.owasp.webgoat.session.UnauthorizedException;
import org.owasp.webgoat.session.ValidationException;
import org.owasp.webgoat.session.WebSession;
/**
* Copyright (c) 2006 Free Software Foundation developed under the custody of the Open Web
* Application Security Project (http://www.owasp.org) This software package org.owasp.webgoat.is
* published by OWASP under the GPL. You should read and accept the LICENSE before you use, modify
* and/or redistribute this software.
*
*/
/* STAGE 2 FIXES
Solution Summary: Edit RoleBasedAccessControl.java and change handleRequest().
Modify handleRequest() with lines denoted by // STAGE 2 - FIX.
Solution Steps:
1. This solution adds an access control check in the controller.
Point out that their architecture may require the check to occur in the business function.
2. Look at the RoleBasedAccessControl class identify where execution happens of an action.
a. action.handleRequest(s); is not protected by an access control check.
b. look at handleRequest(s) to determine where access control check should occur.
c. add protection by a programmatic authorization check before dispatching to the action:
1. Add an isAuthorized() call before dispatching to the action,
and throw an unauthorized exception. Tell student this exception exists.
Use eclipse command completion to find the isAuthorized() call on the action.
From command completion - determine calling arguments of isAuthorized()
int userId = action.getUserId(s);
if (action.isAuthorized(s, userId, action.getActionName()))
{
action.handleRequest(s);
}
else
throw new UnauthorizedException();
Repeat stage 1 and note that the function fails with a "Not authorized" message.
Tom will be in the list again, because the DB is reset when lesson restarts.
Adding the access check in the RoleBasedAccessControl:handleRequest() is putting the check in the <20>Controller<65>
The access check can also be added to DeleteProfile.deleteEmployeeProfile(), which is putting the check in the <20>Business Function<6F>
*/
public class RoleBasedAccessControl_i extends RoleBasedAccessControl
{
public void handleRequest(WebSession s)
{
// System.out.println("RoleBasedAccessControl.handleRequest()");
if (s.getLessonSession(this) == null) s.openLessonSession(this);
String requestedActionName = null;
try
{
requestedActionName = s.getParser().getStringParameter("action");
} catch (ParameterNotFoundException pnfe)
{
// Missing the action - send them back to login.
requestedActionName = LOGIN_ACTION;
}
try
{
LessonAction action = getAction(requestedActionName);
if (action != null)
{
// FIXME: This code has gotten much uglier
// System.out.println("RoleBasedAccessControl.handleRequest() dispatching to: " +
// action.getActionName());
if (!action.requiresAuthentication())
{
// Access to Login does not require authentication.
action.handleRequest(s);
}
else
{
if (action.isAuthenticated(s))
{
int userId = action.getUserId(s); // STAGE 2 - FIX
// action.getActionName() returns the user requested function which
// is tied to the button click from the listStaff jsp
//
// Checking isAuthorized() for the requested action
if (action.isAuthorized(s, userId, action.getActionName())) // STAGE 2 - FIX
{
// Calling the handleRequest() method for the requested action
action.handleRequest(s);
}
else
throw new UnauthorizedException(); // STAGE 2 - FIX
}
else
throw new UnauthenticatedException();
}
}
else
setCurrentAction(s, ERROR_ACTION);
} catch (ParameterNotFoundException pnfe)
{
// System.out.println("Missing parameter");
pnfe.printStackTrace();
setCurrentAction(s, ERROR_ACTION);
} catch (ValidationException ve)
{
// System.out.println("Validation failed");
ve.printStackTrace();
setCurrentAction(s, ERROR_ACTION);
} catch (UnauthenticatedException ue)
{
s.setMessage("Login failed");
// System.out.println("Authentication failure");
ue.printStackTrace();
} catch (UnauthorizedException ue2)
{
String stage = getStage(s);
// Update lesson status if necessary.
if (STAGE2.equals(stage))
{
try
{
if (GoatHillsFinancial.DELETEPROFILE_ACTION.equals(requestedActionName)
&& !isAuthorized(s, getUserId(s), GoatHillsFinancial.DELETEPROFILE_ACTION))
{
setStageComplete(s, STAGE2);
}
} catch (ParameterNotFoundException pnfe)
{
pnfe.printStackTrace();
}
}
// System.out.println("isAuthorized() exit stage: " + getStage(s));
// Update lesson status if necessary.
if (STAGE4.equals(stage))
{
try
{
// System.out.println("Checking for stage 4 completion");
DefaultLessonAction action = (DefaultLessonAction) getAction(getCurrentAction(s));
int userId = Integer.parseInt((String) s.getRequest().getSession()
.getAttribute(getLessonName() + "." + GoatHillsFinancial.USER_ID));
int employeeId = s.getParser().getIntParameter(GoatHillsFinancial.EMPLOYEE_ID);
if (!action.isAuthorizedForEmployee(s, userId, employeeId))
{
setStageComplete(s, STAGE4);
}
} catch (Exception e)
{
// swallow this - shouldn't happen inthe normal course
// e.printStackTrace();
}
}
s.setMessage("You are not authorized to perform this function");
// System.out.println("Authorization failure");
setCurrentAction(s, ERROR_ACTION);
ue2.printStackTrace();
}
// All this does for this lesson is ensure that a non-null content exists.
setContent(new ElementContainer());
}
}

View File

@ -0,0 +1,135 @@
package org.owasp.webgoat.lessons.instructor.RoleBasedAccessControl;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.owasp.webgoat.lessons.GoatHillsFinancial.GoatHillsFinancial;
import org.owasp.webgoat.lessons.GoatHillsFinancial.LessonAction;
import org.owasp.webgoat.lessons.RoleBasedAccessControl.RoleBasedAccessControl;
import org.owasp.webgoat.lessons.RoleBasedAccessControl.UpdateProfile;
import org.owasp.webgoat.session.Employee;
import org.owasp.webgoat.session.UnauthorizedException;
import org.owasp.webgoat.session.WebSession;
/**
* Copyright (c) 2006 Free Software Foundation developed under the custody of the Open Web
* Application Security Project (http://www.owasp.org) This software package org.owasp.webgoat.is
* published by OWASP under the GPL. You should read and accept the LICENSE before you use, modify
* and/or redistribute this software.
*
*/
/*************************************************/
/* */
/* This file is not currently used in the course */
/* */
/*************************************************/
public class UpdateProfile_i extends UpdateProfile
{
public UpdateProfile_i(GoatHillsFinancial lesson, String lessonName, String actionName, LessonAction chainedAction)
{
super(lesson, lessonName, actionName, chainedAction);
}
public void changeEmployeeProfile(WebSession s, int userId, int subjectId, Employee employee)
throws UnauthorizedException
{
if (s.isAuthorizedInLesson(userId, RoleBasedAccessControl.UPDATEPROFILE_ACTION)) // FIX
{
try
{
// Note: The password field is ONLY set by ChangePassword
String query = "UPDATE employee SET first_name = ?, last_name = ?, ssn = ?, title = ?, phone = ?, address1 = ?, address2 = ?,"
+ " manager = ?, start_date = ?, ccn = ?, ccn_limit = ?,"
+ " personal_description = ? WHERE userid = ?;";
try
{
PreparedStatement ps = WebSession.getConnection(s)
.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ps.setString(1, employee.getFirstName());
ps.setString(2, employee.getLastName());
ps.setString(3, employee.getSsn());
ps.setString(4, employee.getTitle());
ps.setString(5, employee.getPhoneNumber());
ps.setString(6, employee.getAddress1());
ps.setString(7, employee.getAddress2());
ps.setInt(8, employee.getManager());
ps.setString(9, employee.getStartDate());
ps.setString(10, employee.getCcn());
ps.setInt(11, employee.getCcnLimit());
ps.setString(12, employee.getPersonalDescription());
ps.setInt(13, subjectId);
ps.execute();
} catch (SQLException sqle)
{
s.setMessage("Error updating employee profile");
sqle.printStackTrace();
}
} catch (Exception e)
{
s.setMessage("Error updating employee profile");
e.printStackTrace();
}
}
else
{
throw new UnauthorizedException(); // FIX
}
}
public void createEmployeeProfile(WebSession s, int userId, Employee employee) throws UnauthorizedException
{
if (s.isAuthorizedInLesson(userId, RoleBasedAccessControl.UPDATEPROFILE_ACTION)) // FIX
{
try
{
// FIXME: Cannot choose the id because we cannot guarantee uniqueness
int nextId = getNextUID(s);
String query = "INSERT INTO employee VALUES ( " + nextId + ", ?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
// System.out.println("Query: " + query);
try
{
PreparedStatement ps = WebSession.getConnection(s).prepareStatement(query);
ps.setString(1, employee.getFirstName().toLowerCase());
ps.setString(2, employee.getLastName());
ps.setString(3, employee.getSsn());
ps.setString(4, employee.getTitle());
ps.setString(5, employee.getPhoneNumber());
ps.setString(6, employee.getAddress1());
ps.setString(7, employee.getAddress2());
ps.setInt(8, employee.getManager());
ps.setString(9, employee.getStartDate());
ps.setString(10, employee.getCcn());
ps.setInt(11, employee.getCcnLimit());
ps.setString(12, employee.getDisciplinaryActionDate());
ps.setString(13, employee.getDisciplinaryActionNotes());
ps.setString(14, employee.getPersonalDescription());
ps.execute();
} catch (SQLException sqle)
{
s.setMessage("Error updating employee profile");
sqle.printStackTrace();
}
} catch (Exception e)
{
s.setMessage("Error updating employee profile");
e.printStackTrace();
}
}
else
{
throw new UnauthorizedException(); // FIX
}
}
}

View File

@ -0,0 +1,133 @@
package org.owasp.webgoat.lessons.instructor.RoleBasedAccessControl;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.owasp.webgoat.lessons.GoatHillsFinancial.GoatHillsFinancial;
import org.owasp.webgoat.lessons.RoleBasedAccessControl.ViewProfile;
import org.owasp.webgoat.session.Employee;
import org.owasp.webgoat.session.UnauthorizedException;
import org.owasp.webgoat.session.WebSession;
/* STAGE 4 FIXES
1. Find the code location where this flaw of directly retrieving the profile without data-level access control checking exists:
public void handleRequest( WebSession s )
{ <09>
Employee employee = getEmployeeProfile(s, userId, employeeId);
<09> }
public Employee getEmployeeProfile(WebSession s, int employeeId, int subjectUserId) throws UnauthorizedException { <09>
return getEmployeeProfile(s, employeeId, subjectUserId);
<09> }
2. The solution requires a data-level access control check to ensure the user has the rights to access the data they are requesting.
a. There is a common method you can take advantage of:
isAuthorizedForEmployee(s, userId, subjectUserId)
Either tell the student this exists or have them look in DefaultLessonAction.
Note that this is not required to implement data access control but is for detection of violations.
b. Uncomment the modified query retrieving the user data to have data access control
String query = "SELECT * FROM employee,ownership WHERE employee.userid = ownership.employee_id and " +
"ownership.employer_id = " + userId + " and ownership.employee_id = " + subjectUserId;
3. Bundle the entire logic with this call and throw an unauthorized exception
if (isAuthorizedForEmployee(s, userId, subjectUserId))
{ ...
//String query = "SELECT * FROM employee WHERE userid = " + subjectUserId;
String query = "SELECT * FROM employee,ownership WHERE employee.userid = ownership.employee_id and " +
"ownership.employer_id = " + userId + " and ownership.employee_id = " + subjectUserId; // STAGE 4 - FIX
...
}
else
{
throw new UnauthorizedException();
}
4. Repeat stage 3 and note that the function fails with a "Not authorized" message.
Adding the access check in the query is providing data-level access control.
The access check from isAuthorizedForEmployee is used to detect a violation.
The same logic could've been applied after the query but isAuthorizedForEmployee provides a nice centralized abstraction of that logic.
*/
public class ViewProfile_i extends ViewProfile
{
public ViewProfile_i(GoatHillsFinancial lesson, String lessonName, String actionName)
{
super(lesson, lessonName, actionName);
}
public Employee getEmployeeProfile(WebSession s, int userId, int subjectUserId) throws UnauthorizedException
{
// Query the database to determine if the given employee is owned by the given user
// Query the database for the profile data of the given employee
Employee profile = null;
// isAuthorizedForEmployee() allows us to determine authorization violations
if (isAuthorizedForEmployee(s, userId, subjectUserId)) // STAGE 4 - (ALTERNATE) FIX
{
// Query the database for the profile data of the given employee
try
{
// STAGE 4 - FIX
// String query = "SELECT * FROM employee WHERE userid = " + subjectUserId;
// Switch to this query to add Data Access Control
//
// Join employee and ownership to get all valid record combinations
// - qualify on ownership.employer_id to see only the current userId records
// - qualify on ownership.employee_id to see the current selected employee profile
// STAGE 4 - FIX
String query = "SELECT * FROM employee,ownership WHERE employee.userid = ownership.employee_id and "
+ "ownership.employer_id = " + userId + " and ownership.employee_id = " + subjectUserId;
try
{
Statement answer_statement = WebSession.getConnection(s)
.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet answer_results = answer_statement.executeQuery(query);
if (answer_results.next())
{
// Note: Do NOT get the password field.
profile = new Employee(
answer_results.getInt("userid"),
answer_results.getString("first_name"),
answer_results.getString("last_name"),
answer_results.getString("ssn"),
answer_results.getString("title"),
answer_results.getString("phone"),
answer_results.getString("address1"),
answer_results.getString("address2"),
answer_results.getInt("manager"),
answer_results.getString("start_date"),
answer_results.getInt("salary"),
answer_results.getString("ccn"),
answer_results.getInt("ccn_limit"),
answer_results.getString("disciplined_date"),
answer_results.getString("disciplined_notes"),
answer_results.getString("personal_description"));
/* System.out.println("Retrieved employee from db: " +
profile.getFirstName() + " " + profile.getLastName() +
" (" + profile.getId() + ")");
*/ }
}
catch ( SQLException sqle )
{
s.setMessage("Error getting employee profile");
sqle.printStackTrace();
}
} catch (Exception e)
{
s.setMessage("Error getting employee profile");
e.printStackTrace();
}
}
else
{
throw new UnauthorizedException(); // STAGE 4 - ALTERNATE FIX
}
return profile;
}
}

View File

@ -0,0 +1,81 @@
package org.owasp.webgoat.lessons.instructor.SQLInjection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.owasp.webgoat.lessons.GoatHillsFinancial.GoatHillsFinancial;
import org.owasp.webgoat.lessons.GoatHillsFinancial.LessonAction;
import org.owasp.webgoat.lessons.SQLInjection.Login;
import org.owasp.webgoat.lessons.SQLInjection.SQLInjection;
import org.owasp.webgoat.session.WebSession;
/*
Solution Summary: Edit Login.java and change login().
Modify login() with lines denoted by // STAGE 2 - FIX.
Solution Steps:
1. Change dynamic query to parameterized query.
a. Replace the dynamic varaibles with the "?"
String query = "SELECT * FROM employee WHERE userid = ? and password = ?"
b. Create a preparedStatement using the new query
PreparedStatement answer_statement = SQLInjection.getConnection(s).prepareStatement(
query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY );
c. Set the values of the parameterized query
answer_statement.setString(1, userId); // STAGE 2 - FIX
answer_statement.setString(2, password); // STAGE 2 - FIX
d. Execute the preparedStatement
ResultSet answer_results = answer_statement.executeQuery();
*/
public class Login_i extends Login
{
public Login_i(GoatHillsFinancial lesson, String lessonName, String actionName, LessonAction chainedAction)
{
super(lesson, lessonName, actionName, chainedAction);
}
public boolean login(WebSession s, String userId, String password)
{
// System.out.println("Logging in to lesson");
boolean authenticated = false;
try
{
// STAGE 2 - FIX
String query = "SELECT * FROM employee WHERE userid = ? and password = ?";
try
{
// STAGE 2 - FIX
PreparedStatement answer_statement = WebSession.getConnection(s)
.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
answer_statement.setString(1, userId); // STAGE 2 - FIX
answer_statement.setString(2, password); // STAGE 2 - FIX
ResultSet answer_results = answer_statement.executeQuery(); // STAGE 2 - FIX
if (answer_results.first())
{
setSessionAttribute(s, getLessonName() + ".isAuthenticated", Boolean.TRUE);
setSessionAttribute(s, getLessonName() + "." + SQLInjection.USER_ID, userId);
authenticated = true;
}
} catch (SQLException sqle)
{
s.setMessage("Error logging in");
sqle.printStackTrace();
}
} catch (Exception e)
{
s.setMessage("Error logging in");
e.printStackTrace();
}
// System.out.println("Lesson login result: " + authenticated);
return authenticated;
}
}

View File

@ -0,0 +1,109 @@
package org.owasp.webgoat.lessons.instructor.SQLInjection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.owasp.webgoat.lessons.GoatHillsFinancial.GoatHillsFinancial;
import org.owasp.webgoat.lessons.SQLInjection.ViewProfile;
import org.owasp.webgoat.session.Employee;
import org.owasp.webgoat.session.UnauthorizedException;
import org.owasp.webgoat.session.WebSession;
import org.owasp.webgoat.util.HtmlEncoder;
/*
Solution Summary: Edit ViewProfile.java and change getEmployeeProfile().
Modify getEmployeeProfile() with lines denoted by // STAGE 4 - FIX.
Solution Steps:
1. Change dynamic query to parameterized query.
a. Replace the dynamic variables with the "?"
Old: String query = "SELECT employee.* " +
"FROM employee,ownership WHERE employee.userid = ownership.employee_id and " +
"ownership.employer_id = " + userId + " and ownership.employee_id = " + subjectUserId;
New: String query = "SELECT employee.* " +
"FROM employee,ownership WHERE employee.userid = ownership.employee_id and " +
"ownership.employer_id = ? and ownership.employee_id = ?";
b. Create a preparedStatement using the new query
PreparedStatement answer_statement = SQLInjection.getConnection(s).prepareStatement(
query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY );
c. Set the values of the parameterized query
answer_statement.setInt(1, Integer.parseInt(userId)); // STAGE 4 - FIX
answer_statement.setInt(2, Integer.parseInt(subjectUserId)); // STAGE 4 - FIX
d. Execute the preparedStatement
ResultSet answer_results = answer_statement.executeQuery();
*/
public class ViewProfile_i extends ViewProfile
{
public ViewProfile_i(GoatHillsFinancial lesson, String lessonName, String actionName)
{
super(lesson, lessonName, actionName);
}
public Employee getEmployeeProfile(WebSession s, String userId, String subjectUserId) throws UnauthorizedException
{
// Query the database to determine if this employee has access to this function
// Query the database for the profile data of the given employee if "owned" by the given
// user
Employee profile = null;
try
{
String query = "SELECT employee.* "
+ "FROM employee,ownership WHERE employee.userid = ownership.employee_id and "
+ "ownership.employer_id = ? and ownership.employee_id = ?";
try
{
// STAGE 4 - FIX
PreparedStatement answer_statement = WebSession.getConnection(s).prepareStatement( query,
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY );
answer_statement.setInt(1, Integer.parseInt(userId)); // STAGE 4 - FIX
answer_statement.setInt(2, Integer.parseInt(subjectUserId)); // STAGE 4 - FIX
ResultSet answer_results = answer_statement.executeQuery(); // STAGE 4 - FIX
if (answer_results.next())
{
// Note: Do NOT get the password field.
profile = new Employee(
answer_results.getInt("userid"),
answer_results.getString("first_name"),
answer_results.getString("last_name"),
answer_results.getString("ssn"),
answer_results.getString("title"),
answer_results.getString("phone"),
answer_results.getString("address1"),
answer_results.getString("address2"),
answer_results.getInt("manager"),
answer_results.getString("start_date"),
answer_results.getInt("salary"),
answer_results.getString("ccn"),
answer_results.getInt("ccn_limit"),
answer_results.getString("disciplined_date"),
answer_results.getString("disciplined_notes"),
answer_results.getString("personal_description"));
/* System.out.println("Retrieved employee from db: " +
profile.getFirstName() + " " + profile.getLastName() +
" (" + profile.getId() + ")");
*/ }
}
catch ( SQLException sqle )
{
s.setMessage("Error getting employee profile");
sqle.printStackTrace();
}
} catch (Exception e)
{
s.setMessage("Error getting employee profile");
e.printStackTrace();
}
return profile;
}
}