I have a PHP project is essentially an order processing website for a company. Each user in the company has access to this website and is given certain credentials to the application that control access to pages and functionality throughout.
Now I have a request to allow a guest access to a single page. The complexity of this request is that the guest will be different each time as well as the page will be different. Basically it is a portal to allow customers, who don't have accounts within the system as there is no live ordering on this site, to be able to access and verify the order and shipping information.
My thought to accomplish this is to have a database table setup as a guest relationship table that will be used to store UIDs, MD5 Hash Keys and the destination page that the record is referring to. Also included would be a visit counter and expiration date. When the user receives an email they would have a link provided in the email to somewhere like http://website.com/verify/?HASH-KEY.
When this link is clicked I expect that the verify index.php page takes in the HASH, verifies it in the database and displays the page reference in the database within this location instead of redirecting into the application. This would allow guest access to the single page without the need to expose the structure of the website or a rework of the user authorization already setup.
Am I approaching this solution in the proper manner?
How do I grab the contents of one page and display it in another?
1. Am I approaching this solution in the proper manner?
Yep, more or less.
Some pointers:
Make sure you seed hash generation randomly. For example, DON'T simply MD5 a customer ID or some other small/sequential number, as that would make it easy for a malicious use to hunt down other pages.
Expire the hashed links after a set time out.
2. How do I grab the contents of one page and display it in another?
If you want people to "access and verify the order and shipping information" you should probably create a page specifically for it, instead of trying to pass through normally secure pages to insecure guests. Ie, a 'shipping confirmation page' that populates details according the data keyed by the supplied hash.
I'm trying to a follow this as well as I can.
It seems to be you should use your hash method, and just have a stand alone page that will generate the content you want, totally separate from the rest of the system. Just put enough data in your hash URL to determine what is needed.
Something else to do is use a timestamp in your hash string URL and have that timestamp part of the random bits that you generate your hash on. This will allow you to make a URL essentially "expire" after a certain point.
Example: url.com/in/123456789865/hash-here
You can compare "123456789865" in this example to the current server time and determine if its expired. Of course you need to make "123456789865" part of your hash encryption to still validate
If I understand you correctly (and I think I do), than I think you're approaching this correctly.
To include another page's contents, you usually use include.
include "/path/to/page.php";
Related
I am working with Qualtrics, which is just a web-based survey engine. The request is that, once users finish the survey, they will receive a small prize in the form of a gift code. Since I can't host the prize code data on the Qualtrics platform, my idea was to store the prize codes on a remote server. When the user finishes the survey they will be directed to my server (https), to a PHP script that will give out the prizes. On the surface this is possible, because as one piece of customization they allow to re-direct to a URL upon completion of the survey.
The problems that I am faced with, regarding my PHP script that gives out the prizes are as follows:
1) Make sure visitors have COME FROM the survey and have actually
finished the survey.
2) Only give out 1 prize per participant per survey.
It is difficult to address #1 because it seems like after the survey is complete, you just get a basic re-direct to my site. It would be possible to add GET data to the URL, its very easily readable and doesn't offer security. Even encrypting the GET data doesn't seem feasible because a hacker could just copy the data string once they see it.
The idea I had to address #2 was to check the user's IP address using PHP, and store the address in my DB after a 1-way encryption. This way the IP would be unknown, but I could check for duplicates, only allowing 1 prize per IP.
So the question is, is it even possible to do what I am trying to do with just a simple URL re-direct? Is my idea for addressing #2 acceptable?
Thanks.
There are probably many ways this could be handled. Two that come to mind:
1) At the end of survey, Qualtrics creates an embedded data field called ResponseID which is in the Qualtrics data. You can include the ResponseID in the redirect then have your php script call the Qualtrics REST API, and try to retrieve the response with that ResponseID to make sure it exists.
2) Just before the end of survey, you could do a web service call to a script that creates a unique id, store the id on the server side, and return it to the survey as an embedded data field. Then pass the unique id in your redirect and make sure it matches a unique id you stored.
EDIT based on comment below:
You can add custom parameters to your redirect by piping in parameter values like this:
http://mywebsite.com/myscript.php?rid=${e://Field/ResponseID}
If you are able generate special request parameter for redirect url and make it for every user unique, then you could invent some algorithm, and encrypt user ID with it and pass this ID as parameter in redirect url.
I'm seeking to utilize an iframe to embed some html in customers websites that will list some information from my database using a simple GET request like so:
// customer would copy/paste this code onto their site
// value of key would be unique key for that customer
<iframe src='http://mydomain.php/api?key=1234j1lj1hj124kh' ></iframe>
Now I want to be able to verify that the request is coming from customer that owns the key, and not just anybody who copy/pasted that code onto their page.
I've done some research and found that $_SERVER['HTTP_REFERRER'] can give me this information, but with mostly mixed reviews saying it isn't always reliable (and most of the questions I came across were a couple years old).
QUESTIONS
1.) Is this method of using an iframe/GET request the standard way of achieving this functionality?
2.) Is there a standard, SECURE and RELIABLE way to verify the origin of the GET request?
Unfortunately this is not possible in a secure way.
To answer your questions: In fact this is not a standard functionality itself. I mean, there is no standard secure way of allowing content to be loaded only through iframes from allowed websites.
There are three parties in this communication:
1) Your website
2) Customer website that loads your website's data in an iframe
3) End user visiting customer website
When an end user visits customer web site, he will perform a GET request to your website through the iframe. At this connection, 2nd party above (customer website) is not involved. In this case, there is no reliable way for your website to know whether this request is coming through the iframe or not. Only favor that party 2 does here is adding HTTP_REFERER header to end-user's request. But this header cannot be trusted.
For example, if I want to abuse this and show that content on my website, I can create a proxy page on my application, where I perform a back-end call to your app (adding a valid HTTP_REFERER header) and display results back.
Personally I would never use iFrames for this functionality. I am assuming that this has to be reasonably secure, which is why only your specified customer can view it? If for whatever reason you can't use PHP to embed the content you need to display (through the use of an "included" file for example), I would instead use AJAX which would still use any PHP user verification you have in place to dynamically load content into a secure webpage.
This is because your PHP user verification will (should!) use cookie/session information to determine which customer is viewing the page and therefore decide whether the content should be delivered, since Session variables are determined by a single unique code stored client-side, which match up to as much information as you want to collect about a user server-side (Which could include the last page they visited, which is what the "HTTP_REFERRER" variable would give you, if they came from another page on your website).
'$_SERVER' variables aren't reliable because they rely on the information given to them by the web browser when the request is made, and such information can easily be forged, by most people who have a basic understanding about how headers are sent.
In summary, use a NONCE (cookied), validate IP and user agent.
Steps:
When you deliver the outer frame, generate a unique identifier
(totally random, long string) and return that in a cookie with the
HTML content.
At the same time, note the IP and the user agent string you have
sent that unique identifier to, and store in a DB with the time.
When requesting the inner frame, assuming the same domain, the
cookie will come too. (If a different domain, you'll need to attach
the unique identifier as a visible string, but that's not really of
concern, just uglier)
If the user agent or IP do not match those you stored against the
unique string, or the request is too long (i.e. after an hour, or
whatever is reasonable for your application) or the unique string is used more than once
(or whatever other restrictions you place on it) then reject the
request and invalidate (delete) the unique identifier.
Not 100% foolproof, but just combine more options to make it less and less likely to be abused.
Is there a way to only let a webpage be viewed if the link pointing to it is pressed. I am sending emails to members of my organization with links that attach values to the URL so I can use phps $_GET to figure out who they are on the webpage and update appropriately. What I am worried about is individuals changing the values of the link and changing other members data. If there is a better method for doing this, I am all ears. Using a log in system is not an option.
Not exactly, no.
What you could do is include some token that you keep associated with a particular user id and is very difficult to guess, and include that in the link as well - then, when you get a GET request, you check to make sure the token matches the one you know is correct for that userid. (You'd store the "correct" tokens locally in a database when sending out the emails.)
For instance, you might have...
/modify_info_script?user_id=123&token=aSDqWEqwejk2123salskq
And then you'd have a database table or some other storage that has...
user_id token
----------------------
... ...
122 klqwkejajwie8u8213nak
123 aSDqWEqwejk2123salskq
... ...
and thus if someone tried to change the user_id in the URL, the token wouldn't match and you could reject their request. For instance, this would get rejected...
/modify_info_script?user_id=122&token=aSDqWEqwejk2123salskq
since the right token for 122 would be klqwkejajwie8u8213nak, not aSDqWEqwejk2123salskq.
This is probably the best option if using a login system isn't an option. However, you should really make sure that using a login system isn't an option at all, because user data really should be protected by a login.
This is really not the proper way to secure your site.
However, the simple fix for you is to check the "referer" header and make sure it's not blank. If it's not blank, then it came from a click (or they spoofed it, which is why this isn't secure).
The real way to protect data is to implement a login system with a set of permissions.
To check, if someone came from a link, see $_SERVER['HTTP_REFERER'].
To protect the application against link manipulation, you can combine it with a secret passphrase (only internally, the passphrase must not be known to anyone) and use md5() on the result. Attach the MD5 to the url. If anyone manipulates the url, you will know because the MD5 of "the url plus your passphrase minus the MD5" will be different.
Quite a lot password reset systems work like this so you could say it's reasonably safe provided you use long enough random token. Something like 32 chars should be fine.
Just providing the token should be enough since you don't need the user ID to check it against issued tokens in database.
/modify_info_script?token=aSDqWEqwejk2123salskqfilltill32chars
The other alternative is to have login system where use has to type in their credentials in order to change information.
Also if you really fear that someone might try to guess it, just timeout/ban users after 3 wrong token attempts. No one should be trying to type them in by hand anyway.
I have
echo <a href=\"javascript:;\" onClick=\"window.open('". $link ."','no','scrollbars=yes,width=550,height=400')\" >View report</a>
$link contains sensitive information, so I'm wondering if there is a simple way to prevent this link showing up explicitly when you "view source code" on the browser. Any alternative to href would be fine. I just need to give the user an option to click and see his processing result after he submits some data. I would like to avoid having auto popups as soon as the processing is submitted.
UPDATE: so the $link is a GET URL that includes a user ID and password.. It's internal right now so it's fine, but I'm thinking of putting this on our online server in the future. I'm very much a novice with PHP, so this is probably not in the near future as I don't know much about security features that need to be implemented for a live site on the Internet. Right now, it seems that utilizing a database would be the best way to go. Correct me if I'm wrong, please, and thanks for all of the support!
If the user has to navigate to the link, there is no way to actually hide the information. You should rethink how your process works so sensitive information is not displayed in the link.
Perhaps you can store the information in a database table and the link would just use the id of the row that has the information.
Simply put: No. If you send me to a URL, I will be able to see it using some sort of tool. Wireshark, Fiddler, etc. Consider using a different link structure.
If the user already owns a session, this is an option:
If you render a page and need to protect this given sample secret URL
http://www.MyHost.com/?what?secret&id=23232
save the URL in the user's session and associate a hash value with the secret URL.
Instead of sending the URL to the result HTML-page, insert another URL, e.g.
http://www.MyHost.com/?continueWith=<hashValue>
If this URL gets called, check the user's session and retrieve and delete the secret URL. Then continue to evaluate, as if the user had called the secret URL.
This way, no parameter of the original secret URL ever reaches the user's browser.
To refine the schema, attach a lifetime to the URL saved in the session. If a request comes later as the end of life, return an error.
If you protect all URL in such a way, users won't be able to call arbitrary URLs, since all acceptable URLs are those inside their sessions. Thus, a user will even not be able to change parameters of less secret URLs.
How is $link generated in the first place? If it is sensitive, this implies that the user has already been authenticated somehow. Thus, the information in $link can be stored in the session where it's safe
Save all the information in your PHP session (or preferably the session system your PHP framework uses) and then just send some kind of non-db-associated identifier in the link so that the code knows what you want to do next.
For example you could have a link to "http://www.yourdomain.com/sec/special_action/4" with "sec" meaning secure, "special_action" being the name of the action to take, and "4" being the action id reference.
So lets say you have to have it associated to their social security number. Then you would in your back end use a salted hash to encrypt the SSN and save it to the session data. You then append it to the end of your session array and get an array count. If it returns 5 then you know that the encrypted SSN is saved in index 4 (since PHP uses 0 based indexing). So you send along that index as part of the link to confuse things even more. Heck you can even salt and hash the index if you want.
The user clicks on the link, the code finds the index, grabs the encrypted content, decrypts it, then uses it. Easy and secure.
Working on a web based "buying and selling" application with PHP MySQL where users can post adverts for items and services.
Before a new advert is displayed on the system there must be a method of verification to ensure that the user provided email address is correct, and that the advert is legitimate.
I want to send the creator of any new advert an email containing an url which directs to a page whose primary functionality is to receive a posted variable, $advert_id, and to select the advert from the db for updating / editing / deleting.
This variable is embedded in the url with PHP syntax
ie. [http://www.example.com?content=modify_advert&advert_id=2246317].
This part is quite simple to implement, BUT, if a user was to modify this variable called "advert_id=2246317" to any other integer, they can access other posts/adverts in the system.
The system is advert based, and users dont need an account or login to post, so we cannot prompt for a login at the point of verification which would have been convenient.
Any ideas as to how we could protect the adverts/posts in the system from being accessed via the aforementioned url???
Any suggestions?
If visitors will only be viewing that page from the link you send via e-mail, you can include a hash in that address instead of the advert_id — essentially a random, one-time password.
One common and "often good enough" trick for generating such a random password is to take a single, secret, truly random string (I usually use grc.com), concatenate it with the unique advert_id, and hash the whole thing with, say, SHA1(). Like so:
UPDATE advert SET advert_hash = SHA1(CONCAT(advert_id, 'lots-of-randomness-here'))
You could even vary this by adding time(), or (better still) a random number to the end. The outcome is a 40-character string stored in your database that nobody could possibly predict (without knowing the secret data you used to generate it).
For example, I might get this instead of advert_id=1:
f2db832ddfb149522442c156dadab50307f12b62
If I wanted to sneakily edit advert_id=2 (which somebody else created), I'd first have to guess that the hash is this completely different string:
e5c6a3a9473b814b3230ee7923cbe679fcebc922
So, include that in the URL instead of the advert_id (or, if you like, in addition to the advert_id), and suddenly your users are powerless to ruin other people's content.
You could add a salt to the id and then hash it.
sha1($advert_id . $salt);
Send this to the user in the URL instead of the advert_id, and store it in your database, along with the advert_id.
Then when they click the link, you find the matching advert for that hashed value.
Making the salt a secret is how you keep users from 'guessing' a valid URL that will let them modify an ad that they did not post. Perhaps you could use the users email address, the time posted and/or a name or something that the user enters when they make a post.
Generate a GUID as the advert ID so simple ID guessing attacks are unlikely to succeed.