Selectively displaying pages - security

I have a page that I am sending into an iframe. The iframe itself is being conditionally displayed based on logic in the back end. Is it possible for only the iframe to be able to display the page?
Basically I want to be able to call the page from within the iframe, but a person who accesses the URL directly will get redirected or blocked.

You can check the Referer header and serve the page only if it matches the URL of the document that contains the iframe. But this will foil only a user browsing casually to the direct URL. In general the answer is no, you have no control over how the user agent is going to display the content.
If you really need to do this, generate the parent document dynamically so that it contains a URL for the iframe with an embedded random one-time token. Have the iframe content be generated by a script that checks for the validity of the one-time token before delivering the page, and deletes the token from the database at the same time. You will have to make the iframe content uncacheable and you will likely encounter side effects related to caching that cause the page to break for legitimate users from time to time.

Lets assume the url for your iframe is http://example.com/myiframepage. The page that renders the iframe is http://example.com/parentpage
I am assuming your parent page already has code similar to :
//in parentpage :
if(can_show_iframe) {
}
You just need to go a step further and modify the code for myiframepage as follows -
//in myiframepage
if(can_show_iframe) {
//normal processing
}
else {
//return 403 error code which indicates access denied
}

Related

Chrome Extension - Scrape any url, ignoring sandboxing and Content Security Policy?

I'd like to build a chrome extension that can make requests against any web page that the user has access to, even pages that are protected by Content Security Policies, preferably in the background (without having to have the page open in the browser).
So for example, I'd like to be able to:
request info from a page the user may be logged into, like Gmail
request info from a RSS/other pages
request info from pages on Facebook
Is this possible? It seems like I could have the extension open a new window, and a tab for every page I want to pull info from. Is this the only way this can work? I'd prefer to have this happen behind the scenes, without having to open a window.
CSP is not a problem as long as your manifest.json adds the URLs you want to process in permissions e.g. "*://*/" or "<all_urls>" will allow access to any site.
The solution, however, depends on how that page is built. If the server response contains all the info you need then you can simply make a direct request via XMLHttpRequest or fetch (more info) in the background script, parse it with DOMParser and extract the data. Otherwise you can try to run it in an iframe (you'll have to strip X-Frame-Options) or in an inactive/pinned tab and use a content script to extract the data. To access JavaScript variables of the page you'll need to add a DOM script so its code will run in page context.

Chrome Extension: Sending a message to the page loaded in a specific iframe

I'm working on a Chrome extension to (among other things) support a page with multiple iframes, each of which loads a page from some other domain. I need to send a msg to the page loaded a specific one of those iframes. The top-level page and the pages in the iframe each have their own content scripts, so the full messaging API is available.
From the top page, when I do chrome.runtime.sendMessage(), all the iframes get it (as does the top window, but it's easy for its content script to know that that particular msg isn't intended for it). Is there any way to target a specific one of those iframes, or for the desired iframe page to know that the msg is for it?
Note that...
The top page can't access anything in iframe pages directly, because they're from other domains.
The top page knows the URL that was originally loaded in each frame, but the user may have navigated from there, so including the target URL as a msg parameter for the receiving script to check won't work.
Is there something obvious I'm missing here?
UPDATE: #wOxxOm's answer was very helpful, but I'm still stuck on how to get the frameIds I need.
More specifically, I need to do two things with those iframes, both of which need that frameId:
Inject a script into each iframe
Send msgs to a specific iframe in response to user actions on the top-level page
All of this is complicated by the fact that the iframes are created and removed dynamically as the user works.
One idea I had is to initially load each new iFrame with the URL "about:blank?id=nnn", where nnn is the DOM id of the corresponding iframe element. That way, when I call getAllFrames(), I can recognize the new iframes by that URL, and build a lookup of frameIds for each DOM id. Once that's done, I can load the real URL, inject the script once it's loaded.
That seems so roundabout, I'm hoping I've missed some supporting API or other straightforward approach.
I did find a solution, but it's pretty indirect. I hope this is clear; all these moving parts are the nature of the beast as I understand it.
Here's what I ended up doing:
Added a name attribute to each iframe, the same as its DOM id.
When the page in each iframe loads, a global content script calls chrome.runtime.sendMessage(), passing that name, which it can access as window.name.
The background script gets that msg, with the frameId of that iframe as sender.frameId, and calls chrome.tabs.sendMessage(), passing the frameId and window name.
The top-level page's content script builds a lookup object from those window-name (AKA iframe DOM id) / frameId pairs.
When the top-level page's content script wants to send a message to any of the iframe pages, it looks up the target's frameId in that lookup object, then calls chrome.runtime.sendMessage(), with a message type that indicates it's for a specific iframe, and including that frameId.
In response, the background script sends it on to the requested iframe's content script with chrome.tabs.sendMessage(), passing {frameId: request.frameId} as the 3rd parameter, as wOxxOm suggested.
This is working here, but by all means let me know if there's a simpler way to do this.

Link directly to document and have it work after login has completed

I have an page home.xsp that logs a user into my application. After the authentication is successful it goes to HomeAfterLogin.xsp which is the home/landing page of the application.
Yesterday I got to the point of creating emails that are triggered by status events in the app. In the emails I can include a direct link to the document in question. The direct link works if you are already authenticated, if not it takes you the login page (as it should). After you login, it takes you to the HomeAfterLogin instead of the document you linked to. When I built that part I did not anticipate that I would link directly to documents. My login process is largely based on a project from Ferry Kranenburg.
My question is where would I obtain the calling URL from the email or if a user happened to bookmark a document. I have tried context.getUrl() but it just returns the URL of the login page. I should be able to compute the property of where to redirect if I knew how to obtain the calling URL.
UPDATE: facesContext.getExternalContext().... also seems to just return the current URL, not the calling URL.
SECOND UPDATE: I know what the answer is. The URL is not accessible anymore because it has already been redirected. The XPage that is linked to directly contains code in the beforePageLoad event to redirect to the login page if the user is anonymous. At that point, I can get to the refering URL and store it in a sessionScope variable, and then redirect the page after login if the variable is present. I will answer my own question if this works.
The reason the URL is not accessible is that the page has already been redirected. The XPage that is linked to directly contains code in the beforePageLoad event to redirect to the login page if the user is anonymous.
if(session.getEffectiveUserName() == "Anonymous"){
//if the PO document was accessed directly like from a Email link or bookmark
//then the doc id is set to a sessionScope variable and after the login page
//the page is directed to the specific PO instead of the HomeAfterLogin page
sessionScope.URL_document = context.getUrlParameter("doc");
context.redirectToPage("Home.xsp")
}
I fixed this setting the docID from the URL to a sessionScope variable prior to redirecting to the login XPage in the same beforePageLoad event.
In the custom property that determines where to redirect after login, I added an if statement that will redirect to the specific document if the sessionScope variable is present. Otherwise go to the HomeAfterLogin as normal.
if(sessionScope.URL_document == ""){
facesContext.getExternalContext().getRequestContextPath() + "/HomeAfterLogin.xsp"
} else {
facesContext.getExternalContext().getRequestContextPath() + "/New_PO.xsp?doc=" + sessionScope.URL_document;
}
This has fixed the issue for me.

Sharepoint Online iframed system with login

What's the best way to do a unified login between a Sharepoint Online page and an iFramed in system that also needs it's own login. Is there any way for me to let the iframe know that the user is logged in and give the iframe the user email ?
Similar to what FB does with page tabs and apps.
Things to do:
First thing, do not give source to IFRAME element by default. Do it on main page's onload().
Add a custom JS in IFRAME page called IFRAME_READEMAIL() - will be called on IFRAME's page load. Add code where you read a HIDDEN VARIABLE - hfEmail
In your main page, using JQUERY, on load GET THE IFRAME object & set the hfEmail's value
The flow is like this:
The Main page gets loaded, then sets the IFRAME's SRC to required page, then sets the hidden field of IFRAME. The IFRAME picks up the HIDDEN variable & uses it.
Not sure what URL you get in IFRAME's location.href, but If you get the actual IFRAME's SRC as location.href, then you can set the SRC in main page like :
$('MYFAME').attr('src','http://mysite/mypage.aspx?email=' + YOURVARIABLE)

Understanding 3rd party iframes security?

Facebook and others offer little iframe snipplets that I can put in my site.
Example:
<iframe src="http://www.facebook.com/widgets/like.php?href=http://example.com"
scrolling="no" frameborder="0"
style="border:none; width:450px; height:80px"></iframe>
What I'd like to know is, if I put this code inside my side, could the code they load into my page access the DOM of my page? I see some security isssues if so.
Likewise facebook allows me to put an iframe into their site, this is how facebook applications work.
Could I then mine any data off any page that contains my iframe?
Note I used facebook as an example here, but many companies do the same thing so this quesiton is not specific to facebook in any way so I am not tagging it as such.
Also can the parent page access the DOM of the iframe?
Actually there are specific rules of inheritance for iframes. This is apart of the same-origin policy, and I highly recommend reading the entire Google Browser Sec Handbook.
I do know the parent page can access the DOM of the iframe. Recently we had a project at work where we had a site which needed to be 508 compliant. The iframe was not and although screen readers are handling iframes much better, the content within this iframe was not compliant. We loaded jquery library into our site, and then also loaded code into our site to manipulate the iframe (only after it loads) and at that point mashup the iframes content to be accessible.
To give you an idea of how we did it here is a sample of our jquery. (Used a lot of finds and replaces but you get the idea, you could do other things. )
$('iframe').load(function() {
var f = $(this).contents();
f.find('#sysverb_back').remove();
f.find('a.column_head').each(function(){
$(this).attr('title', $(this).text());
});
f.find('img[title]:not([alt])').each(function(){
$(this).attr('alt',$(this).attr('title'));
});
f.find('input').filter(function() {
return this.id.match(/sys_readonly\..+|ni\..+/);
}).each(function() {
$(this).before('<label for="'+this.id+'" style="display:none;">'+this.id+'</label>');
});
});
});
Although I do not know if you can from the iframe access the parent DOM.
I'm assuming cross-domain iFrame since presumably the risk would be lower if you controlled it yourself.
I've been trying to figure this out myself
Clickjacking/XSS is a problem if your site is included as an iframe
A compromised iFrame could display malicious content (imagine the iFrame displaying a login box instead of an ad)
An included iframe can make certain JS calls like alert and prompt which could annoy your user
An included iframe can redirect via location.href (yikes, imagine a 3p frame redirecting the customer from bankofamerica.com to bankofamerica.fake.com)
Malware inside the 3p frame (java/flash/activeX) could infect your user
Note that the html5 "sandbox" attribute can solve a lot of these problems if your browser supports it, and you can prevent your site from being included as an iFrame as well via X-FRAME-OPTIONS.

Resources