In my Laravel application, a User
can have a Profile
which they or a user with privileges can update.
The relation for these two models is defined in this method:
/**
* Get the profile associated with this user
*/
public function profile()
{
return $this->hasOne(Profile::class, 'user_username', 'username');
}
This is the method for updating a user profile:
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Profile $profile
* @return \Illuminate\Http\Response
*/
public function update(UpdateProfile $request, User $user)
{
if ($user) {
// Only proceed if there is a logged in user
$profile = $user->profile;
// If there is no profile, create one for this user as they'll need one.
if (!empty(request()->get('background'))) {
$profile->background = clean($request->get('background'));
}
if (!empty(request()->get('skills'))) {
$profile->skills = clean($request->get('skills'));
}
if (!empty(request()->get('filepath'))) {
$profile->displayPicture = $request->get('filepath');
}
if (!empty(request()->get('linkedInUrl'))) {
$socialProfilesDecoded = json_decode($user->profile->socialProfiles, true);
$socialProfilesDecoded["LinkedIn"] = $request->get('linkedInUrl');
$profile->socialProfiles = json_encode($socialProfilesDecoded);
}
if (!empty(request()->get('twitterUrl'))) {
$socialProfilesDecoded = json_decode($user->profile->socialProfiles, true);
$socialProfilesDecoded["Twitter"] = $request->get('twitterUrl');
$profile->socialProfiles = json_encode($socialProfilesDecoded);
}
$user->profile()->save($profile);
return redirect()->back()->withSuccess('Your profile has been successfully updated');
}
}
The route for updating a profile is:
Route::post('profile/{user}', 'ProfileController@update');
It came to my attention that exposing the username presents a vulnerability as if you're able to grab the request with a web proxy you can just change the username and update another user's profile.
Without changing the URL could I put a Policy in place to check that:
Or, should I change the URL and have a way to edit profiles in an admin area only?
Also, as a Profile is associated with a User, how could a privileged user access another user's profile?
Maybe a hidden input?
Update:
if ($request->is('admin/*')) {
//
}
Could I check if this matches the POST request?
Update 2
Added a simple check to ensure the logged in user had permissions to update a Profile.
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Profile $profile
* @return \Illuminate\Http\Response
*/
public function update(UpdateProfile $request, User $user)
{
// Check this user
if(auth()->user() == $user || auth()->user()->can('Approve user profile')){
if ($user) {
// Only proceed if there is a logged in user
$profile = $user->profile;
// If there is no profile, create one for this user as they'll need one.
if (!empty(request()->get('background'))) {
$profile->background = clean($request->get('background'));
}
if (!empty(request()->get('skills'))) {
$profile->skills = clean($request->get('skills'));
}
if (!empty(request()->get('filepath'))) {
$profile->displayPicture = $request->get('filepath');
}
if (!empty(request()->get('linkedInUrl'))) {
$socialProfilesDecoded = json_decode($user->profile->socialProfiles, true);
$socialProfilesDecoded["LinkedIn"] = $request->get('linkedInUrl');
$profile->socialProfiles = json_encode($socialProfilesDecoded);
}
if (!empty(request()->get('twitterUrl'))) {
$socialProfilesDecoded = json_decode($user->profile->socialProfiles, true);
$socialProfilesDecoded["Twitter"] = $request->get('twitterUrl');
$profile->socialProfiles = json_encode($socialProfilesDecoded);
}
$user->profile()->save($profile);
return redirect()->back()->withSuccess('Your profile has been successfully updated');
}
}
}