|
|
Question : security issue in login application: a logged in user is able to edit her or his own profile
|
|
|
|
Hello friends. I found a security issue in my login application. This is the NBPTS application which by now is familiar to many of you in the CFML forum. =) A logged in user is able to edit her or his own profile:
http://www.nbptsprincipals.org/principal/principal_registration.cfm?UserID=160
But by simply changing, in the browser location field, the value UserID=160 to another UserID, she can view and edit other UserIDs too!
Is there a way to secure UserIDs? Is there a statement I can add to the onRequestStart function in application.cfc to disallow editing of other UserIDs?
The statement would need to say:
* If logged in user has UserRoleID 5, she can edit only her UserID.
* If logged in user has UserRoleID 3, he can edit UserIDs with UserRoleID 5, and his own UserID.
* If logged in user has UserRoleID 1, she can edit all UserIDs.
How would I add that logic to my existing onRequestStart function?
Thank you as always for any advice.
Eric B
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
|
<!--- function: onRequestStart --->
<cffunction name="onRequestStart">
<cfargument type="String" name="targetPage" required="true" />
<!--- All these folders/top level files require a login, specific roles are addressed below ---->
<cfset var securefolders = "admin,liaison,principal,index.cfm,nbpts_principals.cfm,nbpts_liaisons.cfm,nbpts_process.cfm">
<cfset var currentFolder = listFirst(cgi.script_name,"/")> <!--- the user's current location ---->
<!--- process login credentials --->
<!--- begin cfif isDefined("form.userEmail") and isDefined("form.userPassword") --->
<cfif isDefined("form.userEmail") and isDefined("form.userPassword") and isDefined("form.doLogin")>
<!--- check box to remember UserEmail was checked, so make a cookie for it --->
<cfif isDefined("form.SaveUserEmail") and form.SaveUserEmail is "Yes">
<cfcookie name="SaveUserEmail" value="#form.UserEmail#" expires="7">
</cfif>
<!--- user is attempting to log in, so process the login request ---->
<cfif NOT checkLogin(form.userEmail, form.userPassword)>
<cfinclude template="LoginForm.cfm"> <!--- login failed, so show login form ---->
<cfreturn false>
<!--- close cfif NOT checkLogin(form.userEmail, form.userPassword) --->
</cfif>
<!--- close cfif isDefined("form.userEmail") and isDefined("form.userPassword") and isDefined("form.doLogin") --->
</cfif>
<!--- /process login credentials --->
<cftry>
<!--- test for access to secureFolders --->
<cfif listFindNoCase(secureFolders, currentFolder)> <!---- are we in a secure area? --->
<cfif session.auth.isLoggedIn is False> <!--- This is a secure area, if the user is not logged in, go to login page ---->
<cfinclude template="LoginForm.cfm">
<cfthrow message="Please log in with proper credentials to access this area.">
<cfabort>
<cfelse> <!--- the user is logged in, then check roles ---->
<cfswitch expression="#currentFolder#">
<cfcase value="admin">
<cfif listFind("1",session.auth.UserRoleID) eq 0> <!---- role 1 has access to admin --->
<cfinclude template="LoginError.cfm">
<cfabort>
</cfif>
</cfcase>
<cfcase value="liaison">
<cfif listFind("1,3",session.auth.UserRoleID) eq 0> <!---- roles 1, 3 have access to liaison --->
<cfinclude template="LoginError.cfm">
<cfabort>
</cfif>
</cfcase>
<cfdefaultcase> <!---- all other secure folders ---->
</cfdefaultcase>
</cfswitch>
</cfif> <!---- end if user is logged in or not ---->
</cfif> <!---- end if user is in a secure area or not ---->
<!--- /test for access to secureFolders --->
<cfcatch>
<cfset clearSessionVariables()>
<cfset SESSION.auth.lastError = cfcatch.message>
<cfreturn false>
</cfcatch>
</cftry>
<!--- if query_string contains cast(, then abort! --->
<cfif cgi.query_string contains "cast(">
<cfabort>
</cfif>
</cffunction>
<!--- close function: onRequestStart --->
|
|
|
|
|
Answer : security issue in login application: a logged in user is able to edit her or his own profile
|
|
Well, in
{33, "B"}, {22, "C"}, {22, "D"}, {44, "E"}, {22, "D"}
you have that very duplicate entry - just remove it after it is sorted, e.g.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
|
#include <iomanip>
#include <iostream>
#include <string>
#include <sstream>
#include <set>
#include <vector>
#include <algorithm>
using namespace std;
struct StudentAttempt
{
int distance;
string studentName;
};
bool cmpEntry(StudentAttempt left, StudentAttempt right) {
return left.distance == right.distance && left.studentName == right.studentName;
}
bool cmpAttempts(StudentAttempt left, StudentAttempt right) {
if( left.distance < right.distance ) {
return true;
}
else if( left.distance == right.distance ) {
if( left.studentName < right.studentName ) {
return true;
}
else
return false;
}
else
return false;
}
bool isDistEqual( StudentAttempt left, StudentAttempt right) {
return ( left.distance == right.distance
&& left.studentName != right.studentName );
}
size_t printAllEqual(const vector<StudentAttempt>& v, const StudentAttempt& sa, stringstream& ss ) {
vector<StudentAttempt>::const_iterator i = v.begin();
size_t sz = 0;
bool bFirst = true;
while (i != v.end()) {
if(isDistEqual(*i,sa)) {
if (!bFirst) ss << ',';
ss << i->studentName;
++sz;
}
++i;
bFirst = false;
}
return sz;
}
int main() {
StudentAttempt throwDist[] = {
{50, "A"}, {22, "A"}, {16, "B"}, {44, "C"},
{33, "D"}, {34, "E"}, {22, "F"}, {21, "G"},
{49, "A"}, { 5, "B"}, { 2, "C"}, {22, "A"},
{33, "B"}, {22, "C"}, {22, "D"}, {44, "E"}, {22, "D"}
};
set<int> handled;
int len = sizeof( throwDist )/ sizeof( throwDist[0] );
vector<StudentAttempt> dist(throwDist, throwDist + len);
vector<StudentAttempt>::iterator it = dist.begin();
sort( dist.begin(), dist.end(), cmpAttempts);
unique( dist.begin(), dist.end(), cmpEntry); // removes identical duplicates from the sorted vector
for( ; it != dist.end(); it++ ) {
stringstream ss;
pair<set<int>::iterator,bool> p = handled.insert(it->distance);
if (!p.second) continue; // already handled
if(0 < printAllEqual(dist,*it,ss))
cout << setw(2) << (*it).distance
<< " feet: " << (*it).studentName << ss.str() << endl;
}
}
|
|
|
|
|