How to make a specific web page inaccessible, except to those who get there by a redirect - redirect

I have a webpage on a Joomla based website that I am trying to make inaccessible to anyone but those who have been redirected there through a redirect page.
Basically, they would purchase something on a form on my page which is integrated with Paypal, and when Paypal payment is complete I have them redirected to this specific page. I don't want anyone to be able to just copy this url and be able to come back to the page later. Is there a way to do this?

Then you have to store some "token" in your database, which is invalidated after the first time a returning client accesses your "thank you" page.
The token should be given to the client (in the URL) when you redirect him to Paypal and when he comes back after a valid payment, the token must still be in URL.
As far as I remember from the time I tried to use PayPal in one of my projects, it is possible to pass something like this to Paypal and get it back.

Checking a redirect is a poor way to do this. Such things can be easily spoofed. Instead have the pages you require a redirect from to create a session record of some kind and pass the ID of that record in the query string to the restricted page. The restricted page can deny if the session ID does not exist in the database or is too old.

It's been a while since I worked with Joomla. You might be able to look at the Server variables and check the Referring URL. If it's not one of your web pages or paypal, then you can redirect the user to the page of your choice.
I would include a specific token on the redirect. Maybe a Guid that has a limited life and is assigned to that specific user.

Paypal has a feature called Express Checkout that does just what you're looking for.

If you only care that the link expires shortly after it is used, then I think you should create a one-time URL for the content you are trying to protect. Have the action of purchasing create a unique key or token, store the value of the token on your server, and then reference that token in your link:
example.com/purchased_content?token=59803475203658902345089
When the link is clicked, check against your stored values. You can expire them based on whatever criteria you want.
If you also want to prevent copying the URL to somewhere else, you can have the action of purchasing set a cookie with the token value. Then check the cookie when the link is clicked. This is not foolproof since a knowledgeable user can copy the cookie too.

Related

How can I pass User Id back from Shopify's oAuth to my website?

I am using Shopify's OAuth for developing a custom Shopify public app and the OAuth part is working fine. I have used the state parameter to include the user id in the nonce value and then capture the user id from there so that I know which user to save that access token for. However, this seems really hacky to me. What is the standard way of doing it, ie capturing user id(User is a "user" on my application backend. The user id is his id for my application, not his shopify user ID) in this case? I am making the application fully REST API based so I cannot use sessions here. What is the general approach?
Here's the Shopify documentation on OAuth implementation. https://help.shopify.com/en/api/getting-started/authentication/oauth
Any help would be appreciated!
If I understand the question correctly, I don't think there's a more efficient/secure/non-hacky way of doing this other than how you're currently doing it. Ultimately you'd have to send something to Shopify, that Shopify then turns around and send back to you.
I'm doing a similar thing using the state parameter, but I'm encrypting the value (security by obscurity?) when sending, and decrypting when received. In my case, it's not a user id I'm using but a session id.

Oauth2: authorize access based on unguessable url in email

Our application uses oauth2 & openid connect for auth&auth. It's built using an angular client that calls a REST API. I would like to know how to authorize access to the API, based on the possession of an unguessable url.
I'll explain this a little more. In the application, a user can invite another user. When this happens, an email is sent to the second user. When user 2 clicks a link in the email, he is sent to a webpage with details about the invitation.
Only user 2 should be allowed to see the invitation page. I was planning to solve this by using an 'unguessable url' in the email. Upon visiting the url, the user must somehow be authorized to fetch the invitation details from the API.
The question: how do I authorize a user, based on knowing the unguessable url? How do I assign a claim when the page is loaded, and how do I verify this claim in the API call that follows? The only solution I see, is to set a cookie containing a token. But this is not in line with our existing auth mechanism. I prefer not writing my own token validation code, and let the Identity Provider handle this.
Additional info: user 2 may or may not have an account in the system, and he may or may not be logged in. Neither should prevent the user from seeing the invitation details. In other words: a totally unknown user should be able to see the page. The knowledge of the url should be the only requirement.
Any solution to this problem? Or am I handling it all wrong?
After asking around, the general consensus is to NOT let the external auth mechanism take care of this, but to validate the link ourselves.
The solution is to turn the unguessable part of the url (the 'link id') in some kind of token, which can be validated upon calling the API. This is done by the API itself, not by the Identity Server.
Applied to the invitation issue: when an invitation is created, store the link id together with some info, i.e. what kind of access it allows (invitation access) and the id of the invitation. When the user calls the API to get the invitation, pass the link id for validation. Match the invitation id with the invitation id stored in the link, and if it doesn't, throw an error.

Possible approach to secure a Rest API endpoints using Facebook OAuth

I've been reading a lot about the topic but all I find are obsolete or partial answers, which don't really help me that much and actually just confused me more.
I'm writing a Rest API (Node+Express+MongoDB) that is accessed by a web app (hosted on the same domain than the API) and an Android app.
I want the API to be accessed only by my applications and only by authorized users.
I also want the users to be able to signup and login only using their Facebook account, and I need to be able to access some basic info like name, profile pic and email.
A possible scenario that I have in mind is:
The user logs-in on the web app using Facebook, the app is granted
permission to access the user Facebook information and receives an
access token.
The web app asks the API to confirm that this user
is actually registered on our system, sending the email and the
token received by Facebook.
The API verifies that the user
exists, it stores into the DB (or Redis) the username, the token and
a timestamp and then goes back to the client app.
Each time the
client app hits one of the API endpoint, it will have to provide the
username and the token, other than other info.
The API each time
verifies that the provided pair username/token matches the most
recent pair username/token stored into the DB (using the timestamp
to order), and that no more than 1 hour has passed since we stored
these info (again using the timestamp). If that's the case, the API
will process the request, otherwise will issue a 401 Unauthorized
response.
Does this make sense?
Does this approach have any macroscopic security hole that I'm missing?
One problem I see using MongoDB to store these info is that the collection will quickly become bloated with old tokens.
In this sense I think it would be best to use Redis with an expire policy of 1 hour so that old info will be automatically removed by Redis.
I think the better solution would be this:
Login via Facebook
Pass the Facebook AccessToken to the server (over SSL for the
android app, and for the web app just have it redirect to an API endpoint
after FB login)
Check the fb_access_token given, make sure its valid. Get user_id,email and cross-reference this with existing users to
see if its a new or old one.
Now, create a random, separate api_access_token that you give back to the webapp and android app. If you need Facebook for
anything other than login, store that fb_access_token and in your
DB associate it with the new api_access_token and your user_id.
For every call hereafter, send api_access_token to authenticate it. If you need the fb_access_token for getting more info, you can
do so by retrieving it from the DB.
In summary: Whenever you can, avoid passing the fb_access_token. If the api_access_token is compromised, you have more control to see who the attacker is, what they're doing etc than if they were to get ahold of the fb_access_token. You also have more control over settings an expiration date, extending fb_access_tokens, etc
Just make sure whenever you pass a access_token of any sort via HTTP, use SSL.
I know I'm late to the party, but I'd like to add a visual representation of this process as I'm dealing with this problem right now (specifically in dealing with the communication between the mobile app and the web api by securing it with a 3rd party provider like facebook).
For simplicity, I haven't included error checks, this is mostly just to outline a reasonable approach. Also for simplicity, I haven't included Tommy's suggestion to only pass your own custom api token once the authorization flow is over, although I agree that this is probably a good approach.
Please feel free to criticize this approach though, and I'll update as necessary.
Also, in this scenario, "My App" refers to a mobile application.

WIF - optional authentication

I'm working on a proof of concept app. The basic functionality works, where I can log into one website, link to another site that shares the same STS, and the partner site picks up the credentials properly.
However, the partner site only requests the token if the page that we link to requires authentication (which kind of makes sense I guess).
Ideally, I'd like to link to a partner page that does not require you to be authenticated, BUT if the user IS already authenticated, I'd like to at least be able to recognize them on the partner site.
Currently, if my partner landing page does not require authentication, it doesn't appear that the user is logged in when they arrive. As soon as the user requests a page on the partner site that does require authentication, it then grabs the token without requiring the user to log in.
I've tried playing around with the SecurityTokenReceived and RedirectingToIdentityProvider events, but so far I'm stumped.
Any thoughts are appreciated.
So, the problem you are running up against is in dealing with the SessionAuthenticationModule hijacking the request. This module is responsible for detecting if the user has a valid session (based on a cookie that is written upon a successful redirect from the STS) and if not, to redirect the user to the STS to fetch a valid token. The WSFederationAuthenticationModule supplies the eventing necessary to hook into various stages of the redirection/authentication process.
Based on your description, it sounds like you want the following to happen:
User clicks on a link that redirects to the partner site
At the partner site, the request is intercepted and the system determines if the user is signed-in to the STS or anonymous
If the user has a valid session with the STS, then pull the claims for that user
The problem is, your RP cannot know that the user has a valid session without sending the user to the STS first (the RP's do not talk to each other or the STS. The user's brower is used as the means of communication between the RP's and the STS in the form of WS-Fed directives and SAML tokens passed in the url during redirects). If the user is sent to the STS, then they must authenticate, which could be a problem for anonymous users.
So, I do not think there is a "trick" that you can pull via configuration or interception of the request to determine if the user has a valid session with the STS. You might be able to pass a hint, however, from the referrer that is intercepted by the partner site. This hint could take the form of a parameter on the url that indicates to the partner site that the current user has a valid session and to go ahead and redirect to the STS (absence of this hint would indicate an anonymous user). You could also build a system to "hand-off" knowledge of the signed-in user using a resource that both sites have access to (i.e. database).
As you are sure to learn soon, more often than not, WIF offers pieces to the puzzle, but every situation is different and you have to supply the other pieces on your own.
Hope this helps!

How does AntiForgeryToken work

I'm in trying to protect from CSRF and have two scenarious:
Doing POST from within another site and it fails when I enable AntiForgeryToken
I have tried from my "malicious" Javascript (running on another site) to first do GET of the page, parse it and extract RequestVerificationToken and then do a POST. This also fails but it is unclear to me why?
Can anyone please explain why?
Here's a good tutorial on CSRF:
http://youtu.be/vrjgD0azkCw
Here is the general gist: You are logged in to your bank's website. Your bank puts a cookie on your machine so it can authenticate you. Every time you make a request to (ie. load a page from) yourbank.com, the browser sends the cookie to the web server and the code on the web server checks the cookie to make sure you're authenticated. Great.
However, while the cookie hasn't yet expired, you check your mail and open an email from a Nigerian Prince telling you to click on a link. You click on it (who can resist) and instead of taking you to the page the Prince has described, the link takes you to this URL:
http://yourbank.com/transfer.aspx?amt=1000000&from=myAccount&to=princeAccount
Because you're already authenticated at your bank (through the cookie), it thinks you're actually asking to transfer the money, so it does it.
This is obviously a bit of a contrived example, but it gets the point across. More realistically, the link might submit a request that changes your email address on a forum website that you belong to or something, so that they can get access to it.
So NOW, on to answering your specific question:
One way to combat this (used by Ruby and .NET and others) is to include an anti-forgery-token. Basically, when you request a page, the server includes a hidden field with an encrypted value. And when you submit the form, the website looks at the cookie to make sure you're authenticated, but it also looks at the encrypted value that the browser sends and make sure it's valid. The encrypted token would realistically be a session id that your account is tied to. So the server sees the cookie, identifies you as user 123, and then checks the encrypted form field token, decrypts the value and makes sure that unencrypted value matches your session or user id or something. If it does, it knows to proceed.
The Nigerian prince who sent you the link won't know what your session id is, and even if he did, he wouldn't be able to encrypt it with the same key and algorithm that the website is using.
And there you have it. Thwarting Nigerian princes one anti-forgery-token at a time.
(Nothing against Nigeria or Nigerians here. I'm sure they're lovely people. It's just their princes sometimes behave a bit poorly.) :)
For security reasons, you cannot retrieve content from another domain using AJAX.
Therefore, other sites cannot get your token.