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;
   }
}
Random Solutions  
 
programming4us programming4us