I am working on a small app using phalcon for php framework. I have implemented multiple controllers and models, but so far when I want to edit a user for example, i use a link that links to
localhost/myappname/User/edit/11 "user's id"
I was told this is not the best way to do this, and I am trying to do this without passing the id through the url, like using post method like in forms but without success so far.
Is this the only correct way to edit or delete an entry or it there something better?
I tried to search for the problem but couldn't figure how to name this question so I am yet to find an answered question.
If you don't want to let everyone access to edit page you can do this in a few ways.
Solution #1
You can use Phalcon ACL to block user's who has no permission to edit this page so only allowed people like managers can edit user or whatever.
See Access Control Lists ACL
Solution #2
You can crypt/decrypt user id so in URL it will not be readable by humans and then in edit method try to dectypt that id and if it is not a valid echo error.
<?php
use Phalcon\Crypt;
// Create an instance
$crypt = new Crypt();
$key = 'le password';
$user_id = 5;
$encrypt = $crypt->encryptBase64($user_id, $key);
// Use $encrypt for URL like Edit
// Use decrypt to get the real id of a user
$crypt->decryptBase64($encrypt, $key);
?>
In this way users will see URL something like
localhost/myappname/User/edit/nomGPPXd+gAEazAP8ERF2umTrfl9GhDw1lxVvf39sGKF34AFNzok31VdaT/OwADPPJ4XgaUNClQKrlc/2MfaXQ==
For more info see Encryption/Decryption
But my personal opinion is that it is better to go with ACL. After all ACL was made for that kind of things.
Note! If you want to use Encrypt/Decript remember to wrap decryption
in edit method in try/catch block and catch exception so you don't
get Error if someone tries to guess sone id.
Solution #3
If you still want to do that using POST then don't use Edit instead you can try something like:
<form method="POST">
<input type="hidden" name="uid" value="{{ user_id }}"/>
<button type="submit">Edit</button>
</form>
And then in edit method catch that id like:
<?php
$user_id = $this->request->getPost("uid");
?>
NOTE! In this way your URL will not contain user id but someone still
can POST another uid so you can try to hide that real user id even
from input type hidden. You can use again crypt/decrypt so input
hidden uid can be crypted and then decrypt post data in method.
you could use sessionStorage. It would store the value of the userId in the browser and be deleted as soon as they leave the page.
http://www.w3schools.com/html/html5_webstorage.asp
set on one page
sessionStorage.userId = 11;
access on another
var user = sessionStoarge.userId;
Related
I have the following workflow on a website:
Some user John Doe declares a company through form 1
(fields: name, head office location)
After John Doe submits (HTTP POST) form 1, he is redirected (HTTP 302) to company form 2 with additional legal information about the company.
The problem is, if John Doe hits the back button of his browser during step 2, he will land on the form 1, with data filled by the browser (using values he already submitted — that's what Firefox and major browsers seem to do).
John Doe might then think he can use this form to update some information (e.g. fix a typo in the name of the company) whereas he will actually create a new company doing so, as we don't know on the server side whether he wants to declare a new company or update the one he just created.
Do you know any simple solution to handle that problem ?
Use javascript/jquery script after the page is loaded to empty all the inputs. This will prevent confusion of "updating the company".
jQuery would look something like this:
$('#elementID').val('');
You can also handle the situation by manipulating the browser history
on load of form 2, and pass the CompanyId generated on submit of form 1 using querystring. So that you can actually update the company as the user
Suppose John submits form1.html, a unique CompanyId "1001" is generated and redirected to form2.html. Now on load of form2 you can modify the browser history form1.html?companyid=1001 using
var stateObj = { foo: "bar" };
history.pushState(stateObj, "page 1", "form1.html?companyid=1001");
Now, when the user click back button and submits the form1 again. you can check for companyid in querystring and update the company.
I think it is more user-friendly when user can return back to previous form and update it (instead preventing the described behavior).
I use in most cases similar way to handle described problem:
Let's assume that user is on the page /some-page, that contains "Create new company" button.
When the user opens this page, will be executed special method createOrFindCompanyDraft() on the server-side. This method creates new company "draft" record in DB (only for the current user). For example, draft record has primary key id=473. When you execute this method again it will return the same record with the id=473 (with "draft" status). "Draft" record should't display on any other interfaces.
And "Create new company" has link /company/common/473.
When user go to /company/common/473, you display form 1, that will be filled from "draft" record. At first time user will see empty form.
Technically user will update the existing record, but you can display "Create new company" title on the page.
Then user go to form 2, for example, /company/legal-info/473, you create similar draft record for the this form (similar to step 1).
When user submit the form 2, you will remove "draft" status from the record id=473 (and any related records).
Next time when user open page /some-page, will be created new draft record for the current user.
Browser history will contain:
/some-page
/company/common/473
/company/legal-info/473
/some-page2
I like this approach, because all form only update records. You can go to previous/next form many times (for example "Back"/"Forward" browser buttons). You can close browser, and open not completed forms tomorrow. This way doesn't require any additional manipulation with the browser history.
try this
<form autocomplete="off" ...></form>
And Another
Use temporary tables or session to store the Page 1 form data. If the page 2 form is submitted use the temporary data of page 1 which is stored in database or in session.
Use a Separate key (Hidden field ) in both page 1 and page 2.
Actually I thought of a trick to obtain that "create on first post, update after" behavior (just like the user thinks it should behave).
Let's say the step 1 form is at the URL /create_company/. Then I could have that page generate a random code XXX and redirect to /create_company/?token=XXX. When I create the company I save the information that it was created through page with token XXX (for instance, I save it in user's session as we don't need to keep that information forever) and when the form is submitted, if I know that a company was already generated using this token, I know the user used the same form instance and must have used the back button since the token would be different if he explicitly asked for another company.
What do you think ? (I initially thought there should be a simpler solution, as this seems a little bit over-engineered for such a simple issue)
This is more like a UX question.
I'd think that the solution lies within the information given to the user on that form, to help them understand what they're doing.
Set a title that says 'Create a company', for example, and set your submit button as 'Create Company' will help your user with that. Use a unique id when you create the company object, and pass the id back to the same URL in order to perform an update. You should then update your title and button that tells user that they are updating instead of creating.
In that sense I'd say it's better to use a more generic URL like /company and /company?id=12345.
You could also consider using Restful API protocol to help your server identifies the CRUD operation. http://www.restapitutorial.com/lessons/httpmethods.html
Without the "routing" part of django it is hard to help. I can just answer my experience from the express.js-router functionality:
you can specify a post on /company, which is for new users.
you can specify another route for post on /company/:companyid for a changing form
and as a response from the create-post you can redirect to the different location.
So as the title says I'm curious, can user change the ID of an element through browser? I have a list of inputs - checkboxes, when you click on one of them ajax takes ID of that element and uses it to get data from database, so basically what I'm thinking is that if it is somehow possible to change the ID of the element my database wouldn't be secured. If that's possible, how I should protect it?
Okay, So I get the idea that it wouldn't be secured, If I'd use this way:
<?php
$mysqli = new mysqli("host", "user", "password", "database");
$usuario = $mysqli->real_escape_string($_POST["usuario"]);
$clave = $mysqli->real_escape_string($_POST["clave"]);
$sql=' SELECT * FROM usuarios
WHERE username="'.$usuario.'"
AND pass="'.$clave.'"
';
$mysqli->query($sql);
$mysqli->close();
?>
would it be enough, or there aren't actually safe enough way to protect data?
You are correct that this would be a security hole. The ID attributes could indeed be changed via the browser console.
Yes, they can change it or just make while request faked and you won't tell the difference. Rule of thumb here is NEVER trust any data that comes from user. It means - always validate, sanitize data on server-side, and always assume data that comes in request are there to fool/trick/hack you.
Yes. The user can do anything they like to the DOM once it is in their browser.
They can also execute any JS they like there.
You're worrying about the problem in the wrong place though. Your control ends at the edge of the webserver. Clients can make any HTTP request they like to it and include any id value they want. You need to address security there and not in the browser.
If you want to secure your database then you need to either allow no HTTP request to lead to the secret data being released / changed or you need to write server side rules that limit which HTTP requests can change them.
Typically this would involve Knowing Who The Request Comes From (Authentication) and Knowing Who Can Access Which IDs (Authorization).
A simple approach would be to keep a database that has a users table (including hashed passwords), a "things" table, and an ownership table (which has a column of user ids and a column of thing ids). If the request doesn't include a username and password you can cross reference from the thing id across the ownership table - return an error message instead of what was asked for.
I have a small app where users create things that are assigned to them.
There are multiple users but all the things are in the same table.
I show the things belonging to a user by retrieving all the things with that user's id but nothing would prevent a user to see another user's things by manually typing the thing's ID in the URL.
Also when a user wants to create a new thing, I have a validation rule set to unique but obviously if someone else has a thing with the same name, that's not going to work.
Is there a way in my Eloquent Model to specify that all interactions should only be allowed for things belonging to the logged in user?
This would mean that when a user tries to go to /thing/edit and that he doesn't own that thing he would get an error message.
The best way to do this would be to check that a "thing" belongs to a user in the controller for the "thing".
For example, in the controller, you could do this:
// Assumes that the controller receives $thing_id from the route.
$thing = Things::find($thing_id); // Or how ever you retrieve the requested thing.
// Assumes that you have a 'user_id' column in your "things" table.
if( $thing->user_id == Auth::user()->id ) {
//Thing belongs to the user, display thing.
} else {
// Thing does not belong to the current user, display error.
}
The same could also be accomplished using relational tables.
// Get the thing based on current user, and a thing id
// from somewhere, possibly passed through route.
// This assumes that the controller receives $thing_id from the route.
$thing = Users::find(Auth::user()->id)->things()->where('id', '=', $thing_id)->first();
if( $thing ) {
// Display Thing
} else {
// Display access denied error.
}
The 3rd Option:
// Same as the second option, but with firstOrFail().
$thing = Users::find(Auth::user()->id)->things()->where('id', '=', $thing_id)->firstOrFail();
// No if statement is needed, as the app will throw a 404 error
// (or exception if errors are on)
Correct me if I am wrong, I am still a novice with laravel myself. But I believe this is what you are looking to do. I can't help all that much more without seeing the code for your "thing", the "thing" route, or the "thing" controller or how your "thing" model is setup using eloquent (if you use eloquent).
I think the functionality you're looking for can be achieved using Authority (this package is based off of the rails CanCan gem by Ryan Bates): https://github.com/machuga/authority-l4.
First, you'll need to define your authority rules (see the examples in the docs) and then you can add filters to specific routes that have an id in them (edit, show, destroy) and inside the filter you can check your authority permissions to determine if the current user should be able to access the resource in question.
Hopefully this question isn't too naive...
I'm attempting to implement The Giving Lab API in order to allow users of my site to donate to charity.
Using a URL such a this:
https://www.thegivinglab.org/api/donation/start?donationtype=0&amount=10&charityid=84ed3c54-6d8c-41c5-8090-f8ec800f45a7&returnurl=mywebsite.com/
the user is directed to the donation page and then returned to the returnURL after the donation has been made.
I want to be able to add how much the user donated to my databases if they successfully complete a payment. Would it be possible to use the returnURL to do this? Ie could I use a returnURL in the form of mywebsite.com?q="amount_donated" and then use this to update my databases?
I can see that this would allow someone to update my databases by just entering the returnURL into their browser.
Is there a generally better method, that removes this problem?
Many thanks.
Dutch banks use a thing called a sha-sign (and they're probally not the first)
All you have to do is add a key which only you can know:
function makeSecureCode($var1, $var2){
$secretCode = 'example';
$secretKey = '';
$secretKey.= $var1 . $secretCode;
$secretKey.= $var2 . $secretCode;
return sha1($secretKey);
}
Then make the url like this: ?var1=foo&var2=bar&key=5e8b73da0b20481c1b4a285fb756958e4faa7ff1
And when you process the code after payment, makeSecureCode( $_GET['var1'], $_GET['var2']) should be equal to $_GET['key']. If not, someone changed it.
This is a simplefied version with only two vars. You can make it have more input arguments, or an array, whichever you prefer.
I've been trying to get the most recent Facebook Status for a fan page via the API for a while now and can't seem to get what I'm after. I'm really trying to avoid using RSS for it. I can get the full list from the feed via https://graph.facebook.com/174690270761/feed but I want only the last status posted by the page admin, not by anyone else.
Is their an easy way to get it without having to authenticate?
Thanks in advance
edit:
https://graph.facebook.com/174690270761/statuses seems to be what I'm looking for but I need an OAuthAccessToken for this but can't see how to without involving the user, as I'm trying to access through my own credentials/application
Facebook has changed the api and now requires you to provide an access token.
You can use Facebooks PHP sdk for that but i found a much quicker way to go:
<?
$appid = '1234567890';
$secret = 'db19c5379c7d5b0c79c7f05dd46da66c';
$pageid = 'Google';
$token = file_get_contents('https://graph.facebook.com/oauth/access_token?grant_type=client_credentials&client_id='.$appid.'&client_secret='.$secret);
$feed = file_get_contents('https://graph.facebook.com/'.$pageid.'/feed&'.$token);
print_r(json_decode($feed));
?>
Update 15/12/12
app access tokens nosist of the id and secret now - use this request:
$feed = file_get_contents('https://graph.facebook.com/Saxity/feed?access_token='.$appid.'|'.$secret);
I finally found out that this doesn't have to be done through the API, or require any authentication at all.
Basically you can access the data via a JSON feed:
$pageID = "ID of Page" //supply the Id of the fan page you want to access
$url = "https://graph.facebook.com/". $pageID ."/feed";
$json = file_get_contents($url);
$jsonData = json_decode($json);
foreach($jsonData->data as $val) {
if($val->from->id == $pageID) { //find the first matching post/status by a fan page admin
$message = $val->message;
echo $message;
break; //stop looping on most recent status posted by page admin
}
}
I don't think there's a good way to do this. You can process the JSON pretty easily though from the looks of it. You can limit the number of results by using the since query parameter. For instance:
https://graph.facebook.com/174690270761/feed?since=last%20Monday
You can also use limit on that, but I don't think that filters by user. If the administrator is the only one allowed to post, then you may be able to get away with using limit=1.