As part of a thought experiment, I am attempting to ascertain whether there is any hope in a server providing a piece of data only for receipt and use by a browser environment, i.e. which could not be read by a bot crawling my site.
Clearly, if that information is sent in the source code, or indeed via any usual HTTP means, this can be picked up by a bot - so far, so simple.
But what about if the information was transmitted by the server instead as a websocket message: Wouldn't this be receivable only by some corresponding (and possibly authenticated) JavaScript in the browser environment, thus precluding its interception by a bot?
(This is based on my assumption that a bot has no client environment and is essentially a malicious server-side script calling a site over something like cURL, pretending to be a user).
Another way of phrasing this question might be: with the web implementation of websockets, is the receipt of messages always done by a client environment (i.e. JS)?
I can't answer about websockets, but a sufficiently motivated attacker will find a way to emulate whatever environment you require. By loading this content through ajax, you can eliminate the casual bots. You can eliminate well behaved bots with robots.txt.
Using WebSocket makes no difference. You cannot escape the following fact: you can always write a non-browser client that looks and behaves to the server exactly as any standard browser.
I can fake: any HTTP headers (like browser vendor etc) you might read. The origin header doesn't help either (I can fake it). Neither does cookies. I'll read them and give it back.
You might get away by protecting your site with strong captchas, and set cookies only after the captcha was solved. That depends on the captcha being unsolvable by bots ..
Related
First of all, all of this might be a newbie stupid question.
I am developing a web application with Laravel but ended up using tons and tons of Jquery/javascript. I tried to think of all the possible security risks as I was developing but the more I research this topic, the more I am concerned about usage of Jquery/javascript. It seems that dynamic content loading using Jquery/javascript is overall a very bad idea...But I don't want to rework everything since that would take weeks of extra developing of what is already developed. A quick example
Let's say I have a method attached to my div like so
<div class="img-container" id="{{$file->id}}" onmouseover="showImageButtons({{$file->id}})"></div>
And then a part of Javascript
function showImageButtons(id)
{
console.log(id);
}
When I open this in browser, I am able to alter the value of parameter sent to javascript through the chrome inspector.
from this
to this
And it actually gets executed, I can see "some malicious code" being printed to console.
What if I had an ajax call to server with that parameter? Would it pass?
Is there something I don't understand or is this seriously so easy to manipulate?
There are two basic aspects you need to consider regarding web security -
The connection between the browser and your server should be secure (i.e. https), that way, assuming you configured your server correctly, no one can intercept the client-server communication and you can share data through AJAX.
On the server side, you should treat information coming from the client as hostile and sanitize it; That is since anyone can send you anything through your webpage, even if you do input validation on the client side since the your javascript code is executed by the client and therefore in complete control of the attacker. While implanting "malicious code" in the webpage alone is not an actual attack, if an attacker gets you to store that malicious code in the server and send it to other clients she can run her javascript on your other clients browsers and that is bad (lookup "cross site scripting / XSS").
Given the simplicity of writing a server side proxy that fetches data across domains, I'm at a loss as to what the initial intention was in preventing client side AJAX from making calls across domains. I'm not asking for speculation, I'm looking for documentation from the language designers (or people close to them) for what they thought they were doing, other than simply creating a mild inconvenience for developers.
TIA
It's to prevent that a browser acts as a reverse proxy. Suppose you are browsing http://www.evil.com from a PC at your office, and suppose that in that office exists an intranet with sensitive information at http://intranet.company.com which is only accessible from the local network.
If the cross domain policy wouldn't exists, www.evil.com could made ajax requests to http://intranet.company.com, using your browser as a reverse proxy, and send that information to www.evil.com with another Ajax request.
This one of the reasons of the restriction I guess.
If you're the author for myblog.com and you make an XHR to facebook.com, should the request send your facebook cookie credentials? No, that would mean that you could request users' private facebook information from your blog.
If you create a proxy service to do it, your proxy can't access the facebook cookies.
You may also be questioning why JSONP is OK. The reason is that you're loading a script you didn't write, so unless facebook's script decides to send you the information from their JS code, you won't have access to it
The most important reason for this limit is a security concern: should JSON request make browser serve and accept cookies or security credentials with request to another domain? It is not a concern with server-side proxy, because it don't have direct access to client environment. There was a proposal for safe sanitized JSON-specific request methods, but it wasn't implemented anywhere yet.
The difference between direct access and a proxy are cookies and other security relevant identification/verification information which are absolutely restricted to one origin.
With those, your browser can access sensitive data. Your proxy won't, as it does not know the user's login data.
Therefore, the proxy is only applicable to public data; as is CORS.
I know you are asking for experts' answers, I'm just a neophyte, and this is my opinion to why the server side proxy is not a proper final solution:
Building a server side proxy is not as easy as not build it at all.
Not always is possible like in a Third Party JS widget. You are not gonna ask all your publisher to declare a DNS register for integrate your widget. And modify the document.domain of his pages with the colateral issues.
As I read in the book Third Party Javascript "it requires loading an intermediary tunnel file before it can make cross-domain requests". At least you put JSONP in the game with more tricky juggling.
Not supported by IE8, also from the above book: "IE8 has a rather odd bug that prevents a top-level domain from communicating with its subdomain even when they both opt into a common domain namespace".
There are several security matters as people have explained in other answers, even more than them, you can check the chapter 4.3.2 Message exchange using subdomain proxies of the above book.
And the most important for me:
It is a hack.. like the JSONP solution, it's time for an standard, reliable, secure, clean and confortable solution.
But, after re-read your question, I think I still didn't answer it, so Why this AJAX security?, again I think, the answer is:
Because you don't want any web page you visit to be able to make calls from your desktop to any computer or server into your office's intranet
We have a few staging environments for internal testing/dev that do not use "real" SSL certs. Honestly I'm a bit fuzzy on the details, but the bottom line is when accessing a subdomain on those environments, browser would prompt you to add a security exception along the lines of "You have asked Firefox to connect securely to example.com but we can't confirm that your connection is secure":
Could this be detected e.g. by making a request to the url in question and processing the error code/any other relevant information it may come back with? I could not find any specifications to indicate how this is being handled by the browser.
Edit:
I don't mind the error occurring on the landing page itself, it's pretty clear to the user. However some requests fail like this in the background (pulling css/js/other static content from different subdomains) but you don't know they do unless you go to net panel in firebug and open it in new tab and see the error...
The intention is not to circumvent this but rather to detect the issue and say something like "hey, these requests are failing, you can add security exceptions by going to these urls directly: [bunch of links]"
Checking the validity of the certificate is solely the responsibility of the client. Only it can know that it has to use HTTPS, and that it has to use it against a certificate that's valid for that host.
If the users don't make these checks and therefore put themselves in a position where a MITM attack could take place, you wouldn't necessarily be able to know about it. An active MITM attacker could answer perform the tasks you use to try to check the users are doing things correctly, but the legitimate users might not even get to know about it. This is quite similar to wanting to use redirections from http:// to https://: it works as long as there is no active MITM attack downgrading the connection.
(There is an exception to this, to make sure the client has seen the same handshake as you: when using client certificates. In this case, you would at least know that the client that ha authenticated with a cert would have seen your server cert and not a MITM cert, because of the signature at the end of the handshake. This is not really what you're looking for, though.)
JavaScript mechanisms generally won't let you check the certificate themselves. This being said, XHR requests to untrusted websites (with such warnings) will fail one way or another (generally via an exception): this could be a way to detect whether other pages than the landing page have are accessible by background requests (although you will certainly run into issues regarding Same Origin Policies).
Rather than using self-signed certificates for testing/development, you would be in a much better position if you deployed a test Certification Authority (CA). There are a number of tools to help you do this (which one to use would depend on the number of certificates you need). You would then have to import your own CA certificate into these browsers (or other clients), but the overall testing would be more realistic.
No.
That acceptance (or denial) only modifies a behavior in the client's browser (each browser, in a different way). It ACKs nothing to the server and the page is not yet loaded, therefore, there is no chance to catch that event.
Here's the idea:
If I can get something unique about a computer with JavaScript from an HTML page (probably the MAC address), then can I use this data as another security check?
Is that possible?
I am not going to check the computer at client side, i am going to send it to server to check. If nothing sent, user will be blocked. So it is not something that any developer+firebug combination can bypass. I just want to send one more string with username and password which is unique to computer and no one else knows if they don't entered to the system from that computer. Like a password hidden from user itself.
You can try using a tracking cookie; note however that such mechanisms are considered transient (e.g. cookies can be erased). In-browser JavaScript is sandboxed so that it does not have access to components outside the page. Note also that any feeling of security you'll gain with JavaScript is illusory - the script runs on the client side, where it can be modified (therefore there's no way to tell whether the "unique" piece of data is genuine or faked) or disabled altogether.
If you're trying to prevent random people from hacking at your app, you may want to ban them after a certain number of failed attempts. This will not get you any security, it's more of a flytrap - it limits the annoyances somewhat.
Finally, if you want actual security, go for HTTPS with real (NOT self-signed) server certificates and client-side certificates - see e.g. this for an implementation (that example, however, uses self-signed server certificates, which is not very secure). This is a mechanism that is well-implemented in the browser itself, and provides you with a somewhat secure system (complete with a secure keystore) of identifying your users (as opposed to a fundamentally flawed JS "security", or relying on user-readable files). Oh, and your data is encrypted while on the wire, that's a bonus.
SSL actually does what you're asking for: verifies that the client machine has a certificate issued to that user. This mechanism works inside the browser, not just inside the webpage; thus, it is much harder to subvert this than an in-page JavaScript. It stores a large unique identifier (clientside certificate) in a secure way, and it can prove to the server that it actually has that identifier - which is pretty much your initial requirement.
(Incidentally, using SSL, the data will be protected in transit, and the client can validate the server's identity; those weren't your requirements, but they're more or less necessary to assure that you're actually talking to the real client and real server)
JavaScript within a Web browser executes within a sandbox and has no access to the underlying hardware. Besides, MAC addresses aren't guaranteed to be unique.
No. And you shouldn't implement security with JavaScript only as any competent developer with Firebug will get around it in no time.
How can a user, using one of the major modern browsers, know for sure that he is running my unmodified javascript code even over an untrusted network?
Here is some more info about my situation:
I have a web application that deals with private information.
The login process is an implementation of a password-authenticated key agreement in JavaScript. Basically during login, a shared secret key is established between the client and the server. Once the user logs in all communication with the server is encrypted using the shared key. The system must be safe against ACTIVE man-in-the-middle attacks.
Assuming that my implementation is correct and the user is smart enough not to fall victim to a phishing attack there remains just one large hole in the system: an attacker can tamper with my application as it is being downloaded and inject code that steals the password. Basically the entire system relies on the fact that the user can trust the code running on his machine.
I want something similar to signed applets but I would prefer a pure javascript solution, if possible.
Maybe I am misunderstanding your problem, but my first thought is to use SSL. It is designed to ensure that you're talking to the server you think you are, and that no one has modified the content midstream. You do not even have to trust the network in this case, because of the nature of SSL.
The good thing about this approach is that you can fairly easily drop it into your existing web application. In most cases, you can basically configure your HTTP server to use SSL, and change your http:// requests to https://.
This is an old, open question but the answers seemed to not do this justice.
https:// provides integrity, not true identification nor non-repudiation.
I direct you to http://www.matasano.com/articles/javascript-cryptography/
Don't do crypto in JS, because a malicious injected script can easily grab passwords or alter the library. SJCL is neat, but it offer a blatantly false sense of security (their quote, and quoted by above)
Unfortunately, this is not as great as in desktop applications
because it is not feasible to completely protect against code
injection, malicious servers and side-channel attacks.
The long-term issue is that JavaScript lacks:
Uniformly working const
The ability to make objects deeply const and not reprototypable.
Code-signing
// codesign: cert:(hex fingerprint) signature:(hex MAC)
Certs would be managed similar to CA certs. MAC would be used with appropriate sign/verify constructions.
Crypto, clipboard stuff are reasons to have JavaScript native plugins (signed, of course)
Getting JavaScript engines to all implement a standard is another thing, but it's doable an it's absolutely necessary to end a large swath of malware.
You could have an external Javascript file which takes an MD5 hash of your login JS, and sends an Ajax request to the server to verify that it is correct and up-to-date. Use basic security or encryption practices here - public/private keys or some other method to be sure that the response came from your server.
You can then confidently display to the user that the client-side scripts are verified, and allow the login script to proceed.