You combat that very easy: Mark every webpage as a webpage and do it in such a way, that the webpage itself cannot (under no circumstances) remove this mark
I’m surprised the browser vendors never came up with that concept.
E.g. draw a border around every webpage and offer no way for JS code to remove this border. Then you only need to educate the user If you see this border around something on the screen, it is a webpage, not an application, don’t fall for it claiming otherwise! And being a webpage, it has no access to your local system (files or hardware devices), no matter what it claims.
This way hackers could only fake it the other way round. They could intentionally draw a border around their app window looking alike - but why would they do so? What advantage do they have to pretend they are just a webpage if they are in fact a local app and already have full access to your system? In that case they better present no UI at all, so users never detect that this app is even there and running.
However, no attacking website can remove this border and thus they will always be clearly marked as web content. Or use a semi-transparent icon in the upper right corner. Maybe put a transparent watermark over the page - it’s always the same concept.
The real problem though is that all current operating systems are not secure enough. In a perfectly secure operating system, all code needs to be signed (as Apple started in Leopard). You can say that you trust a vendor and thus you trust their signature. If you trusted a signature, the app gets full access as every app gets right now. But if you never trusted a signature or the code is not even signed, the app shouldn’t be allowed to access anything. No network, no files, no hardware devices, nothing. Whenever the app tries to do anything, the user is prompted for permission by the system, even if it just wants to read its own config file, doesn’t matter. That way the app can’t do anything without the users permission and the user will get exactly informed about every action of this app (e.g. which file it tries to read, which Internet server it tries to contact).
In practice most users will download software from vendors they know and make their signature trust and never get bothered again. The OS itself is trusted by default and all default binaries of the OS are signed with a trusted signature. But as soon as you download any application from the Internet (possibly without even knowing that it got downloaded and executed), the app is like in a sandbox and only the user can remove it from there.
Then it’s only a question of educating users to not just allow apps they don’t know anything about to jump out of the sandbox and to educate them, that rejecting an app request usually has no negative consequences. Very often I see users clicking on Allow because they are afraid, if they don’t allow it, they break something and their system cease working. This is ridiculous. If a system stops working just because you once disallow a certain action, the system is a pile of crap and should be replaced by a decent system.
A good example of software that works according to a similar concept (but not for file or device access, only for network access) is LittleSnitch for Mac (one of the little utility apps I have actually bought as all freeware alternatives suck). Thanks to LS no app on my system (not even command line ping) can send any network traffic anywhere without LS popping up and asking me for permission. Then I can choose to allow this access once, till the app terminates or forever (because I trust it). Further if it says Firefox tries to access www.google.com on port 80, I can generalize the request. Instead of just allowing this, I can say Allow all ports on this server (so 443, HTTPS would now work with Google, too) or I can say Allow all servers on this port (so all port 80 requests will work, not just those to Google) or I can say Allow any request, any server, any port to completely remove the protection of the app (again, just for the session or forever). If I made a mistake and allowed an app more than I should have or if I blocked it permanently and now certain features won’t work, I can always modify the list of my permanent entries (and those for the current session as well) using a config tool. Further it detects if the hash of the binary changes, as someone could have replaced the app with another app to circumvent LS. Last but not least, LS works on kernel level using a kernel extension. A malicious tool could simply unload this kext (kexts can be unloaded at runtime in MacOS X), however, if it does so, network won’t work at all anymore (this is an intentional protection of LS; it modifies the network stack in such a way, that no packets can go anywhere anymore if it’s unloaded at runtime).